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

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值