The Library Project
I created a ChatLibrary
that will contain the valid commands and a Message
that will contain the parsing.
public enum Command
{
Login = 0,
PersonalMessage = 1,
ClientList = 2,
Conference = 3,
Logout = 4
};
public class Message
{
string strSender;
string strReceiver;
Command cmdMessageCommand;
string strMessageDetail;
public Message ()
{
}
public Message (byte [] rawMessage)
{
string strRawStringMessage = System.Text.Encoding.ASCII.GetString (rawMessage);
string [] strRawStringMessageArray = strRawStringMessage.Split(new char []{'|'});
this.strSender = strRawStringMessageArray[1];
this.strReceiver = strRawStringMessageArray[2];
this.cmdMessageCommand = (Command) Convert.ToInt32(strRawStringMessageArray[3]);
this.MessageDetail = strRawStringMessageArray[4];
}
...
public byte [] GetRawMessage ()
{
System.Text.StringBuilder sbMessage = new System.Text.StringBuilder ("John");
sbMessage.Append("|");
sbMessage.Append(strSender);
sbMessage.Append("|");
sbMessage.Append(strReceiver);
sbMessage.Append("|");
sbMessage.Append((int)cmdMessageCommand);
sbMessage.Append("|");
sbMessage.Append(strMessageDetail);
sbMessage.Append("|");
return System.Text.Encoding.ASCII.GetBytes(sbMessage.ToString());
}
...
The Server Project
I created a SocketServer
that calls the TCPListener.Start()
method:
IPEndPoint endPoint = new IPEndPoint (ipaAddress, iPort);
listener = new TcpListener (endPoint);
listener.Start();
Upon calling Listen
, a new thread will be created that will listen for incoming clients:
thrListenForClients = new Thread(new ThreadStart(ListenForClients));
thrListenForClients.Start();
The ListenForClients
method will wait for connections and will assign the incoming socket to a new Client
instance:
Client acceptClient = new Client();
acceptClient.Socket = listener.AcceptTcpClient();
listenForMessageDelegate = new ListenForMessageDelegate (ListenForMessages);
listenForMessageDelegate.BeginInvoke
(acceptClient, new AsyncCallback(ListenForMessagesCallback), "Completed");
The Client
, by the way is a class that contains a TCPClient
, so we can keep track of our connections:
public class Client {
string strName;
TcpClient tcpClient;
public Client()
{
}
public string Name
{
get{return strName;}
set{ this.strName = value;}
}
public TcpClient Socket
{
get{return tcpClient;}
set{ this.tcpClient = value;}
}
public void SendMessage (Message sendMessage)
{
NetworkStream stream = tcpClient.GetStream();
stream.Write(sendMessage.GetRawMessage() , 0, sendMessage.GetRawMessage().Length);
}
}
Our server is now ready to listen for incoming messages. To do this, we pass the client socket that we received, then make a loop. We use a NetworkStream
to read the message:
NetworkStream stream = client.Socket.GetStream();
byte [] bytAcceptMessage = new byte [1024];
stream.Read(bytAcceptMessage, 0, bytAcceptMessage.Length);
Message message = new ChatLibrary.Message(bytAcceptMessage);
Once we receive the message, we can do anything that we want:
txtStatus.Text += "\r\n" + strDisplayMessageType +
strWriteText.TrimStart(new char[]{'\r','\n'});
My SocketServer
makes use of a few events that make coding a little easier:
public event ClientConnectedEventHandler ClientConnected;
public event ClientDisconnectingEventHandler ClientDisconnecting;
public event MessageReceivedEventHandler MessageReceived;
In my ServerForm
code, what I did was I kept a copy of each connected Client
in a ClientCollection
that inherits from System.Collections.CollectionBase
. With this, I can iterate through the Client
s.
The Client Project
The Client
does basically the same thing. I created a ClientSocket
that will create a TCPListener
and call Connect()
:
IPEndPoint serverEndpoint = new IPEndPoint (ipaAddress , iPort);
tcpClient = new TcpClient ();
tcpClient.Connect(serverEndpoint);
thrListenForMessages = new Thread (new ThreadStart(ListenForMessages));
thrListenForMessages.Start();
What ListenForMessages
will do is loop with NetworkStream.Read()
:
stream = tcpClient.GetStream();
byte [] bytRawMessage = new byte [1024];
stream.Read(bytRawMessage, 0, bytRawMessage.Length);
ChatMessage receivedMessage = new ChatLibrary.Message (bytRawMessage);
Then we do the same process, create a Message
using the received bytes.
Again, my goal is to create a YM/MSN - looking Instant Messenger, so I made two UI forms. The MessengerForm
and the ClientWindow
. The MessengerForm
is the class that instantiates the ClientSocket
and receives the messages. Upon receiving a message, it calls the MessengerWindow
that should display the text.
Note that I didn't do a regular instantiation. I called Invoke
to be able to make my controls thread safe:
this.Invoke(createNewClientDelegate, new object []{receivedMessage});
History
- 4th June 2006: Initial version