1:什么是Socket
所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。
一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。
从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。
2:客服端和服务端的通信简单流程
3:服务端Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
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 ChartService { using System.Net; using System.Net.Sockets; using System.Threading; using ChatCommoms; using ChatModels; public partial class ServiceForm : Form { Socket _socket; private static List<ChatUserInfo> userinfo = new List<ChatUserInfo>(); public ServiceForm() { InitializeComponent(); } private void btnServicStart_Click( object sender, EventArgs e) { try { string ip = textBox_ip.Text.Trim(); string port = textBox_port.Text.Trim(); if ( string .IsNullOrWhiteSpace(ip) || string .IsNullOrWhiteSpace(port)) { MessageBox.Show( "IP与端口不可以为空!" ); } ServiceStartAccept(ip, int .Parse(port)); } catch (Exception) { MessageBox.Show( "连接失败!或者ip,端口参数异常" ); } } public void ServiceStartAccept( string ip, int port) { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint endport = new IPEndPoint(IPAddress.Parse(ip), port); socket.Bind(endport); socket.Listen(10); Thread thread = new Thread(Recevice); thread.IsBackground = true ; thread.Start(socket); textboMsg.AppendText( "服务开启ok..." ); } /// <summary> /// 开启接听服务 /// </summary> /// <param name="obj"></param> private void Recevice( object obj) { var socket = obj as Socket; while ( true ) { string remoteEpInfo = string .Empty; try { Socket txSocket = socket.Accept(); _socket = txSocket; if (txSocket.Connected) { remoteEpInfo = txSocket.RemoteEndPoint.ToString(); textboMsg.AppendText($ "\r\n{remoteEpInfo}:连接上线了..." ); var clientUser = new ChatUserInfo { UserID = Guid.NewGuid().ToString(), ChatUid = remoteEpInfo, ChatSocket = txSocket }; userinfo.Add(clientUser); listBoxCoustomerList.Items.Add( new ChatUserInfoBase { UserID = clientUser.UserID, ChatUid = clientUser.ChatUid }); listBoxCoustomerList.DisplayMember = "ChatUid" ; listBoxCoustomerList.ValueMember = "UserID" ; ReceseMsgGoing(txSocket, remoteEpInfo); } else { if (userinfo.Count > 0) { userinfo.Remove(userinfo.Where(c => c.ChatUid == remoteEpInfo).FirstOrDefault()); //移除下拉框对于的socket或者叫用户 } break ; } } catch (Exception) { if (userinfo.Count > 0) { userinfo.Remove(userinfo.Where(c => c.ChatUid == remoteEpInfo).FirstOrDefault()); //移除下拉框对于的socket或者叫用户 } } } } /// <summary> /// 接受来自客服端发来的消息 /// </summary> /// <param name="txSocket"></param> /// <param name="remoteEpInfo"></param> private void ReceseMsgGoing(Socket txSocket, string remoteEpInfo) { //退到一个客服端的时候 int getlength = txSocket.Receive(recesiveByte); 有抛异常 Thread thread = new Thread(() => { while ( true ) { try { byte [] recesiveByte = new byte [1024 * 1024 * 4]; int getlength = txSocket.Receive(recesiveByte); if (getlength <= 0) { break ; } var getType = recesiveByte[0].ToString(); string getmsg = Encoding.UTF8.GetString(recesiveByte, 1, getlength - 1); ShowMsg(remoteEpInfo, getType, getmsg); } catch (Exception) { //string userid = userinfo.FirstOrDefault(c => c.ChatUid == remoteEpInfo)?.ChatUid; listBoxCoustomerList.Items.Remove(remoteEpInfo); userinfo.Remove(userinfo.FirstOrDefault(c => c.ChatUid == remoteEpInfo)); //从集合中移除断开的socket listBoxCoustomerList.DataSource = userinfo; //重新绑定下来的信息 listBoxCoustomerList.DisplayMember = "ChatUid" ; listBoxCoustomerList.ValueMember = "UserID" ; txSocket.Dispose(); txSocket.Close(); } } }); thread.IsBackground = true ; thread.Start(); } private void ShowMsg( string remoteEpInfo, string getType, string getmsg) { textboMsg.AppendText($ "\r\n{remoteEpInfo}:消息类型:{getType}:{getmsg}" ); } private void Form1_Load( object sender, EventArgs e) { CheckForIllegalCrossThreadCalls = false ; this .textBox_ip.Text = "192.168.1.101" ; //初始值 this .textBox_port.Text = "50000" ; } /// <summary> /// 服务器发送消息,可以先选择要发送的一个用户 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSendMsg_Click( object sender, EventArgs e) { var getmSg = textBoxSendMsg.Text.Trim(); if ( string .IsNullOrWhiteSpace(getmSg)) { MessageBox.Show( "要发送的消息不可以为空" , "注意" ); return ; } var obj = listBoxCoustomerList.SelectedItem; int getindex = listBoxCoustomerList.SelectedIndex; if (obj == null || getindex == -1) { MessageBox.Show( "请先选择左侧用户的用户" ); return ; } var getChoseUser = obj as ChatUserInfoBase; var sendMsg = ServiceSockertHelper.GetSendMsgByte(getmSg, ChatTypeInfoEnum.StringEnum); userinfo.FirstOrDefault(c => c.ChatUid == getChoseUser.ChatUid)?.ChatSocket?.Send(sendMsg); } /// <summary> /// 给所有登录的用户发送消息,群发了 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click( object sender, EventArgs e) { var getmSg = textBoxSendMsg.Text.Trim(); if ( string .IsNullOrWhiteSpace(getmSg)) { MessageBox.Show( "要发送的消息不可以为空" , "注意" ); return ; } if (userinfo.Count <= 0) { MessageBox.Show( "暂时没有客服端登录!" ); return ; } var sendMsg = ServiceSockertHelper.GetSendMsgByte(getmSg, ChatTypeInfoEnum.StringEnum); foreach (var usersocket in userinfo) { usersocket.ChatSocket?.Send(sendMsg); } } /// <summary> /// 服务器给发送震动 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSendSnak_Click( object sender, EventArgs e) { var obj = listBoxCoustomerList.SelectedItem; int getindex = listBoxCoustomerList.SelectedIndex; if (obj == null || getindex == -1) { MessageBox.Show( "请先选择左侧用户的用户" ); return ; } var getChoseUser = obj as ChatUserInfoBase; byte [] sendMsgByte = ServiceSockertHelper.GetSendMsgByte( "" , ChatTypeInfoEnum.Snake); userinfo.FirstOrDefault(c => c.ChatUid == getChoseUser.ChatUid)?.ChatSocket.Send(sendMsgByte); } } } |
4:客服端Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
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 ChatClient { using ChatCommoms; using System.Net; using System.Net.Sockets; using System.Threading; public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load( object sender, EventArgs e) { CheckForIllegalCrossThreadCalls = false ; this .textBoxIp.Text = "192.168.1.101" ; //先初始化一个默认的ip等 this .textBoxPort.Text = "50000" ; } Socket clientSocket; /// <summary> /// 客服端连接到服务器 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnServicStart_Click( object sender, EventArgs e) { try { var ipstr = textBoxIp.Text.Trim(); var portstr = textBoxPort.Text.Trim(); if ( string .IsNullOrWhiteSpace(ipstr) || string .IsNullOrWhiteSpace(portstr)) { MessageBox.Show( "要连接的服务器ip和端口都不可以为空!" ); return ; } clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.Connect(IPAddress.Parse(ipstr), int .Parse(portstr)); labelStatus.Text = "连接到服务器成功...!" ; ReseviceMsg(clientSocket); } catch (Exception) { MessageBox.Show( "请检查要连接的服务器的参数" ); } } private void ReseviceMsg(Socket clientSocket) { Thread thread = new Thread(() => { while ( true ) { try { Byte[] byteContainer = new Byte[1024 * 1024 * 4]; int getlength = clientSocket.Receive(byteContainer); if (getlength <= 0) { break ; } var getType = byteContainer[0].ToString(); string getmsg = Encoding.UTF8.GetString(byteContainer, 1, getlength - 1); GetMsgFomServer(getType, getmsg); } catch (Exception ex) { } } }); thread.IsBackground = true ; thread.Start(); } private void GetMsgFomServer( string strType, string msg) { this .textboMsg.AppendText($ "\r\n类型:{strType};{msg}" ); } /// <summary> /// 文字消息的发送 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSendMsg_Click( object sender, EventArgs e) { var msg = textBoxSendMsg.Text.Trim(); var sendMsg = ServiceSockertHelper.GetSendMsgByte(msg, ChatModels.ChatTypeInfoEnum.StringEnum); int sendMsgLength = clientSocket.Send(sendMsg); } } } |
5:测试效果:
6:完整Code GitHUb下载路径
https://github.com/zrf518/WinformSocketChat.git
7:这个只是一个简单的聊天练习Demo,待进一步完善(实现部分功能,传递的消息byte[0]为消息的类型,用来判断是文字,还是图片等等),欢迎大家指教
以上就是c#基于WinForm的Socket实现简单的聊天室 IM的详细内容,更多关于c# WinForm实现聊天室 IM的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/Fengge518/p/14536940.html