[置顶] C#中Socket服务端代码分享
最近在對(duì)項(xiàng)目中Socket通訊中的服務(wù)端代碼進(jìn)行優(yōu)化,保證能接受盡可能多的客戶端的連接,并且不會(huì)丟掉連接,不會(huì)掉數(shù)據(jù)包。經(jīng)過(guò)一段時(shí)間的反復(fù)測(cè)試和修改,終于達(dá)到了這一要求。服務(wù)端代碼采用了異步通訊的方式,并使用ManualResetEvent來(lái)對(duì)線程進(jìn)行控制。在程序中,ManualResetEvent 的使用很關(guān)鍵。 ManualResetEvent 允許線程通過(guò)發(fā)信號(hào)互相通信。通常,此通信涉及一個(gè)線程在其他線程進(jìn)行之前必須完成的任務(wù)。當(dāng)一個(gè)線程開(kāi)始一個(gè)活動(dòng)(此活動(dòng)必須完成后,其他線程才能開(kāi)始)時(shí),它調(diào)用 Reset 以將 ManualResetEvent 置于非終止?fàn)顟B(tài),此線程可被視為控制 ManualResetEvent。調(diào)用 ManualResetEvent 上的 WaitOne 的線程將阻止,并等待信號(hào)。當(dāng)控制線程完成活動(dòng)時(shí),它調(diào)用 Set 以發(fā)出等待線程可以繼續(xù)進(jìn)行的信號(hào)。并釋放所有等待線程。一旦它被終止,ManualResetEvent 將保持終止?fàn)顟B(tài)(即對(duì) WaitOne 的調(diào)用的線程將立即返回,并不阻塞),直到它被手動(dòng)重置。可以通過(guò)將布爾值傳遞給構(gòu)造函數(shù)來(lái)控制 ManualResetEvent 的初始狀態(tài),如果初始狀態(tài)處于終止?fàn)顟B(tài),為 true;否則為 false。現(xiàn)在貼出主要的代碼,歡迎大家指正,代碼如下所示:
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.設(shè)置無(wú)信號(hào)狀態(tài)的事件
??????????????? 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.等待連接創(chuàng)建后繼續(xù)
??????????????? allDone.WaitOne();
?? ??? ??? ??? ?
?? ??? ??? ??? ?UpdateControls(true);
?? ??? ??? ??? ?
?? ??? ??? ?}
?? ??? ??? ?catch(SocketException se)
?? ??? ??? ?{
?? ??? ??? ??? ?MessageBox.Show ( se.Message );
?? ??? ??? ?}
?? ??? ?}
// This is the call back function, which will be invoked when a client is connected
?? ??? ?public void OnClientConnect(IAsyncResult asyn)
?? ??? ?{
?? ??? ??? ?try
?? ??? ??? ?{
??????????????? //讓它繼續(xù)處理并建立與客戶端的連接
??????????????? 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);
??????????????? if (m_clientCount == 1)
??????????????? {
??????????????????? lock (this)
??????????????????? {
??????????????????????? stopwatch.Start();
??????????????????????? dtStart = DateTime.Now;
??????????????????????? writeLog("Server Start Socket Connect Time"+dtStart.ToString("yyyy-MM-dd HH:mm:ss fff"));
??????????????????? }
??????????????? }
?? ??? ??? ??? ?
?? ??? ??? ??? ?// Add the workerSocket reference to our ArrayList
?? ??? ??? ??? ?m_workerSocketList.Add(workerSocket);
?? ??? ??? ??? ?// Send a welcome message to client
??????????????? string msg = "Welcome client " + m_clientCount + "\n";
??????????????? 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.等待連接創(chuàng)建后繼續(xù)
??????????????? allDone.WaitOne();
?? ??? ??? ?}
?? ??? ??? ?catch(ObjectDisposedException)
?? ??? ??? ?{
?? ??? ??? ??? ?System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket has been closed\n");
?? ??? ??? ?}
?? ??? ??? ?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);
?? ??? ??? ??? ?System.String szData = new System.String(chars);
?? ??? ??? ??? ?string msg = "" + socketData.m_clientNumber + ":";
??????????????? AppendToRichEditControl(msg + szData);
??????????????? //writeFromClientsMsgLog(msg + szData);
?? ??? ??? ??? ?// 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);
?? ??? ??? ??? ?Socket workerSocket = (Socket)socketData.m_currentSocket;
?? ??? ??? ??? ?workerSocket.Send(byData);
??????????????? if (m_clientCount == iConnectNum && Flage == 0)
??????????????? {
??????????????????? Interlocked.Increment(ref Flage);
??????????????????? string msgTime = "Server End Socket Action Time:";
??????????????????? lock(this)
??????????????????? {
??????????????????????? stopwatch.Stop();
??????????????????????? //lblTime.Text = stopwatch.Elapsed.Seconds.ToString();
??????????????????????? int itime = stopwatch.Elapsed.Milliseconds;
?????????????????????? ?
??????????????????????? //msgTime += stopwatch.Elapsed.Seconds.ToString()+"--"+itime.ToString();
??????????????????????? msgTime += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff");
??????????????????? }
??????????????????? writeLog(msgTime);
??????????????????? writeClientConnectionLog();
?????????????????? ?
??????????????????? //UpdateLabelTime(msgTime);
??????????????????? //byData = System.Text.Encoding.ASCII.GetBytes(msgTime);
??????????????????? //workerSocket.Send(byData);
??????????????? }
?? ?
?? ??? ??? ??? ?// Continue the waiting for data on the Socket
?? ??? ??? ??? ?WaitForData(socketData.m_currentSocket, socketData.m_clientNumber );
?? ??? ??? ?}
?? ??? ??? ?catch (ObjectDisposedException )
?? ??? ??? ?{
?? ??? ??? ??? ?System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket has been closed\n");
?? ??? ??? ?}
?? ??? ??? ?catch(SocketException se)
?? ??? ??? ?{
?? ??? ??? ??? ?if(se.ErrorCode == 10054) // Error code for Connection reset by peer
?? ??? ??? ??? ?{?? ?
?? ??? ??? ??? ??? ?string msg = "Client " + socketData.m_clientNumber + " Disconnected" + "\n";
??????????????????? AppendToRichEditControl(msg);
??????????????????? //writeFromClientsMsgLog(msg);
?? ??? ??? ??? ??? ?// Remove the reference to the worker socket of the closed client
?? ??? ??? ??? ??? ?// so that this object will get garbage collected
?? ??? ??? ??? ??? ?m_workerSocketList[socketData.m_clientNumber - 1] = null;
?? ??? ??? ??? ??? ?UpdateClientListControl();
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?MessageBox.Show (se.Message );
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
void CloseSockets()
?? ??? ?{
?? ??? ??? ?if(m_mainSocket != null)
?? ??? ??? ?{
?? ??? ??? ??? ?m_mainSocket.Close();
?? ??? ??? ?}
?? ??? ??? ?Socket workerSocket = null;
?? ??? ??? ?for(int i = 0; i < m_workerSocketList.Count; i++)
?? ??? ??? ?{
?? ??? ??? ??? ?workerSocket = (Socket)m_workerSocketList[i];
?? ??? ??? ??? ?if(workerSocket != null)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?workerSocket.Close();
?? ??? ??? ??? ??? ?workerSocket = null;
?? ??? ??? ??? ?}
?? ??? ??? ?}?? ?
?? ??? ?}
void SendMsgToClient(string msg, int clientNumber)
?? ??? ?{
?? ??? ??? ?// Convert the reply to byte array
?? ??? ??? ?byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);
?? ??? ??? ?Socket workerSocket = (Socket)m_workerSocketList[clientNumber - 1];
??????????? //workerSocket.Send(byData);
??????????? workerSocket.BeginSend(byData, 0, byData.Length, 0,
??????????????? new AsyncCallback(SendCallback), workerSocket);
?? ??? ?}
??????? private void SendCallback(IAsyncResult asyn)
??????? {
??????????? Socket client = (Socket)asyn.AsyncState;
??????????? // 完成數(shù)據(jù)發(fā)送. ?
??????????? int bytesSent = client.EndSend(asyn); ?
??????? }
完整的代碼可以在我的資源中下載到,資源的名稱為C#中Socket服務(wù)端通訊的代碼。
轉(zhuǎn)載于:https://www.cnblogs.com/kevinGao/archive/2011/12/14/2776054.html
總結(jié)
以上是生活随笔為你收集整理的[置顶] C#中Socket服务端代码分享的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 利用Windows API获得系统高级功
- 下一篇: 年底了冲刺中。。。