C# WinForm使用Socket通信搭建简易聊天室
1、创建WinForm应用程序
主入口两个按钮事件:
/// <summary> /// 打开客户端 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_OpenClient_Click(object sender, EventArgs e) { SocketClient socketClient = new SocketClient(); socketClient.ShowDialog(); } /// <summary> /// 打开服务端 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_OpenService_Click(object sender, EventArgs e) { SocketService socketService = new SocketService(); socketService.ShowDialog(); }
2、服务端界面绘制
其中txt_MessageBox与txtSendBox属性Multiline=true
3、客户端界面绘制
4、服务端功能实现
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; namespace Socket通信聊天室 { public partial class SocketService : Form { public SocketService() { InitializeComponent(); //多线程编程中,如果子线程需要使用主线程中创建的对象和控件,最好在主线程中体现进行检查取消 CheckForIllegalCrossThreadCalls = false; } /// <summary> /// 界面加载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SocketService_Load(object sender, EventArgs e) { //获取Ip大概率位【0.0.0.0】表示任何IP //在服务端连接的时候先查看本机Ipv4地址 var ip = IPAddress.Any.ToString(); this.txt_IpAddress.Text = ip; } /// <summary> /// 创建一个字典,用来存储记录服务器与客户端之间的连接(线程问题) /// </summary> Dictionary<string, System.Net.Sockets.Socket> clientList = new Dictionary<string, System.Net.Sockets.Socket>(); private void btn_Create_Click(object sender, EventArgs e) { System.Threading.Thread myServer = new System.Threading.Thread(MySocket); //设置这个线程是后台线程 myServer.IsBackground = true; myServer.Start(); } /// <summary> /// 发送 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_Send_Click(object sender, EventArgs e) { if (this.txtSendBox.Text != "") { SendMsg(this.txtSendBox.Text); this.txtSendBox.Text = ""; } } /// <summary> /// 创建连接的方法 /// </summary> public void MySocket() { //1.创建服务器端电话 Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); //2.创建手机卡 IPAddress iP = IPAddress.Parse(this.txt_IpAddress.Text); IPEndPoint endPoint = new IPEndPoint(iP, int.Parse(this.txt_Port.Text)); //3.将电话卡插进电话中 server.Bind(endPoint); //4.开始监听电话卡 //同一时刻内允许同时加入链接的最大数量 server.Listen(20); this.txt_MessageBox.AppendText("服务器已经成功开启! \r\n"); //5.等待来电接电话 while (true) { //接受接入的一个客户端 Socket connectClient = server.Accept(); if (connectClient != null) { string infor = connectClient.RemoteEndPoint.ToString(); clientList.Add(infor, connectClient); this.txt_MessageBox.AppendText(infor + "加入服务器! \r\n"); ///服务器将消息发送至客服端 string msg = $"[{infor}]已成功进入到聊天室!"; SendMsg(msg); //每有一个客户端接入时,需要有一个线程进行服务 Thread threadClient = new Thread(ReciveMsg); threadClient.IsBackground = true; //设置这个线程中的通信对象是对应的Socket和客户端Socket进行通信 threadClient.Start(connectClient); } } } /// <summary> /// 不停尝试接收服务器接收到客户端发送的消息 /// </summary> /// <param name="o">客户端</param> public void ReciveMsg(object o) { Socket client = o as Socket; while (true) { try { ///定义服务器接收的字节大小 byte[] arrMsg = new byte[1024 * 1024]; ///接收到的信息大小(所占字节数) int length = client.Receive(arrMsg); if (length > 0) { string recMsg = Encoding.UTF8.GetString(arrMsg, 0, length); //获取客户端的端口号 IPEndPoint endPoint = client.RemoteEndPoint as IPEndPoint; //服务器显示客户端的端口号和消息 this.txt_MessageBox.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}[{ endPoint.Port.ToString()}]:{recMsg} \r\n"); //服务器发送接收到的客户端信息给客户端 SendMsg($"[{endPoint.Port.ToString()}]{recMsg}"); } } catch (Exception) { ///关闭客户端 client.Close(); ///移除添加在字典中的服务器和客户端之间的线程 clientList.Remove(client.RemoteEndPoint.ToString()); } } } /// <summary> /// 服务器发送消息, /// </summary> public void SendMsg(string str) { ///遍历出字典中的所有线程 foreach (var item in clientList) { byte[] arrMsg = Encoding.UTF8.GetBytes(str); ///获取键值,发送消息 item.Value.Send(arrMsg); } } } }
5、客户端功能实现
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace Socket通信聊天室 { /// <summary> /// 客户端 /// </summary> public partial class SocketClient : Form { public SocketClient() { InitializeComponent(); } /// <summary> /// Socket连接 /// </summary> private System.Net.Sockets.Socket socket; /// <summary> /// 加入聊天室 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_Join_Click(object sender, EventArgs e) { // Internet 协议、字节流、IPv4连接 socket = new System.Net.Sockets.Socket( System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.IP); System.Net.IPAddress ip = System.Net.IPAddress.Parse(this.txt_IpAddress.Text); System.Net.IPEndPoint point = new System.Net.IPEndPoint(ip, int.Parse(this.txt_Port.Text)); socket.Connect(point); System.Threading.Thread thread = new System.Threading.Thread(ReciveMsg); thread.IsBackground = true; thread.Start(socket); } /// <summary> /// 不停的尝试接收消息 /// 接收信息 /// </summary> /// <param name="o">客户端</param> public void ReciveMsg(object o) { System.Net.Sockets.Socket client = o as System.Net.Sockets.Socket; while (true) { try { ///定义客户端接收到的信息大小 byte[] arrList = new byte[1024 * 1024]; ///接收到的信息大小(所占字节数) int length = client.Receive(arrList); this.txt_MessageBox.AppendText($"{DateTime.Now}:{Encoding.UTF8.GetString(arrList, 0, length)} \r\n"); } catch (Exception) { client.Close(); } } } /// <summary> /// 发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_Send_Click(object sender, EventArgs e) { if (txtSendBox.Text != "") { byte[] arrMsg = Encoding.UTF8.GetBytes(txtSendBox.Text); socket.Send(arrMsg); } } } }
6、调试
6、1 开始执行(不调试)
同一个WinForm项目同时开启两个运行结果需在VS中添加【开始执行(不调试)】功能
6、2 服务端启动时
服务端启动时自动获取到的IP地址【0.0.0.0】并不是一个真实的的IP地址,它表示本机中所有的IPV4地址。
故客户端连接时输入的IP地址应为本机的IPv4地址,可通过cmd命令查看
6、3 调试结果
7、Demo下载
完整Demo下载:C# WinForm使用Socket通信搭建简易聊天室
本文来自博客园,作者:流纹,转载请注明原文链接:https://www.cnblogs.com/lwk9527/p/17374638.html