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. HDU 6611 K Subsequence(Dijkstra优化费用流 模板)题解

    题意: 有\(n\)个数\(a_1\cdots a_n\),现要你给出\(k\)个不相交的非降子序列,使得和最大. 思路: 费用流建图,每个点拆点,费用为\(-a[i]\),然后和源点连边,和后面非降 ...

  2. Makefile 流程控制(error,warning)等调试选项

    1.退出码 0 ok1 错误2 使用了-q 选项 且目标不需要更新 返回2 2.选项 -f --file 指定makefile脚本 -n --just-print --dry -run -- reco ...

  3. 推荐一个vuepress模板,一键快速搭建文档站

    介绍 vuepress-template是一个简单的VuePress案例模板,目的是让用户可以直接clone这个仓库,作为初始化一个VuePress网站启动项目,然后在这个项目的基础上新增自定义配置和 ...

  4. ossutilmac64

    ossutilmac64 ossutil是以命令行方式管理OSS数据的工具,提供方便.简洁.丰富的存储空间(Bucket)和文件(Object)管理命令,支持Windows.Linux. Mac平台. ...

  5. 20 个使用原生 JavaScript 实现的 Web 项目

    20 个使用原生 JavaScript 实现的 Web 项目 20 vanilla JavaScript Web Projects https://github.com/learning-js-by- ...

  6. JavaScript var, let, const difference All In One

    JavaScript var, let, const difference All In One js var, let, const 区别 All In One 是否存在 hoisting var ...

  7. Virtual Reality In Action

    Virtual Reality In Action VR WebXR immersive 沉浸式 https://github.com/immersive-web/webxr https://imme ...

  8. how to tell a function arguments length in js

    how to tell a function arguments length in js JavaScript函数不对参数值(参数)执行任何检查 https://www.w3schools.com/ ...

  9. JS Calendar API

    JS Calendar API js 如何获取当天是周几(一周的第几天) const date = new Date(); // Mon Mar 23 2020 15:15:36 GMT+0800 ( ...

  10. nasm astrspn函数 x86

    xxx.asm %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export ast ...