WinForm的Socket實現簡單的聊天室 IM

天天向上518發表於2021-03-15

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:這個只是一個簡單的聊天聯絡Code,待進一步完善,歡迎大家指教

 

相關文章