最近在对项目中Socket通讯中的服务端代码进行优化,保证能接受尽可能多的客户端的连接,并且不会丢掉连接,不会掉数据包。经过一段时间的反复测试和修改,终于达到了这一要求。服务端代码采用了异步通讯的方式,并使用ManualResetEvent来对线程进行控制。在程序中,ManualResetEvent 的使用很关键。 ManualResetEvent 允许线程通过发信号互相通信。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态,此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。一旦它被终止,ManualResetEvent 将保持终止状态(即对 WaitOne 的调用的线程将立即返回,并不阻塞),直到它被手动重置。可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。现在贴出主要的代码,欢迎大家指正,代码如下所示:void ButtonStartListenClick(object sender, System.EventArgs e) { try { // Check the port value if(textBoxPort.Text == "") { MessageBox.Show("Please enter a Port Number"); return; } if (txtConnectNum.Text.Trim() != "") { iConnectNum = int.Parse(txtConnectNum.Text.Trim()); Flage = 0; } else { MessageBox.Show("Please enter a Connect Number"); return; }
string portStr = textBoxPort.Text; int port = System.Convert.ToInt32(portStr); // Create the listening socket... m_mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ipLocal = new IPEndPoint (IPAddress.Any, port); // Bind to local IP Address... m_mainSocket.Bind( ipLocal ); // Start listening... m_mainSocket.Listen(10000); // Set the event to nonsignaled state.设置无信号状态的事件 allDone.Reset(); // Create the call back for any client connections... m_mainSocket.BeginAccept(new AsyncCallback (OnClientConnect), null); // Wait until a connection is made before continuing.等待连接创建后继续 allDone.WaitOne();
} // This is the call back function, which will be invoked when a client is connected public void OnClientConnect(IAsyncResult asyn) { try { //让它继续处理并建立与客户端的连接 allDone.Set();
// Here we complete/end the BeginAccept() asynchronous call // by calling EndAccept() - which returns the reference to // a new Socket object Socket workerSocket = m_mainSocket.EndAccept (asyn);
// Now increment the client count for this client // in a thread safe manner Interlocked.Increment(ref m_clientCount);
// Add the workerSocket reference to our ArrayList m_workerSocketList.Add(workerSocket);
// Send a welcome message to client string msg = "Welcome client " + m_clientCount + "
"; SendMsgToClient(msg, m_clientCount);
// Update the list box showing the list of clients (thread safe call) UpdateClientListControl();
// Let the worker Socket do the further processing for the // just connected client WaitForData(workerSocket, m_clientCount);
// Since the main Socket is now free, it can go back and wait for // other clients who are attempting to connect m_mainSocket.BeginAccept(new AsyncCallback ( OnClientConnect ),null); // Wait until a connection is made before continuing.等待连接创建后继续 allDone.WaitOne(); } catch(ObjectDisposedException) { System.Diagnostics.Debugger.Log(0,"1","
OnClientConnection: Socket has been closed
"); } catch(SocketException se) { MessageBox.Show ( se.Message ); }
} public class SocketPacket { // Constructor which takes a Socket and a client number public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber) { m_currentSocket = socket; m_clientNumber = clientNumber; } public System.Net.Sockets.Socket m_currentSocket; public int m_clientNumber; // Buffer to store the data sent by the client public byte[] dataBuffer = new byte[1024]; } // Start waiting for data from the client public void WaitForData(System.Net.Sockets.Socket soc, int clientNumber) { try { if ( pfnWorkerCallBack == null ) { // Specify the call back function which is to be // invoked when there is any write activity by the // connected client pfnWorkerCallBack = new AsyncCallback (OnDataReceived); } SocketPacket theSocPkt = new SocketPacket (soc, clientNumber); //receiveDone.Reset(); soc.BeginReceive (theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, theSocPkt); //receiveDone.WaitOne(); } catch(SocketException se) { MessageBox.Show (se.Message ); } } // This the call back function which will be invoked when the socket // detects any client writing of data on the stream public void OnDataReceived(IAsyncResult asyn) { SocketPacket socketData = (SocketPacket)asyn.AsyncState ; try { // Complete the BeginReceive() asynchronous call by EndReceive() method // which will return the number of characters written to the stream // by the client //receiveDone.Set(); int iRx = socketData.m_currentSocket.EndReceive (asyn); char[] chars = new char[iRx + 1]; // Extract the characters as a buffer System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
// Send back the reply to the client string replyMsg = "Server Reply:" + szData.ToUpper(); // Convert the reply to byte array byte[] byData = System.Text.Encoding.ASCII.GetBytes(replyMsg);