65.9K
CodeProject 正在变化。 阅读更多。
Home

一个简单的多线程服务器客户端即时通讯应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.32/5 (25投票s)

2006年6月5日

CPOL

2分钟阅读

viewsIcon

161163

downloadIcon

4647

一个使用TCP监听器和TCP客户端的简单多线程服务器客户端即时通讯应用程序。允许客户端之间以及与服务器进行个人消息和会议通讯。

Sample Image - maximum width is 600 pixels

库项目

我创建了一个ChatLibrary,它将包含有效的命令,以及一个Message,它将包含解析功能。

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());
}
...

服务器项目

我创建了一个SocketServer,它调用TCPListener.Start()方法

IPEndPoint endPoint = new IPEndPoint (ipaAddress, iPort);
listener = new TcpListener (endPoint);
listener.Start();

调用Listen后,将创建一个新线程来监听传入的客户端

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 {
   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);            
   }
}

我们的服务器现在已准备好监听传入的消息。为此,我们将接收到的客户端套接字传递过去,然后创建一个循环。我们使用NetworkStream来读取消息

NetworkStream stream = client.Socket.GetStream();
byte [] bytAcceptMessage = new byte [1024];
stream.Read(bytAcceptMessage, 0, bytAcceptMessage.Length);
Message message = new ChatLibrary.Message(bytAcceptMessage);

收到消息后,我们可以做任何想做的事情

txtStatus.Text += "\r\n" + strDisplayMessageType + 
    strWriteText.TrimStart(new char[]{'\r','\n'});

我的SocketServer利用了一些使编码更容易的事件

public event ClientConnectedEventHandler ClientConnected;
public event ClientDisconnectingEventHandler ClientDisconnecting;
public event MessageReceivedEventHandler MessageReceived;

在我的ServerForm代码中,我所做的是保留一个连接的Client的副本在ClientCollection 中,该集合继承自System.Collections.CollectionBase。这样,我可以遍历Clients。

客户端项目

Client 基本上做同样的事情。我创建了一个ClientSocket,它将创建一个TCPListener并调用Connect()

IPEndPoint serverEndpoint = new IPEndPoint (ipaAddress , iPort);
tcpClient = new TcpClient ();
tcpClient.Connect(serverEndpoint);
thrListenForMessages = new Thread (new ThreadStart(ListenForMessages));
thrListenForMessages.Start();

ListenForMessages 将要做的是使用NetworkStream.Read()循环

stream = tcpClient.GetStream();
byte [] bytRawMessage = new byte [1024];
stream.Read(bytRawMessage, 0, bytRawMessage.Length);
ChatMessage receivedMessage = new ChatLibrary.Message (bytRawMessage);

然后我们执行相同的过程,使用接收到的字节创建一个Message

再次说明,我的目标是创建一个类似YM/MSN的即时通讯工具,所以我创建了两个UI表单。MessengerFormClientWindowMessengerForm是实例化ClientSocket 并接收消息的类。收到消息后,它调用MessengerWindow,该窗口应显示文本。

请注意,我没有进行常规实例化。我调用了Invoke 以便能够使我的控件线程安全

this.Invoke(createNewClientDelegate, new object []{receivedMessage});

历史

  • 2006年6月4日:初始版本
© . All rights reserved.