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

WinForm的Socket实现简单的聊天室 IM的更多相关文章

  1. Python Socket实现简单的聊天室

    通过参考其他牛人的文章和代码,  再根据自己的理解总结得出,  说明已经加在注释中, FYI 主要参考文章: http://blog.csdn.net/dk_zhe/article/details/3 ...

  2. 简单的聊天室代码php+swoole

    php swoole+websocket 客户端代码 <!DOCTYPE html> <html> <head> <title></title&g ...

  3. Android简单的聊天室开发(client与server沟通)

    请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ...

  4. Netty学习笔记(四) 简单的聊天室功能之服务端开发

    前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...

  5. 玩转Node.js(四)-搭建简单的聊天室

    玩转Node.js(四)-搭建简单的聊天室 Nodejs好久没有跟进了,最近想用它搞一个聊天室,然后便偶遇了socket.io这个东东,说是可以用它来简单的实现实时双向的基于事件的通讯机制.我便看了一 ...

  6. 利用socket.io构建一个聊天室

    利用socket.io来构建一个聊天室,输入自己的id和消息,所有的访问用户都可以看到,类似于群聊. socket.io 这里只用来做一个简单的聊天室,官网也有例子,很容易就做出来了.其实主要用的东西 ...

  7. Express+Socket.IO 实现简易聊天室

    代码地址如下:http://www.demodashi.com/demo/12477.html 闲暇之余研究了一下 Socket.io,搭建了一个简易版的聊天室,如有不对之处还望指正,先上效果图: 首 ...

  8. nodejs与websocket模拟简单的聊天室

    nodejs与websocket模拟简单的聊天室 server.js const http = require('http') const fs = require('fs') var userip ...

  9. ASP.NET Signalr 2.0 实现一个简单的聊天室

    学习了一下SignalR 2.0,http://www.asp.net/signalr 文章写的很详细,如果头疼英文,还可以机翻成中文,虽然不是很准确,大概还是容易看明白. 理论要结合实践,自己动手做 ...

随机推荐

  1. anaconda jupyter notebook 启动方法

    介绍 anaconda jupyter notebook是一种基于浏览器的python编译环境.(大概) 使用时可能因为浏览器缓存造成问题. 但是很方便. 启动方法 anaconda navigato ...

  2. 深入剖析JavaScript中的对象与原始值之间的转换机制

    我们都知道原始值之间是可以互相转换的,但是如果对象转原始值呢? 所有的对象在布尔上下文(context)中均为 true .所以对于对象,不存在 to-boolean 转换, 只有字符串和数值转换. ...

  3. js console.log all in one

    js console.log all in one this & arguments "use strict"; /** * * @author xgqfrms * @li ...

  4. css & focus-within & pseudo class

    css & focus-within & pseudo class demo :focus-within https://developer.mozilla.org/en-US/doc ...

  5. c++ 获取和设置 窗口标题

    有些窗口标题中含有中文,可能识别不出来,可以改一下 SetWindowTextW GetWindowTextW 设置: SetWindowTextW( (HWND)0x00370868/*窗口句柄*/ ...

  6. 2021 NGK生态所体验好、交易快 引人注目!

    据悉,NGK计划于2021年2月15日正式上线自己的生态所(时间待定),目的在于满足NGK生态建设者对于NGK几大币种的交易等需求,如NGK.BGV.SPC.USDN.VAST等.只要上NGK生态所, ...

  7. Renice INC:解密干型葡萄酒

    市场上,干型葡萄酒往往对比甜型葡萄酒(如甜红.甜白)受到更多葡萄酒爱好者的青睐.在葡萄酒界,大部分的红葡萄酒和白葡萄酒也都是干型的,而且它们的口感往往各有特色,并非千篇一律.今天,就跟随Renice ...

  8. WebRTC 系列之音频会话管理

    WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音对话或视频对话的 API.W3C 和 IETF 在2021年1月26日共同宣布 WebRTC 1. ...

  9. MySQL的简单使用方法备忘

    这只是一篇我的个人备忘录,写的是我常用的命令.具体可以参考"菜鸟教程" https://www.runoob.com/mysql/mysql-tutorial.html 登录(用户 ...

  10. Unity 定点投射固定高度抛物线

    假设同一平面中有AB两点,A点向B点水平射击,很容易想象子弹会沿由A指向B的向量方向前进,经过时间t后到达B点,若此时A点不再水平射击,改为以抛物线的方式向B点投射,同样需要在时间t后击中B点,那么如 ...