using System; using System.Net; /// <summary> /// 客户端通过TCP/IP连接服务端的方法,包含连接,发送数据,接收数据功能 /// </summary> using System.Net.Sockets; using System.Text; using System.Threading; public class LYL_TCP_Client { // 定义一个空的Socket对象 Socket socket = null; // 当一个异步操作完成时, 用于通知的事件对象 //创建一个手动线程通知事件,false表示默认是线程阻塞,true表示线程继续,只有线程继续WaitOne()才有意义 static ManualResetEvent clientDone = new ManualResetEvent(false); // 异步操作超过时间定义. 如果在此时间内未接收到回应, 则放弃此操作. const int TIMEOUT_MILLISECONDS = 5000; // 用于接收数据的缓存数组大小 const int MAX_BUFFER_SIZE = 1024; /// <summary> /// 通过给定的地址和端口尝试TCP连接 /// </summary> /// <param name="hostName">主机地址</param> /// <param name="portNumber">通讯端口</param> /// <returns>返回一个以字符串形式表示的连接结果</returns> public string Connect(string hostName, int portNumber) { //连接结果,预定义为空 string result = string.Empty; //通过给定的地址和端口创建一个网络终结点 DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber); // 给预定义的空的Socket对象赋值 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建一个SocketAsyncEventArgs 异步操作对象用于连接请求 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs(); //设置异步操作的DNS终结点 socketEventArg.RemoteEndPoint = hostEntry; // Inline event handler for the Completed event. // Note: This event handler was implemented inline in order to make this method self-contained. socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e) { // 获取连接结果 result = e.SocketError.ToString(); //标识请求已经完成, 不阻塞 UI 线程 clientDone.Set(); }); // 重置clientDone,导致线程阻塞 clientDone.Reset(); // socket异步连接请求 socket.ConnectAsync(socketEventArg); //阻塞UI线程,等待下一个线程,如超过指定时间则认为已经超时并开启UI线程 clientDone.WaitOne(TIMEOUT_MILLISECONDS); //返回连接结果 return result; } /// <summary> /// 发送指令数据至服务器 /// </summary> /// <param name="data">要发送的指令</param> /// <returns>发送结果,即成功或失败</returns> public string Send(string data) { string response = "Operation Timeout"; // 使用在连接操作初始化的socket对象进行数据发送 if (socket != null) { // 创建 SocketAsyncEventArgs 对象、并设置对象属性 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs(); socketEventArg.RemoteEndPoint = socket.RemoteEndPoint; socketEventArg.UserToken = null; // 事件完成监听器 socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e) { response = e.SocketError.ToString(); //不阻塞UI线程 clientDone.Set(); }); // 将需要发送的数据指令送入发送缓冲区 byte[] payload = Encoding.Unicode.GetBytes(data); socketEventArg.SetBuffer(payload, 0, payload.Length); // 表示事件未完成,导致线程阻塞 clientDone.Reset(); // socket异步连接请求 socket.SendAsync(socketEventArg); // 阻塞UI线程,等待下一个线程,如超过指定时间则认为已经超时并开启UI线程 clientDone.WaitOne(TIMEOUT_MILLISECONDS); } else { response = "Socket is not initialized"; } return response; } public string Receive() { string reciveString = "";//服务端返回的整一串字符串,有可能包含有多个包 string oneTimeReciveString = "";//一次接收到的字符串,当有多个数据包的时候,每次只接收一个包 while (true) { oneTimeReciveString = OneTimeReceive(); Thread.Sleep(50);//线程等待,避免网络状况不好导致接收不完全 if (oneTimeReciveString.Length > 0) { reciveString = reciveString + oneTimeReciveString; } else break; } return reciveString; } /// <summary> /// 从服务端接收数据,此方法每次只接收一个数据包 /// </summary> /// <returns>一个数据包</returns> public string OneTimeReceive() { string response = "Operation Timeout"; if (socket != null) { // 创建 SocketAsyncEventArgs 对象、并设置对象属性 SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs(); socketEventArg.RemoteEndPoint = socket.RemoteEndPoint; // 设置接收数据缓冲区 socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE); // Inline event handler for the Completed event. // Note: This even handler was implemented inline in order to make // this method self-contained. socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { // 从接收缓冲区得到数据 response = Encoding.Unicode.GetString(e.Buffer, e.Offset, e.BytesTransferred); //去除缓冲区多余的字节,即当返回数据的长度比缓冲字节数组小的时候,去除掉缓冲自己数组中有用数据外的字符 //数组中默认的字符为' ' response = response.Trim(' '); } else { response = e.SocketError.ToString(); } clientDone.Set(); }); //表示事件未完成,导致线程阻塞 clientDone.Reset(); //socket异步连接请求 socket.ReceiveAsync(socketEventArg); //阻塞UI线程,等待下一个线程,如超过指定时间则认为已经超时并开启UI线程 clientDone.WaitOne(TIMEOUT_MILLISECONDS); } else { response = "Socket is not initialized"; } return response; } /// <summary> /// 关闭socket并释放资源 /// </summary> public void Close() { if (socket != null) { socket.Close(); } } }