// This method is invoked when an asynchronous send operation completes. // The method issues another receive on the socket to read any additional // data sent from the client // // <param name="e"></param> private void ProcessSend(SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { // done echoing data back to the client AsyncUserToken token = (AsyncUserToken)e.UserToken; // read the next block of data send from the client bool willRaiseEvent = token.Socket.ReceiveAsync(e); if (!willRaiseEvent) { ProcessReceive(e); } } else { CloseClientSocket(e); } }
private void ShowClient(int count, AsyncUserToken userToken) { if (count < 0) { Msg.BeginInvoke(DateTime.Now.ToString() + "\r\n" + userToken?.Remote + "客户端已登出!" + "\r\n", null, null); DeteList.BeginInvoke(userToken?.Remote.ToString(), null, null); } else { if (userToken != null) { if (m_clients.Find(c => c.Remote == userToken.Remote) == null) { m_clients.Add(userToken); } Msg.BeginInvoke(DateTime.Now.ToString() + "\r\n" + userToken?.Remote + "客户端已连接!" + "\r\n", null, null); MsgList.BeginInvoke(userToken?.Remote.ToString(), null, null); } } }
private void ProcessAccept(SocketAsyncEventArgs e) { try { Interlocked.Increment(ref m_clientCount); // Get the socket for the accepted client connection and put it into the //ReadEventArg object user token SocketAsyncEventArgs readEventArgs = m_pool.Pop(); AsyncUserToken userToken = (AsyncUserToken)readEventArgs.UserToken; userToken.Socket = e.AcceptSocket; userToken.ConnectTime = DateTime.Now; userToken.Remote = e.AcceptSocket.RemoteEndPoint; userToken.IPAddress = ((IPEndPoint)(e.AcceptSocket.RemoteEndPoint)).Address; lock (m_clients) { m_clients.Add(userToken); } if (ClientNumberChange != null) { ClientNumberChange(1, userToken); } if (!e.AcceptSocket.ReceiveAsync(readEventArgs)) { ProcessReceive(readEventArgs); } } catch (Exception me) { Msg.Invoke(me.Message + "\r\n" + me.StackTrace); } // Accept the next connection request if (e.SocketError == SocketError.OperationAborted) { return; } StartAccept(e); }
//关闭客户端 private void CloseClientSocket(SocketAsyncEventArgs e) { AsyncUserToken token = e.UserToken as AsyncUserToken; lock (m_clients) { m_clients.Remove(token); } //如果有事件,则调用事件,发送客户端数量变化通知 if (ClientNumberChange != null) { ClientNumberChange(-1, token); } // close the socket associated with the client try { token.Socket.Shutdown(SocketShutdown.Send); } catch (Exception) { } token.Socket.Close(); // decrement the counter keeping track of the total number of clients connected to the server Interlocked.Decrement(ref m_clientCount); m_maxNumberAcceptedClients.Release(); // Free the SocketAsyncEventArg so they can be reused by another client e.UserToken = new AsyncUserToken(); m_pool.Push(e); }
// This method is invoked when an asynchronous receive operation completes. // If the remote host closed the connection, then the socket is closed. // If data was received then the data is echoed back to the client. // private void ProcessReceive(SocketAsyncEventArgs e) { try { // check if the remote host closed the connection AsyncUserToken token = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { //读取数据 byte[] data = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred); lock (token.Buffer) { token.Buffer.AddRange(data); } //注意:你一定会问,这里为什么要用do-while循环? //如果当客户发送大数据流的时候,e.BytesTransferred的大小就会比客户端发送过来的要小, //需要分多次接收.所以收到包的时候,先判断包头的大小.够一个完整的包再处理. //如果客户短时间内发送多个小数据包时, 服务器可能会一次性把他们全收了. //这样如果没有一个循环来控制,那么只会处理第一个包, //剩下的包全部留在token.Buffer中了,只有等下一个数据包过来后,才会放出一个来. do { //判断包的长度 //byte[] lenBytes = token.Buffer.GetRange(0, 4).ToArray(); //int packageLen = BitConverter.ToInt32(lenBytes, 0); //if (packageLen > token.Buffer.Count - 4) //{ //长度不够时,退出循环,让程序继续接收 // break; //} //包够长时,则提取出来,交给后面的程序去处理 byte[] rev = token.Buffer.ToArray(); //从数据池中移除这组数据 lock (token.Buffer) { token.Buffer.RemoveRange(0, token.Buffer.Count); } //将数据包交给后台处理,这里你也可以新开个线程来处理.加快速度. if (ReceiveClientData != null) { ReceiveClientData(token, rev); } //这里API处理完后,并没有返回结果,当然结果是要返回的,却不是在这里, 这里的代码只管接收. //若要返回结果,可在API处理中调用此类对象的SendMessage方法,统一打包发送.不要被微软的示例给迷惑了. } while (token.Buffer.Count > 4); //继续接收. 为什么要这么写,请看Socket.ReceiveAsync方法的说明 if (!token.Socket.ReceiveAsync(e)) { this.ProcessReceive(e); } } else { CloseClientSocket(e); } } catch (Exception xe) { Msg.Invoke(xe.Message + "\r\n" + xe.StackTrace); } }