using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Net; namespace SimpleServer { public class Client : IDisposable { #region DataMember & Ctor private TcpClient tcpclient; private NetworkStream netstream; public string IP; public string Port; private byte[] readBytes; private object tcpClientLock = new object();//锁TcpClient;Dispose之后就不允许EndRead,远程连接断开以后,就不允许再调用Dispose private bool closed = false;//包括本地主动断开和远程断开 //在事务处理结束后才触发下列事件 public event DlgNoParam ConnectFailEvent; public event DlgOneParam NewClientEvent; public event DlgOneParam RecvMsgEvent; public event DlgOneParam RemoteDisconnectEvent; public event DlgNoParam LocalDisconnectEvent; /// /// 服务的client的构造函数 /// /// public Client(TcpClient tcpclient) { this.tcpclient = tcpclient; readBytes = new byte[tcpclient.ReceiveBufferSize];//接收数据的缓冲区大小,如果太小一段数据会多次接收完成 netstream = tcpclient.GetStream();//如果远程客户端断开一样可以获得netstream } /// /// 客户端client的构造函数 /// public Client() { } #endregion #region 数据收发 /// /// 在建立连接的情况下发送消息 /// /// /// public bool SendMsg(byte[] msg) { bool result = false; try { netstream.Write(msg, 0, msg.Length); result = true; } catch { throw; } return result; } /// /// 服务的接收到客户端连接后最先做的操作之一,客户端接收数据线程起始 /// /// public bool BeginRead() { bool result = false; try { IP = (tcpclient.Client.RemoteEndPoint as IPEndPoint).Address.ToString(); Port = (tcpclient.Client.RemoteEndPoint as IPEndPoint).Port.ToString(); if (NewClientEvent != null) { NewClientEvent(IP + " " + Port); } netstream.BeginRead(readBytes, 0, readBytes.Length, EndRead, null);//如果远程客户端断开这句话一样可以执行 result = true; } catch { throw; } return result; } /// /// 有互斥资源 /// 接收数据,远程连接断开,远程程序关闭,本地连接断开,都会按顺序调用进来;因为连接关闭后不再调用BeginRead /// 服务器listener.stop时不会进入这个函数,客户端照样通讯,服务端只是不能接收新连接而已 /// /// private void EndRead(IAsyncResult ar) { lock (tcpClientLock) { if (!closed)//如果本地主动断开就不会进入 { try { int count = netstream.EndRead(ar); if (count > 0) { string recvStr = Encoding.Default.GetString(readBytes, 0, count); recvStr = recvStr + "\r\n\r\n"; if (RecvMsgEvent != null) { RecvMsgEvent(readBytes); } readBytes = new byte[tcpclient.ReceiveBufferSize]; netstream.BeginRead(readBytes, 0, readBytes.Length, EndRead, null); } else//远程客户端主动断开 { LocalClientClose(); } } catch (Exception ex) { if (ex.Message.Contains("无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接")) { LocalClientClose(); } else { throw; } } } } } #endregion #region 客户端连接和关闭 /// /// 客户端的client连接服务器 /// /// /// /// public bool Connect(string ip, string port) { bool result = false; try { ip = ip.Trim(); port = port.Trim(); if (!string.IsNullOrEmpty(ip) && !string.IsNullOrEmpty(port)) { IPAddress ipAddress = IPAddress.Parse(ip); IPEndPoint point = new IPEndPoint(ipAddress, int.Parse(port)); tcpclient = new TcpClient(AddressFamily.InterNetwork); readBytes = new byte[tcpclient.ReceiveBufferSize]; tcpclient.Connect(point); netstream = tcpclient.GetStream(); closed = false; result = true; } } catch (Exception ex) { if (ex.Message.Contains("由于目标机器积极拒绝,无法连接")) { if (ConnectFailEvent != null) { ConnectFailEvent(); } } else { } } return result; } /// /// 远程连接断开后(点关闭断开,程序退出断开)本地连接处理 /// private void LocalClientClose() { closed = true; DisposeEx(); if (RemoteDisconnectEvent != null) { string param = IP + " " + Port; if (RemoteDisconnectEvent != null) { RemoteDisconnectEvent(param); } } } /// /// 有互斥资源 /// 在已连接条件下关闭本地连接和资源释放时调用 /// public void Dispose() { lock (tcpClientLock) { if (!closed) { closed = true; DisposeEx(); if (LocalDisconnectEvent != null) { LocalDisconnectEvent(); } } } } /// /// 由Dispose和LocalClientClose调用 /// private void DisposeEx() { if (netstream != null) { netstream.Dispose(); netstream = null; } if (tcpclient != null) { tcpclient.Close(); tcpclient = null; } } #endregion } }