C#简单的一对多聊天大厅 + 一对一私聊功能开发思路介绍及源码(socket通信)
一、前言起因
最近突然对socket通信产生了兴趣。于是简单的研究了一下,下面将研究的东西用最简单的大白话写出来与大家分享下。比较浅显,大神就别浪费时间看下面的内容了。
二、简单介绍
socket:插座、插孔,这里代表一种使用tcp或udp协议的简单双向通信连接(即“”套接字“”,我个人就理解为私人固定电话与电话公司。下方文字为专业描述,括号里的用固话和电话公司来比喻描述,可能不太准确望大神指教。)。主要包含客户端和服务端,其最简单的应用就是用于客户端跟服务端进行通讯。
服务端(电话公司):先初始化Socket(创建公司),为其绑定IP和端口以便客户端连接(bind,发布电话公司联系方式),同时对其进行实时监听(listen,等待家用电话办理业务或来电咨询),调用阻塞等待客户端连接或发来消息(accept,安排好客服)。
客户端(家用固话):先初始化Socket(购买电话机),然后连接到服务器(connect,去电话公司开户,办理电话线),同时服务端会给客户端分配好连接端口(电话公司给家用固话分配电话号)。当然,客户端也可以主动绑定未被占用的端口(主动申请挑选靓号),但是并不推荐(办理麻烦,同时可能办理的号码已经有人在用了)。
双方通信(沟通过程):如果连接服务器成功(固话办理成功,并分配好了电话号),客户端则可以向服务端发送数据,服务端同时也可以对接收到的内容进行处理并返回给客户端(固话跟电话公司进行咨询沟通),完成所有需要的操作后(所有咨询沟通完毕),关闭连接完成通信(挂断电话)。如果连接未成功(办理固话失败了),则会引发连接异常(光买了电话,但是没有电话线。。。)。
三、多人聊天大厅扩展思路
上述的连接过程为服务端与客户端一对一来进行的。那我们有没有什么办法可以多人一起进行聊天呢。当然是可以的,办法很简单,就是在服务端做一个消息分发功能(电话公司的公告或广播)。当有很多客户端连接进来时(很多电话同时连接在电话公司中),一个客户端给服务端发送了消息(甲用电话给电话公司留了言),那么服务端则利用分发功能,将该客户端发来的消息同时分发给其他连接在服务端的客户端(客户公司将甲电话的留言,循环发送给当时在线的乙电话、丙电话……)。那么问题又来了,服务端如何保存所有连接的客户端信息呢(电话公司如何存储客户信息)。其实也很简单,建立一个客户端socket列表(电话公司的客户信息档案),每当一个客户端跟服务端连接成功时,服务端就主动的将客户端socket存储进列表(新用户添加入档案),当客户端断开时,在将其从列表中移除即可(拆机的用户从档案中删除)。
四、点对点私聊扩展思路(后补)
在完成了聊天广播功能后,又开始思考要如何实现一对一的私聊功能呢。左思右想后,最终确定了实现方向。首先需要先从客户端输入要私聊对象的聊天地址,将私聊对象的地址和聊天信息一起传输到服务端(将要联系人的电话号码和留言信息一起发送给电话公司)。然后在从服务端对客户端发送的信息进行解析,匹配到私聊对象后,将客户端的消息单独发送给私聊对象并将反馈信息发送回客户端(电话公司根据要联系人的电话号码,将留言信息给发送过去,并给与反馈)。这样,就可以简单的通过服务端解析实现点对点私聊功能。
五、核心方法代码
/// <summary>
/// 广播信息
/// </summary>
/// <param name="useStr">传入收到的传输的内容</param>
/// <param name="obj">传送信息的客户</param>
/// <param name="isSendSelf">是否推送给自己</param>
/// <param name="isServerSelf">是否为服务器推送</param>
/// <returns>返回处理后的广播消息文字</returns>
private string Broadcast(string userStr, object obj,bool isSendSelf,bool isServerSelf)
{
Socket clientSend = obj as Socket; //当前发送信息的客户
string rtnMessage = "";
try
{
foreach (Socket client in userList)
{
if (!isSendSelf) //不推送自己
{
if (client != clientSend)//将信息广播给其他用户
{
if (!isServerSelf) //非服务器推送
{
rtnMessage = IPToAddress(clientSend) + ":" + userStr;
client.Send(Encoding.Default.GetBytes(rtnMessage));
}
else //服务器不推送服务器IP和端口,只推送“服务器”
{
rtnMessage = "【服务器】:" + userStr;
client.Send(Encoding.Default.GetBytes(rtnMessage));
}
}
}
else //推送自己
{
if (!isServerSelf)//非服务器推送
{
rtnMessage = IPToAddress(clientSend) + ":" + userStr;
client.Send(Encoding.Default.GetBytes(rtnMessage));
}
else //服务器不推送服务器IP和端口,只推送“服务器”
{
rtnMessage = "【服务器】:" + userStr;
client.Send(Encoding.Default.GetBytes(rtnMessage));
}
}
}
}
catch (Exception e)
{
userList.Remove(clientSend); //移除退出客户
//Thread.CurrentThread.Abort();//退出时掐死线程,不然递归反弹
}
return rtnMessage;
}
/// <summary>
/// 监听连接
/// </summary>
private void Accept()
{
//接受连接
Socket clientSocket = socketSevice.Accept();
userList.Add(clientSocket); //将连接的客户端存入列表
string clientMess = "【服务器】(" + DateTime.Now.ToString("HH:mm:ss")+")分配给您的端口为:(" + (clientSocket.RemoteEndPoint as IPEndPoint).Port.ToString() + ")"; //拼接分配端口号字符串
clientSocket.Send(Encoding.Default.GetBytes(clientMess)); //将分配信息反馈给连接的客户端
string mess = IPToAddress(clientSocket) + ":连接进来了"; //广播登录信息的客户端
Console.WriteLine(mess); //同步在服务端控制台显示
Broadcast(mess, clientSocket, false,true); //服务端广播,客户端连接消息(不广播给自己)
Thread RecvThread = new Thread(ReceMessage); //将接收客户端消息加入进程
RecvThread.IsBackground = true;
RecvThread.Start(clientSocket);
Accept();//递归
}
六、截图
七、源码包
下载地址:https://download.csdn.net/download/fwl562213140/12981612
说明:
一、服务器默认地址为:192.168.15.139,端口为:8888 。如需修改,可在服务端源码顶端的属性中进行修改。
二、客户端打开后,默认为服务端连接地址赋值。如需修改,可在客户端源码顶端的属性中进行修改。
三、客户端连接后,服务端自动将分配给客户端的端口号返回客户端。客户端解析后添加到标题栏。(该处根据需要,可以自行修改为返回IP地址等连接信息)
四、该demo由于只是为了实现简单的聊天大厅功能,所以未考虑粘包的情况。如果需要考虑请自行添加。参考地址:https://blog.csdn.net/weixin_30379911/article/details/97265907
五、开发环境为VS2015,服务端使用控制台,客户端使用Winform进行编写
六、本demo包中包含服务端、客户端的开发源码以及生成后的可执行文件。
后补:加入点对点私聊功能,需要在客户端的接收人地址中输入socket服务端分配的地址(ip:端口)。如果不输入则默认为全部在线客户端都会接收到的广播模式。
八、转载说明
码字不易,转载望留痕。
原文出处:https://blog.csdn.net/fwl562213140/article/details/109133059