public partial class ServerApp : Form { public delegate void UpdateRichEditCallback(string text); public delegate void UpdateClientListCallback(); public AsyncCallback pfnWorkerCallBack ; private Socket m_mainSocket; // An ArrayList is used to keep track of worker sockets that are designed // to communicate with each connected client. Make it a synchronized ArrayList // For thread safety private System.Collections.ArrayList m_workerSocketList = ArrayList.Synchronized(new System.Collections.ArrayList()); // The following variable will keep track of the cumulative // total number of clients connected at any time. Since multiple threads // can access this variable, modifying this variable should be done // in a thread safe manner private int m_clientCount = 0; public ServerApp() { InitializeComponent(); // Display the local IP address on the GUI textBoxIP.Text = GetIP(); } void ButtonStartListenClick(object sender, System.EventArgs e) { try { // Check the port value if(textBoxPort.Text == "") { MessageBox.Show("Please enter a Port 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(4); // Create the call back for any client connections... m_mainSocket.BeginAccept(new AsyncCallback (OnClientConnect), null); UpdateControls(true); } catch(SocketException se) { MessageBox.Show ( se.Message ); } } private void UpdateControls( bool listening ) { buttonStartListen.Enabled = !listening; buttonStopListen.Enabled = listening; } // This is the call back function, which will be invoked when a client is connected public void OnClientConnect(IAsyncResult asyn) { try { // 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 +"\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); } 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); soc.BeginReceive (theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, theSocPkt); } 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 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); double num = 3000000; double sum = 0; for (int i = 0; i <= num; i++) { sum = sum + i; } // 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); // 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); // 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 ); } } } // This method could be called by either the main thread or any of the // worker threads private void AppendToRichEditControl(string msg) { // Check to see if this method is called from a thread // other than the one created the control if (InvokeRequired) { // We cannot update the GUI on this thread. // All GUI controls are to be updated by the main (GUI) thread. // Hence we will use the invoke method on the control which will // be called when the Main thread is free // Do UI update on UI thread object[] pList = {msg}; richTextBoxReceivedMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList); } else { // This is the main thread which created this control, hence update it // directly OnUpdateRichEdit(msg); } } // This UpdateRichEdit will be run back on the UI thread // (using System.EventHandler signature // so we don't need to define a new // delegate type here) private void OnUpdateRichEdit(string msg) { richTextBoxReceivedMsg.AppendText(msg); } private void UpdateClientListControl() { if (InvokeRequired) // Is this called from a thread other than the one created // the control { // We cannot update the GUI on this thread. // All GUI controls are to be updated by the main (GUI) thread. // Hence we will use the invoke method on the control which will // be called when the Main thread is free // Do UI update on UI thread listBoxClientList.BeginInvoke(new UpdateClientListCallback(UpdateClientList), null); } else { // This is the main thread which created this control, hence update it // directly UpdateClientList(); } } void ButtonSendMsgClick(object sender, System.EventArgs e) { try { string msg = richTextBoxSendMsg.Text; msg = "Server Msg: " + msg + "\n"; byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg); Socket workerSocket = null; for(int i = 0; i < m_workerSocketList.Count; i++) { workerSocket = (Socket)m_workerSocketList[i]; if(workerSocket!= null) { if(workerSocket.Connected) { workerSocket.Send (byData); } } } } catch(SocketException se) { MessageBox.Show (se.Message ); } } void ButtonStopListenClick(object sender, System.EventArgs e) { CloseSockets(); UpdateControls(false); } String GetIP() { String strHostName = Dns.GetHostName(); // Find host by name IPHostEntry iphostentry = Dns.GetHostByName(strHostName); // Grab the first IP addresses String IPStr = ""; foreach(IPAddress ipaddress in iphostentry.AddressList) { IPStr = ipaddress.ToString(); return IPStr; } return IPStr; } void ButtonCloseClick(object sender, System.EventArgs e) { CloseSockets(); Close(); } 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; } } } // Update the list of clients that is displayed void UpdateClientList() { listBoxClientList.Items.Clear(); for(int i = 0; i < m_workerSocketList.Count; i++) { string clientKey = Convert.ToString(i+1); Socket workerSocket = (Socket)m_workerSocketList[i]; if(workerSocket != null) { if(workerSocket.Connected) { listBoxClientList.Items.Add(clientKey); } } } } 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); } private void btnClear_Click(object sender, System.EventArgs e) { richTextBoxReceivedMsg.Clear(); } }
Attachment: MainCode.rar