第一部分:整个通信过程梳理;文末附全套代码;
本篇为第二部分:重要bug完善;
第三部分:消息类型编码:自定义通信协议。
第四部分:全套代码
在第一部分:整个通信过程梳理中:有一个重要bug:多个客户端与服务器通信,服务器发送的消息只能被最新接入的客户端收到,其他客户端无法收到。不能实现点对点,端到端的通信。
为此在服务端我们预留了一个下拉列表来选择通信目标端。
思路是:
看原来的代码:每当一个客户端接入之后,我们把都会创建一个新的socketSend来跟客户端进行通信socketSend = socketWatch.Accept();所以服务器每次只能给最新接入的客户端发送消息。之前接入的SocketSend被覆盖。
Socket socketSend;
void Listen(object o)
{
Socket socketWatch = o as Socket;
while (true)
{
try
{
// 等待客户端的连接,接受客户端的连接请求,并为新建连接创建一个负责通信的新的System.Net.Socket.Socket连接。
socketSend = socketWatch.Accept();
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功");
//开启一个新线程,不停的接受客户端发送过来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start(socketSend);
}
catch { }
}
}
解决方法:将客户端的IP和端口号保存到下拉列表中,那么每次给客户端发送消息时,由下拉列表中选定。
所以每当客户端接入之后,将客户端信息保存下来。并且将服务器中与客户端通信的socketSend信息也保存下来。保证每次指定SocketSend来实现点对点通信。
将ip地址和对应的socketSend保存下来,一一对应的数据结构就是键值对,字典。所以在外面新建一个Dictionary,供全局使用。
/// <summary>
/// 等待客户端的连接 并且创建与之通信用的Socket
/// </summary>
///
Socket socketSend;
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
void Listen(object o)
{
Socket socketWatch = o as Socket;
while (true)
{
try
{
// 等待客户端的连接,接受客户端的连接请求,并为新建连接创建一个负责通信的新的System.Net.Socket.Socket连接。
socketSend = socketWatch.Accept();
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功");
// 将接入的客户端的IP地址和端口号存入到下拉列表中;
// 当选中客户端之后,对应的socketSend也要相应的去工作。
// 将ip地址和对应的socketSend保存下来,一一对应的数据结构就是键值对,字典。所以在外面新建一个Dictionary,供全局使用。
dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
// 将远程连接的客户端的IP地址和端口号存入到下拉列表中。等待选择;
cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
//开启一个新线程,不停的接受客户端发送过来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start(socketSend);
}
catch { }
}
}
拿到对应关系之后,那么再给客户端发送消息时,首先需要拿到下拉框中选中的IP地址。原来的代码也需要修改。
/// <summary>
/// 服务器给客户端发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
string str = txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
//socketSend.Send(buffer);
// 获得用户在下拉框中选中的IP地址。
string ip = cboUsers.SelectedItem.ToString();
dicSocket[ip].Send(buffer);
}
如此实现了可以根据目标的地址,保留相应的socketSend来实现精准匹配通信。