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. javascript和XML

    一,浏览器对XML DOM的支持1,DOM2级核心 var xmldom = document.implementation.createDocument("","roo ...

  2. Eclipce怎么恢复误删类

    选择误删除文件在eclipse所在包(文件夹) 在包上单击右键. 选择restore from local history... 在弹出的对话框中选择需要恢复的文件

  3. How To Install Linux & Nginx & MySQL & PHP (LEMP) stack on Raspberry Pi 3,Raspberry Pi 3,LEMP,Nginx,PHP, LEMP (not LNMP)

    1.   How To Install Linux & Nginx & MySQL & PHP (LEMP) stack on Raspberry Pi 3         R ...

  4. React Hooks vs React Class vs React Function All In One

    React Hooks vs React Class vs React Function All In One React Component Types React Hooks Component ...

  5. CSS Box Model All In One

    CSS Box Model All In One CSS 盒子模型 All In One CSS Box Model CSS Box Model Module Level 3 W3C Working ...

  6. Wi-Fi 6

    Wi-Fi 6 802.11ax https://en.wikipedia.org/wiki/IEEE_802.11ax https://www.wi-fi.org/discover-wi-fi/wi ...

  7. flat array

    flat array 已知如下数组: var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 1 ...

  8. Taro 物料市场

    Taro 物料市场 taro component demo https://taro-ext.jd.com/ https://taro-ext.jd.com/plugin/view/5caab6c68 ...

  9. 聊聊ASP.NET Core中的配置

    ​作为软件开发人员,我们当然喜欢一些可配置选项,尤其是当它允许我们改变应用程序的行为而无需修改或编译我们的应用程序时.无论你是使用新的还是旧的.NET时,可能希望利用json文件的配置.在这篇文章中, ...

  10. C++算法代码——单词查找

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=2472 题目描述 给定 n 个长度不超过 50 的由小写英文字母组成的单词准备查询,以 ...