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,待進一步完善,歡迎大家指教