此即时交流系统分为服务器端和客户端,服务器端仅为新上线的用户提供在线用户列表,客户端与客户端之间完成其余的所有功能,真正实现了点对点的通讯。
一,架构说明
![](https://www.cnblogs.com/images/cnblogs_com/nethawker/22.JPG)
二,类库说明:
1, 枚举类(Command):Login:登录;PersonalMessage:私聊;ClientList:在线用户列表;
Logout:下线
2, 发送的消息类(Message):
(1),属性:Sender:发送者;Receiver:接受者;MessageCommand:命令;MessageDetail:消息的详细内容。
(2),方法:GetRawMessage:把消息的详细信息序列化
3,描述客户端类(EndPoint):
(1),属性:Name:姓名;Ksname:科室名称;Zyname:专业名称;IPAddress:IP地址;Port:监听的端口
(2),方法:SendMessage:发送消息。
4,客户端集合(EndPointCollection)
5,客户端处理受到消息类(ServerSocket):详见代码。
三,主要代码:
1,Command类和Message类
public enum Command
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
Login = 0,
PersonalMessage = 1,
ClientList = 2,
Conference = 3,
Logout = 4
}
public class Common
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public const string ServerName = "Server";
public const string All = "All";
}
public class Message
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
string strSender;
string strReceiver;
Command cmdMessageCommand;
string strMessageDetail;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Message ()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Message (byte [] rawMessage)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string strRawStringMessage
= System.Text.Encoding.Default.GetString(rawMessage);
string [] strRawStringMessageArray
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
= strRawStringMessage.Split(new char []
{'|'});
this.strSender = strRawStringMessageArray[1];
this.strReceiver = strRawStringMessageArray[2];
this.cmdMessageCommand = (Command) Convert.ToInt32(strRawStringMessageArray[3]);
this.MessageDetail = strRawStringMessageArray[4];
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Sender
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return strSender;}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ strSender = value;}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Receiver
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return strReceiver;}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ strReceiver = value;}
}
public Command MessageCommand
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return cmdMessageCommand ;}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ cmdMessageCommand = value;}
}
public string MessageDetail
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return strMessageDetail ;}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ strMessageDetail = value;}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public byte [] GetRawMessage ()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
System.Text.StringBuilder sbMessage
= new System.Text.StringBuilder ("nmds");
sbMessage.Append("|");
sbMessage.Append(strSender);
sbMessage.Append("|");
sbMessage.Append(strReceiver);
sbMessage.Append("|");
sbMessage.Append((int)cmdMessageCommand);
sbMessage.Append("|");
sbMessage.Append(strMessageDetail);
sbMessage.Append("|");
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return System.Text.Encoding.Default.GetBytes(sbMessage.ToString());
}
2,EndPoint类和EndPointCollection类
public class EndPoint
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
string strName;
private string ks;
private string zy;
private string ipaddress;
private int port;
TcpClient tcpClient;//和本机连接的socket
public EndPoint()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.tcpClient=null;
}
public string Name
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return strName;}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ this.strName = value;}
}
public string Ksname
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
get
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.ks;
}
set
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.ks=value;
}
}
public string Zyname
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
get
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.zy;
}
set
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.zy=value;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string IPAddress
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
get
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.ipaddress;
}
set
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.ipaddress=value;
}
}
public int Port
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
get
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.port;
}
set
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.port=value;
}
}
public TcpClient Socket
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return tcpClient;}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ this.tcpClient = value;}
}
private void Connect()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.tcpClient=new TcpClient();
IPEndPoint iep=new IPEndPoint(System.Net.IPAddress.Parse(this.ipaddress),this.port);
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.tcpClient.Connect(iep);
}
catch
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
throw new Exception("连接失败");
}
}
public void SendMessage (Message sendMessage,ref int errcode)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
errcode=0;
if(this.tcpClient==null)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//this.tcpClient.Close();
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.Connect();
}
catch
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
errcode=1;
return;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
NetworkStream stream = tcpClient.GetStream();
stream.Write(sendMessage.GetRawMessage() , 0, sendMessage.GetRawMessage().Length);
}
catch
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
errcode=2;
}
}
}
public class EndPointCollection: System.Collections.CollectionBase
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
public EndPointCollection()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
}
public EndPoint this[int index]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return (EndPoint) List[index];}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ List[index] = (EndPoint)value; }
}
public void Add (EndPoint client)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
List.Add(client);
}
public void Remove (string clientName)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
for (int i=0;i<List.Count;i++)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (((EndPoint) List[i]).Name.Equals(clientName))
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
List.Remove(List[i]);
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
public bool Contains (string name)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
for (int i=0;i<List.Count;i++)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (((EndPoint) List[i]).Name.Equals(name))
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return true;
}
}
return false;
}
}
3,ServerSocket类:
public class SocketServer
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
private TcpListener listener;//本机的侦听器
private IPAddress ipaAddress;//本级的ip地址
private int iPort;//本机的侦听端口
private string name;
public delegate void ListenForMessageDelegate(EndPoint client) ;
public delegate void ClientConnectedEventHandler (object sender, EndPoint client);
public delegate void ClientDisconnectingEventHandler (object sender, string clientName);
public delegate void MessageReceivedEventHandler (object sender, Message clientMessage);
public delegate void CommandReceivedEventHandler (object sender, ChatMessage commandMessage);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event ClientConnectedEventHandler ClientConnected;//和对方机器连接发生的事件
public event ClientDisconnectingEventHandler ClientDisconnecting;//和对方机器断开发生的事件
public event MessageReceivedEventHandler MessageReceived;//收到消息的事件
public event CommandReceivedEventHandler CommandReceived;//client列表
Thread thrListenForClients;
ListenForMessageDelegate listenForMessageDelegate ;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
bool bListenForClients;
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
SocketServer的构造函数#region SocketServer的构造函数
public SocketServer(string ipAddress, string port,string strname)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ipaAddress = IPAddress.Parse(ipAddress);
iPort = int.Parse(port);
this.name=strname;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
IPEndPoint endPoint
= new IPEndPoint (ipaAddress, iPort);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
listener = new TcpListener (endPoint);
listener.Start();
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
得到姓名#region 得到姓名
public string Name
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
get
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.name;
}
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
得到本机的IP地址#region 得到本机的IP地址
public IPAddress SocketIPAddress
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return ipaAddress;}
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
得到本机的侦端口#region 得到本机的侦端口
public int Port
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return iPort;}
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
启动侦听器#region 启动侦听器
public void Listen ()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
thrListenForClients = new Thread (new ThreadStart(ListenForClients));
thrListenForClients.Start();
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
停止侦听#region 停止侦听
public void Stop ()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
listener.Stop();
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
侦听来自客户端的消息#region 侦听来自客户端的消息
private void ListenForClients ()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
bListenForClients = true;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
while (bListenForClients)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
EndPoint acceptClient = new EndPoint ();
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
acceptClient.Socket = listener.AcceptTcpClient();
//this.ListenForMessages(acceptClient);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
listenForMessageDelegate
= new ListenForMessageDelegate (ListenForMessages);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
listenForMessageDelegate.BeginInvoke
(acceptClient, new AsyncCallback(ListenForMessagesCallback), "Completed");
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
catch (Exception ee)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
// Ang daya!
//
bListenForClients = false;
}
}
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
处理来自客户端的消息#region 处理来自客户端的消息
private void ListenForMessages (EndPoint client)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
while (true)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
NetworkStream stream = client.Socket.GetStream();
byte [] bytAcceptMessage = new byte [1024];
stream.Read(bytAcceptMessage, 0, bytAcceptMessage.Length);
if(bytAcceptMessage.Length>0)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//stream.Flush();
//stream.Close();
Message message = new ChatLib.Message(bytAcceptMessage);
if (message.MessageCommand.Equals(Command.Login))
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (ClientConnected != null)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
client.Name=message.Sender.Split(new char[]
{'@'})[0];
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
client.IPAddress=message.Sender.Split(new char[]
{'@'})[1];
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
client.Port=int.Parse(message.Sender.Split(new char[]
{'@'})[2]);
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
client.Zyname=message.Sender.Split(new char[]
{'@'})[3];
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
client.Ksname=message.Sender.Split(new char[]
{'@'})[4];
// client.Socket.Close();
// client.Socket=null;
//
//client.Name = message.Sender;
ClientConnected(this, client);
}
}
if (message.MessageCommand.Equals(Command.PersonalMessage)||
message.MessageCommand.Equals(Command.Conference)
)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (MessageReceived != null)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
MessageReceived(this, message);
}
}
if (message.MessageCommand.Equals(Command.Logout))
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (ClientDisconnecting != null)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
string sender=message.Sender;
ClientDisconnecting(this, sender);
}
}
if (message.MessageCommand.Equals(Command.ClientList))
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// client.Socket.Close();
// client.Socket=null;
CommandReceived(this, message );
//return;
}
}
}
}
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
连接客户端#region 连接客户端
#endregion
private void ListenForMessagesCallback (IAsyncResult ar)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
listenForMessageDelegate.EndInvoke(ar);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
客户上线#region 客户上线
public void Login(TcpClient tcpClient)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ChatMessage loginMessage = new ChatLib.Message ();
loginMessage.Receiver = ChatLib.Common.ServerName;;
loginMessage.Sender = this.name+"@"+this.ipaAddress+"@"+this.iPort.ToString();
loginMessage.MessageCommand = ChatLib.Command.Login;
NetworkStream stream = tcpClient.GetStream();
byte [] bytRawMessage = loginMessage.GetRawMessage();
stream.Write(bytRawMessage, 0, bytRawMessage.Length);
// for(int i=0;i<epc.Count;i++)
// {
// loginMessage.Receiver = epc[i].Name;
// loginMessage.Sender = this.name+"@"+this.ipaAddress+"@"+this.iPort.ToString();
// loginMessage.MessageCommand = ChatLib.Command.Login;
// NetworkStream stream = tcpClient.GetStream();
// byte [] bytRawMessage = loginMessage.GetRawMessage();
// stream.Write(bytRawMessage, 0, bytRawMessage.Length);
// epc[i].SendMessage(loginMessage);
// }
//
}
#endregion
}
详细代码:/Files/nethawker/Instance.rar