WinForm的Socket实现简单的聊天室 IM

1:什么是Socket

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。

一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。

从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。

2:客服端和服务端的通信简单流程

3:服务端Code:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows.Forms;
 10 
 11 namespace ChartService
 12 {
 13     using System.Net;
 14     using System.Net.Sockets;
 15     using System.Threading;
 16     using ChatCommoms;
 17     using ChatModels;
 18 
 19     public partial class ServiceForm : Form
 20     {
 21         Socket _socket;
 22         private static List<ChatUserInfo> userinfo = new List<ChatUserInfo>();
 23         public ServiceForm()
 24         {
 25             InitializeComponent();
 26 
 27         }
 28 
 29         private void btnServicStart_Click(object sender, EventArgs e)
 30         {
 31             try
 32             {
 33                 string ip = textBox_ip.Text.Trim();
 34                 string port = textBox_port.Text.Trim();
 35                 if (string.IsNullOrWhiteSpace(ip) || string.IsNullOrWhiteSpace(port))
 36                 {
 37                     MessageBox.Show("IP与端口不可以为空!");
 38                 }
 39                 ServiceStartAccept(ip, int.Parse(port));
 40             }
 41             catch (Exception)
 42             {
 43                 MessageBox.Show("连接失败!或者ip,端口参数异常");
 44             }
 45         }
 46         public void ServiceStartAccept(string ip, int port)
 47         {
 48             Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 49             IPEndPoint endport = new IPEndPoint(IPAddress.Parse(ip), port);
 50             socket.Bind(endport);
 51             socket.Listen(10);
 52             Thread thread = new Thread(Recevice);
 53             thread.IsBackground = true;
 54             thread.Start(socket);
 55             textboMsg.AppendText("服务开启ok...");
 56         }
 57 
 58         /// <summary>
 59         /// 开启接听服务
 60         /// </summary>
 61         /// <param name="obj"></param>
 62         private void Recevice(object obj)
 63         {
 64             var socket = obj as Socket;
 65             while (true)
 66             {
 67                 string remoteEpInfo = string.Empty;
 68                 try
 69                 {
 70                     Socket txSocket = socket.Accept();
 71                     _socket = txSocket;
 72                     if (txSocket.Connected)
 73                     {
 74                         remoteEpInfo = txSocket.RemoteEndPoint.ToString();
 75                         textboMsg.AppendText($"\r\n{remoteEpInfo}:连接上线了...");
 76                         var clientUser = new ChatUserInfo
 77                         {
 78                             UserID = Guid.NewGuid().ToString(),
 79                             ChatUid = remoteEpInfo,
 80                             ChatSocket = txSocket
 81                         };
 82                         userinfo.Add(clientUser);
 83 
 84 
 85                         listBoxCoustomerList.Items.Add(new ChatUserInfoBase { UserID = clientUser.UserID, ChatUid = clientUser.ChatUid });
 86                         listBoxCoustomerList.DisplayMember = "ChatUid";
 87                         listBoxCoustomerList.ValueMember = "UserID";
 88 
 89                         ReceseMsgGoing(txSocket, remoteEpInfo);
 90                     }
 91                     else
 92                     {
 93                         if (userinfo.Count > 0)
 94                         {
 95                             userinfo.Remove(userinfo.Where(c => c.ChatUid == remoteEpInfo).FirstOrDefault());
 96                             //移除下拉框对于的socket或者叫用户
 97                         }
 98                         break;
 99                     }
100                 }
101                 catch (Exception)
102                 {
103                     if (userinfo.Count > 0)
104                     {
105                         userinfo.Remove(userinfo.Where(c => c.ChatUid == remoteEpInfo).FirstOrDefault());
106                         //移除下拉框对于的socket或者叫用户
107                     }
108                 }
109             }
110 
111         }
112 
113         /// <summary>
114         /// 接受来自客服端发来的消息
115         /// </summary>
116         /// <param name="txSocket"></param>
117         /// <param name="remoteEpInfo"></param>
118         private void ReceseMsgGoing(Socket txSocket, string remoteEpInfo)
119         {
120 
121             //退到一个客服端的时候 int getlength = txSocket.Receive(recesiveByte); 有抛异常
122             Thread thread = new Thread(() =>
123             {
124                 while (true)
125                 {
126                     try
127                     {
128                         byte[] recesiveByte = new byte[1024 * 1024 * 4];
129                         int getlength = txSocket.Receive(recesiveByte);
130                         if (getlength <= 0) { break; }
131 
132                         var getType = recesiveByte[0].ToString();
133                         string getmsg = Encoding.UTF8.GetString(recesiveByte, 1, getlength - 1);
134                         ShowMsg(remoteEpInfo, getType, getmsg);
135                     }
136                     catch (Exception)
137                     {
138                         //string userid = userinfo.FirstOrDefault(c => c.ChatUid == remoteEpInfo)?.ChatUid;
139                         listBoxCoustomerList.Items.Remove(remoteEpInfo);
140                         userinfo.Remove(userinfo.FirstOrDefault(c => c.ChatUid == remoteEpInfo));//从集合中移除断开的socket
141 
142                         listBoxCoustomerList.DataSource = userinfo;//重新绑定下来的信息
143                         listBoxCoustomerList.DisplayMember = "ChatUid";
144                         listBoxCoustomerList.ValueMember = "UserID";
145                         txSocket.Dispose();
146                         txSocket.Close();
147                     }
148                 }
149             });
150             thread.IsBackground = true;
151             thread.Start();
152 
153         }
154 
155         private void ShowMsg(string remoteEpInfo, string getType, string getmsg)
156         {
157             textboMsg.AppendText($"\r\n{remoteEpInfo}:消息类型:{getType}:{getmsg}");
158         }
159         private void Form1_Load(object sender, EventArgs e)
160         {
161             CheckForIllegalCrossThreadCalls = false;
162             this.textBox_ip.Text = "192.168.1.101";//初始值
163             this.textBox_port.Text = "50000";
164         }
165 
166         /// <summary>
167         /// 服务器发送消息,可以先选择要发送的一个用户
168         /// </summary>
169         /// <param name="sender"></param>
170         /// <param name="e"></param>
171         private void btnSendMsg_Click(object sender, EventArgs e)
172         {
173             var getmSg = textBoxSendMsg.Text.Trim();
174             if (string.IsNullOrWhiteSpace(getmSg))
175             {
176                 MessageBox.Show("要发送的消息不可以为空", "注意"); return;
177             }
178             var obj = listBoxCoustomerList.SelectedItem;
179             int getindex = listBoxCoustomerList.SelectedIndex;
180             if (obj == null || getindex == -1)
181             {
182                 MessageBox.Show("请先选择左侧用户的用户"); return;
183             }
184             var getChoseUser = obj as ChatUserInfoBase;
185             var sendMsg = ServiceSockertHelper.GetSendMsgByte(getmSg, ChatTypeInfoEnum.StringEnum);
186             userinfo.FirstOrDefault(c => c.ChatUid == getChoseUser.ChatUid)?.ChatSocket?.Send(sendMsg);
187         }
188 
189         /// <summary>
190         /// 给所有登录的用户发送消息,群发了
191         /// </summary>
192         /// <param name="sender"></param>
193         /// <param name="e"></param>
194         private void button1_Click(object sender, EventArgs e)
195         {
196             var getmSg = textBoxSendMsg.Text.Trim();
197             if (string.IsNullOrWhiteSpace(getmSg))
198             {
199                 MessageBox.Show("要发送的消息不可以为空", "注意"); return;
200             }
201             if (userinfo.Count <= 0)
202             {
203                 MessageBox.Show("暂时没有客服端登录!"); return;
204             }
205             var sendMsg = ServiceSockertHelper.GetSendMsgByte(getmSg, ChatTypeInfoEnum.StringEnum);
206             foreach (var usersocket in userinfo)
207             {
208                 usersocket.ChatSocket?.Send(sendMsg);
209             }
210         }
211 
212         /// <summary>
213         /// 服务器给发送震动
214         /// </summary>
215         /// <param name="sender"></param>
216         /// <param name="e"></param>
217         private void btnSendSnak_Click(object sender, EventArgs e)
218         {
219             var obj = listBoxCoustomerList.SelectedItem;
220             int getindex = listBoxCoustomerList.SelectedIndex;
221             if (obj == null || getindex == -1)
222             {
223                 MessageBox.Show("请先选择左侧用户的用户"); return;
224             }
225             var getChoseUser = obj as ChatUserInfoBase;
226 
227             byte[] sendMsgByte = ServiceSockertHelper.GetSendMsgByte("", ChatTypeInfoEnum.Snake);
228             userinfo.FirstOrDefault(c => c.ChatUid == getChoseUser.ChatUid)?.ChatSocket.Send(sendMsgByte);
229         }
230 
231 
232     }
233 }

