[翻译]
massivegas著A simple Multi-Threaded Server Client Instant Messenger Application
源代码下载地址:http://www.codeproject.com/KB/cs/Instant_Messenger.aspx
[简介]
本文实现一个简单的多线程客户/服务器即时通讯应用程序,它将使用TCP连接。允许客户之间及客户和服务器之间,个人消息与会议通信。最终目标是实现象雅虎/msn这样的即时通讯工具。
![即时通讯](http://www.msproject.cn/upload_image/3c88d3f4-9aeb-4c51-8f7b-13e7883c5889.jpg)
[库]
我创建一个ChatLibrary,它包含命令及可以着色的消息。
public
enum
Command
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
Login = 0,
PersonalMessage = 1,
ClientList = 2,
Conference = 3,
Logout = 4;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
public
class
Message
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
string strSender;
string strReceiver;
Command cmdMessageCommand;
string strMessageDetail;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public Message ()
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{}
public Message (byte [] rawMessage)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
string strRawStringMessage = System.Text.Encoding.ASCII.GetString (rawMessage);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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 ()
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
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());
}
...
}
服务器
我创建了一个SocketServer 类,它调用TCPListener.Start() 方法:
IPEndPoint endPoint
=
new
IPEndPoint (ipaAddress, iPort);
listener
=
new
TcpListener (endPoint);
listener.Start();
然后,给监听创建一个线程:
thrListenForClients
=
new
Thread(
new
ThreadStart(ListenForClients));
thrListenForClients.Start();
ListenForClients 方法会等待连接,并赋值给一个新的Client 实例:
Client acceptClient
=
new
Client();
acceptClient.Socket
=
listener.AcceptTcpClient();
listenForMessageDelegate
=
new
ListenForMessageDelegate (ListenForMessages);listenForMessageDelegate.BeginInvoke(acceptClient,
new
AsyncCallback(ListenForMessagesCallback),
"
Completed
"
);
Client是一个包含TCPClient的一个类,用于连接:
public
class
Client
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
string strName;
TcpClient tcpClient;
public Client()
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{}
public string Name
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
get...{return strName;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
set...{ this.strName = value;}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public TcpClient Socket
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
get...{return tcpClient;}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
set...{this.tcpClient = value;}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public void SendMessage (Message sendMessage)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
NetworkStream stream = tcpClient.GetStream();
stream.Write(sendMessage.GetRawMessage() , 0, sendMessage.GetRawMessage().Length);
}
}
接下来,再用NetworkStream 读消息:
一旦我们收到消息后,我们就可以做任何想做的了:
txtStatus.Text
+=
"
"
+
strDisplayMessageType
+
strWriteText.TrimStart(
new
char
[]
...
{' ',' '}
);
我的SocketServer 类使用一些事件,这样使得coding变得更容易:
public
event
ClientConnectedEventHandler ClientConnected;
public
event
ClientDisconnectingEventHandler ClientDisconnecting;
public
event
MessageReceivedEventHandler MessageReceived;
[客户端]
客户端基本上与上面一样,创建一个包含TCPListener 的ClientSocket ,然后调用其Connect() 方法:
IPEndPoint serverEndpoint
=
new
IPEndPoint (ipaAddress , iPort);tcpClient
=
new
TcpClient ();
tcpClient.Connect(serverEndpoint);
thrListenForMessages
=
new
Thread (
new
ThreadStart(ListenForMessages));
thrListenForMessages.Start();
ListenForMessages 会循环NetworkStream.Read()
然后,我们做一些处理,把得来的数据发送一个Message:
另外,我的目标是创建一个象YM/MSN 一样的即时通讯软件,所以,我做了两个UI form:MessengerForm 和ClientWindow。MessengerForm 包含ClientSocket ,并接收消息。根据接收到的消息,调用MessengerWindow 显示文字。
提示:文章中通过Invoke调用界面:
this.Invoke(createNewClientDelegate, new object []{receivedMessage});