c#基于socket编程实现简单多人聊天程序

xiaoxiao2021-02-28  85

首先直接上代码链接,欢迎修改与指正:https://github.com/yinyoupoet/chatRoomTest 代码、可运行程序、详细设计文档、使用说明等都在里面啦

然后再上图你们感受下:

客户端本来想做个在线列表的,就在那空出来的那块,因为时间原因做出了半成品但是还有bug,就没上传了。

下面讲一下设计思路。(如果是新手不懂下面的术语也没关系,我在代码的注释里会写的很清楚,可以先大致了解一下) 多人聊天用p2p不太好,就是用c/s模式了。服务器设置好监听套接字,绑定监听的IP地址和端口,然后一直监听该端口就行了。 客户端首先需要连接上服务器,所以设置的IP和端口(要连接的服务器的IP和端口)必须是得和服务器一样的,不然肯定连接不上。 然后客户端连接上后,服务器将其用户名与客户端的套接字绑定好,然后保存在一个Dictionary里面。以后客户端发送的消息由服务器直接向该数组中所有套接字转发即可。

代码有点长,而且是winform,所以不好放代码,本程序是用vs2013写的,必须装了.NET Fragment 4.5以上框架的windows 64位系统才能运行程序。

不过把代码放在最后,供github抽风进不去时看看,注释很详细,我也是从完全不懂抄别人的慢慢找资料学会的。只放了后台代码,界面的不好放这了,不过一般都可根据命名和截图猜得出。建议还是直接去github里面下载下来,看的更舒服。

服务器端:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Windows.Threading; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using System.Security.Cryptography; //参考网址: http://www.tuicool.com/articles/RBJFRn //参考网址: http://zhangxuefei.site/p/59 namespace chatRoomServer { public partial class Form1 : Form { public Form1() { InitializeComponent(); ipadr = IPAddress.Loopback; } //保存多个客户端的通信套接字 public static Dictionary<String, Socket> clientList = null; //申明一个监听套接字 Socket serverSocket = null; //设置一个监听标记 Boolean isListen = true; //开启监听的线程 Thread thStartListen; //默认一个主机监听的IP IPAddress ipadr; //将endpoint设置为成员字段 IPEndPoint endPoint; private void btnStart_Click(object sender, EventArgs e) { if (serverSocket == null) { try { isListen = true; clientList = new Dictionary<string, Socket>(); //实例监听套接字 //参考网址:http://blog.csdn.net/sight_/article/details/8138802 //int socket(int domain, int type, int protocol); // domain: 协议域,又名协议族。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。 //协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。 // type: 指定socket类型,。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等 // protocol: 指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等 //并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议 serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //AddressFamily.InterNetwork代表IPV4地址,不包含IPV6 参考网址:http://bbs.csdn.net/topics/390283656?page=1 //端点 /* 在IPEndPoint类中有两个很有用的构造函数: public IPEndPoint(long, int); public IPEndPoint(IPAddress, int); 它们的作用就是用指定的地址和端口号初始化IPEndPoint类的新实例。 * 参考网址:http://www.cnblogs.com/Medeor/p/3546359.html */ //IPAddress ipadr = IPAddress.Parse("192.168.1.100"); //如果txtIP里面有值,就选择填入的IP作为服务器IP,不填的话就默认是本机的 endPoint = new IPEndPoint(ipadr, 8080); //IPAddress.loopback是本地环回接口,其实是虚拟接口,物理不存在的 参考网址:http://baike.sogou.com/v7893363.htm?fromTitle=loopback //绑定 //把一个地址族的特定地址给socket //int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //sockfd: 即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。 //*addr: 一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同 //addrlen: 对应的是地址的长度 //通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器; //而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。 //这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。 //参考网址:http://blog.csdn.net/sight_/article/details/8138802 //但是这里的bind不是上面的bind,是.NET里面的一个bind,使 Socket 与一个本地终结点相关联。 命名空间:System.Net.Sockets 程序集:System(在 system.dll 中) //给套接字绑定一个端点,其实差不多用上面的那种bind也能实现 //参考网站: https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind(VS.80).aspx //10.127.221.248 try { serverSocket.Bind(endPoint); //设置最大连接数 //如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。 //int listen(int sockfd, int backlog); //listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。 //socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。 serverSocket.Listen(100); thStartListen = new Thread(StartListen); thStartListen.IsBackground = true; thStartListen.Start(); //这里有点不一样,原文用的是 txtMsg.Dispatcher.BeginInvoke /*Invoke在线程中等待Dispatcher调用指定方法,完成后继续下面的操作。 * BeginInvoke不必等待Dispatcher调用制定方法,直接继续下面的操作。 * 参考网址: https://zhidao.baidu.com/question/1175146013330422099.html?qbl=relate_question_1&word=Dispatcher.BeginInvoke
转载请注明原文地址: https://www.6miu.com/read-23684.html

最新回复(0)