4:客服端Code:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows.Forms;
 10 
 11 namespace ChatClient
 12 {
 13     using ChatCommoms;
 14     using System.Net;
 15     using System.Net.Sockets;
 16     using System.Threading;
 17 
 18     public partial class Form1 : Form
 19     {
 20         public Form1()
 21         {
 22             InitializeComponent();
 23         }
 24 
 25         private void Form1_Load(object sender, EventArgs e)
 26         {
 27             CheckForIllegalCrossThreadCalls = false;
 28             this.textBoxIp.Text = "192.168.1.101";//先初始化一个默认的ip等
 29             this.textBoxPort.Text = "50000";
 30         }
 31 
 32         Socket clientSocket;
 33         /// <summary>
 34         /// 客服端连接到服务器
 35         /// </summary>
 36         /// <param name="sender"></param>
 37         /// <param name="e"></param>
 38         private void btnServicStart_Click(object sender, EventArgs e)
 39         {
 40             try
 41             {
 42                 var ipstr = textBoxIp.Text.Trim();
 43                 var portstr = textBoxPort.Text.Trim();
 44                 if (string.IsNullOrWhiteSpace(ipstr) || string.IsNullOrWhiteSpace(portstr))
 45                 {
 46                     MessageBox.Show("要连接的服务器ip和端口都不可以为空!");
 47                     return;
 48                 }
 49                 clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 50                 clientSocket.Connect(IPAddress.Parse(ipstr), int.Parse(portstr));
 51                 labelStatus.Text = "连接到服务器成功...!";
 52                 ReseviceMsg(clientSocket);
 53 
 54             }
 55             catch (Exception)
 56             {
 57                 MessageBox.Show("请检查要连接的服务器的参数");
 58             }
 59         }
 60         private void ReseviceMsg(Socket clientSocket)
 61         {
 62 
 63             Thread thread = new Thread(() =>
 64              {
 65                  while (true)
 66                  {
 67                      try
 68                      {
 69                          Byte[] byteContainer = new Byte[1024 * 1024 * 4];
 70                          int getlength = clientSocket.Receive(byteContainer);
 71                          if (getlength <= 0)
 72                          {
 73                              break;
 74                          }
 75                          var getType = byteContainer[0].ToString();
 76                          string getmsg = Encoding.UTF8.GetString(byteContainer, 1, getlength - 1);
 77 
 78                          GetMsgFomServer(getType, getmsg);
 79                      }
 80                      catch (Exception ex)
 81                      {
 82                      }
 83                  }
 84              });
 85             thread.IsBackground = true;
 86             thread.Start();
 87 
 88         }
 89 
 90         private void GetMsgFomServer(string strType, string msg)
 91         {
 92             this.textboMsg.AppendText($"\r\n类型:{strType};{msg}");
 93         }
 94 
 95         /// <summary>
 96         /// 文字消息的发送
 97         /// </summary>
 98         /// <param name="sender"></param>
 99         /// <param name="e"></param>
100         private void btnSendMsg_Click(object sender, EventArgs e)
101         {
102             var msg = textBoxSendMsg.Text.Trim();
103             var sendMsg = ServiceSockertHelper.GetSendMsgByte(msg, ChatModels.ChatTypeInfoEnum.StringEnum);
104             int sendMsgLength = clientSocket.Send(sendMsg);
105         }
106     }
107 }

5:测试效果:

6:完整Code GitHUb下载路径 https://github.com/zrf518/WinformSocketChat.git

7:这个只是一个简单的聊天练习Demo,待进一步完善(实现部分功能,传递的消息byte[0]为消息的类型,用来判断是文字,还是图片等等),欢迎大家指教

 

posted @ 2021-03-15 12:51  天天向上518  阅读(948)  评论(3编辑  收藏  举报