|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionI started writing this application to learn Socket programming, Threads, and UI controls in C#. But in the process, I learned more than that. We would go step by step and will try to cover all important aspects of this application. But before we begin, I'd like to set some expectations about the application. This application demonstrates how multiple clients can connect to a single server and communicate to the server. However, at this point, clients cannot communicate with each other. That would be the next step for this application. Using the codeWhat do you need to get started with a multithreaded chat application? Threads and Sockets. Following is how the application starts and how it works:
Now, let's look at what each thread, that corresponds to a client connect, does:
Huh! Looks pretty simple. Now, let's look at some concepts in C# that are required to understand the implementation. 1. How does asynchronous receive work?.NET framework's public IAsyncResult BeginReceive( byte[] buffer, int offset, int size,
SocketFlags socketFlags, AsyncCallback callback, object state );
The way the Now, where exactly will be the received data? It will be in the buffer that was passed in the The BeginReceive call is made:// Create the state object.
StateObject state = new StateObject();
state.workSocket = connectedClient.Client;
//Call Asynchronous Receive Function
connectedClient.Client.BeginReceive(state.buffer, 0,
StateObject.BufferSize, 0,new AsyncCallback(OnReceive), state);
Callback function when data is received on the Socket:public void OnReceive(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead;
if (handler.Connected)
{
// Read data from the client socket.
try
{
bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Remove(0, state.sb.Length);
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Display Text in Rich Text Box
content = state.sb.ToString();
SetText(content);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize,
0,new AsyncCallback(OnReceive), state);
}
}
catch (SocketException socketException)
{
//WSAECONNRESET, the other side closed impolitely
if (socketException.ErrorCode == 10054 ||
((socketException.ErrorCode != 10004) &&
(socketException.ErrorCode != 10053)))
{
// Complete the disconnect request.
String remoteIP =
((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
String remotePort =
((IPEndPoint)handler.RemoteEndPoint).Port.ToString();
this.owner.DisconnectClient(remoteIP, remotePort);
handler.Close();
handler = null;
}
}
// Eat up exception....Hmmmm I'm loving eat!!!
catch (Exception exception)
{
MessageBox.Show(exception.Message + "\n" + exception.StackTrace);
}
}
}
2. How can you access a User Interface control (e.g., RichText Box) from a thread which is not an owner of that UI control?Answer is, use Delegates. If you look at the application, The rich text box that displays the chat message is created by the thread that creates the chat dialog box. Now, the chat data in the rich text box is updated by a thread that calls the callback function, In order to access it, create a delegate as: public delegate void SetTextCallback(string s);
Now, create a function to update the rich text box as: private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.rtbChat.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.rtbChat.SelectionColor = Color.Blue;
this.rtbChat.SelectedText = "\nFriend: "+text;
}
}
History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||