0%

基于C# Winform的简易聊天程序[第三篇-信息群发]

程序简介

好久没写博客了,最近时间比较充足.于是便打算把之前的聊天程序功能改进下,增加了一个服务端给客户端群发信息的功能.

原理

首先我们需要获取连接客户端的IP和Port,并添加到客户端列表里作为每个客户端的唯一标识.然后通过相应客户端的Socket.Send()方法将信息发送出去.

服务端给客户端的信息群发与服务端给单个客户端的信息发送原理是一样的,通过遍历客户端列表里的所有客户端标识,然后把信息一个个发送出去.

界面设计 - 客户端

Client-UI

界面设计 - 服务端

Server-UI

代码实施 - 客户端

客户端没有做什么功能改进,这里就不贴代码了,需要看的学友可以到随笔后面下载源代码.

代码实施 - 服务端

这里将手动输入服务端IPv4地址改为了程序自动获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/// <summary>
/// 获取本地IPv4地址
/// </summary>
/// <returns>本地IPv4地址</returns>
public IPAddress GetLocalIPv4Address()
{
IPAddress localIPv4 = null;
//获取本机所有的IP地址列表
IPAddress[] ipAddressList = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ipAddress in ipAddressList)
{
//判断是否是IPv4地址
if (ipAddress.AddressFamily == AddressFamily.InterNetwork) //AddressFamily.InterNetwork表示IPv4
{
localIPv4 = ipAddress;
}
else
continue;
}
return localIPv4;
}

为了方便后期给所有访问的客户端群发信息,我们需要用过通过监听客户端来获取所有访问客户端的IP地址和端口号,并组成每个访问客户端的唯一标识clientName 用于显示在客户端列表上;客户端唯一标识还有个作用就是服务端可以选择性的给单独某个客户端发送信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//用于保存所有通信客户端的Socket
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

//创建与客户端建立连接的套接字
Socket socConnection = null;
string clientName = null; //创建访问客户端的名字
IPAddress clientIP; //访问客户端的IP
int clientPort; //访问客户端的端口号
/// <summary>
/// 持续不断监听客户端发来的请求, 用于不断获取客户端发送过来的连续数据信息
/// </summary>
private void WatchConnecting()
{
while (true)
{
try
{
socConnection = socketWatch.Accept();
}
catch (Exception ex)
{
txtMsg.AppendText(ex.Message); //提示套接字监听异常
break;
}
//获取访问客户端的IP
clientIP = (socConnection.RemoteEndPoint as IPEndPoint).Address;
//获取访问客户端的Port
clientPort = (socConnection.RemoteEndPoint as IPEndPoint).Port;
//创建访问客户端的唯一标识 由IP和端口号组成
clientName = "IP: " + clientIP +" Port: "+ clientPort;
lstClients.Items.Add(clientName); //在客户端列表添加该访问客户端的唯一标识
dicSocket.Add(clientName, socConnection); //将客户端名字和套接字添加到添加到数据字典中

//创建通信线程
ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg);
Thread thread = new Thread(pts);
thread.IsBackground = true;
//启动线程
thread.Start(socConnection);
txtMsg.AppendText("IP: " + clientIP + " Port: " + clientPort + " 的客户端与您连接成功,现在你们可以开始通信了...\r\n");
}
}

服务端向客户端发送信息,在没有选择具体某个客户端的情况下,默认群发. 如果选择了具体某个客户端,则单独向该客户端发送信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/// <summary>
/// 发送信息到客户端的方法
/// </summary>
/// <param name="sendMsg">发送的字符串信息</param>
private void ServerSendMsg(string sendMsg)
{
sendMsg = txtSendMsg.Text.Trim();
//将输入的字符串转换成 机器可以识别的字节数组
byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendMsg);
//向客户端列表选中的客户端发送信息
if (!string.IsNullOrEmpty(lstClients.Text.Trim()))
{
//获得相应的套接字 并将字节数组信息发送出去
dicSocket[lstClients.Text.Trim()].Send(arrSendMsg);
//通过Socket的send方法将字节数组发送出去
txtMsg.AppendText("您在 " + GetCurrentTime() + " 向 IP: " + clientIP + " Port: " + clientPort + " 的客户端发送了:\r\n" + sendMsg + "\r\n");
}
else //如果未选择任何客户端 则默认为群发信息
{
//遍历所有的客户端
for (int i = 0; i < lstClients.Items.Count; i++)
{
dicSocket[lstClients.Items[i].ToString()].Send(arrSendMsg);
}
txtMsg.AppendText("您在 " + GetCurrentTime() + " 群发了信息:\r\n" + sendMsg + " \r\n");
}
}

运行程序

1.首先启动服务端并连接各个客户端

1-server

1-client1

1-client2

2.服务端向所有客户端群发信息

2-server

2-client1

2-client2

3.向指定的客户端发送信息

3server

3-client2

这样,服务端向客户端群发信息的功能就做好了.如果大家感兴趣,可以结合第2篇-文件发送 来做个服务端向客户端群发文件的功能 :)

附上源代码

服务端ChatServer3.zip 客户端 ChatClient3.zip

转自:https://www.cnblogs.com/longwu/archive/2012/07/02/2572648.html