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(); } } }