using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace GeneralGommunication
{
public class GComm_TcpServer : IGeneralComm,IDisposable
{
///
/// IP 地址 and 端口号
///
public string Addr { get; set; }
IPEndPoint LocalEp => Misc.StringConverter.ToIPEndPoint(Addr);
///
/// 是否异常
///
public bool IsError => !string.IsNullOrEmpty(ErrMsg);
///
/// 异常信息
///
public string ErrMsg { get; private set; }
///
/// 运行中
///
public bool IsRunning { get; private set; }
///
/// 连接成功
///
public bool IsConnected { get; private set; }
///
/// 接收task调用
///
public event IGeneralCommDataReceivedHandler DataReceived;
public event PropertyChangedEventHandler PropertyChanged;
Socket sock;
CancellationTokenSource cts_readTask;
CancellationTokenSource cts_waitForSend;
CancellationTokenSource cts_sendTask;
public GComm_TcpServer(Socket sock)
{
this.sock = sock;
IsConnected = true;
}
///
/// 开始
///
public void Start()
{
if (IsRunning)
return;
IsRunning = true;
cts_readTask = new CancellationTokenSource();
Task.Factory.StartNew(OnTask, cts_readTask.Token);
}
///
/// 接收
///
public void Stop()
{
if (!IsRunning)
return;
IsRunning = false;
IsConnected = false;
cts_readTask.Cancel();
if (sock != null && sock.Connected)
{
sock.Close();
sock = null;
}
}
void OnTask()
{
sendBuf.Clear();
//启动发送task
cts_sendTask = new CancellationTokenSource();
var sendtask = Task.Factory.StartNew(SendTask, cts_sendTask.Token);
//进入接收task
ReceiveTask();
//退出了,肯定连接断开了
//需要等待 SendTask 也退出了
cts_sendTask.Cancel();
sendtask.Wait();
if (sock != null)
{
sock.Close();
sock = null;
}
IsConnected = false;
IsRunning = false;
}
///
/// 接收任务
///
void ReceiveTask()
{
byte[] buf = new byte[0x10000];
while (!cts_readTask.IsCancellationRequested)
{
int len;
try
{
len = sock.Receive(buf);
if (len == 0)
{
continue;//没收到数据,继续等
}
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.TimedOut)
continue;//超时而已
else if ((e.SocketErrorCode == SocketError.ConnectionAborted)
|| (e.SocketErrorCode == SocketError.ConnectionRefused)
|| (e.SocketErrorCode == SocketError.ConnectionReset))
{
IsConnected = false;
return;
}
//Console.WriteLine($"ReceiveTask() {e}");
//肯定断开连接了
IsConnected = false;
break;
}
DataReceived?.Invoke(this, buf.Take(len).ToArray());
}
IsConnected = false;
}
///
/// 发送任务
///
void SendTask()
{
while (!cts_sendTask.IsCancellationRequested)
{
CancellationTokenSource cts3;
while (true)
{
byte[] buffer;
lock (sendBuf)
{
if (sendBuf.Count <= 0)
break;
buffer = sendBuf.ToArray();
}
int slen;
try
{
slen = sock.Send(buffer);
}
catch (Exception e)
{
//连接断开了
IsConnected = false;
break;
}
if (slen <= 0)
{
//连接断开了
IsConnected = false;
break;
}
else
{
lock (sendBuf)
{
sendBuf.RemoveRange(0, slen);
}
}
}
//重新等 下次被呼醒
lock (sendBuf)
{
// 呼醒 发送task
if (cts_waitForSend == null)
{
cts_waitForSend = new CancellationTokenSource();
}
//cts_waitForSend 与 cts_sendTask 合体, 任意一个都会呼醒 delay
cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts_waitForSend.Token, cts_sendTask.Token);
}
try
{
Task.Delay(-1, cts3.Token).Wait();
}
catch (Exception e)
{
//被打断, 有数据需要发送
}
lock (sendBuf)
{
cts_waitForSend = null;
}
}
}
///
/// 无限大,发送缓存
///
List sendBuf = new List();
///
/// 发送数据
///
///
public void Write(IEnumerable buf)
{
if (!IsConnected)
return;
lock (sendBuf)
{
//放入,发送缓存区
sendBuf.AddRange(buf);
//呼醒 发送task
if (cts_waitForSend == null)
{
cts_waitForSend = new CancellationTokenSource();
}
cts_waitForSend.Cancel();
}
}
///
/// 清空输入缓存
///
public void DiscardInBuffer()
{
//TODO
}
public void Dispose()
{
Stop();
}
}
}