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 3341 Lost's revenge (AC自动机 + DP + 变进制/hash)题解

    题意:给你些分数串,给你一个主串,主串每出现一个分数串加一分,要你重新排列主串,最多几分 思路:显然这里开$40^4$去状压内存不够.但是我们自己想想会发现根本不用开那么大,因为很多状态是废状压,不是 ...

  2. openssl的用法

    Openssl详细用法: OpenSSL 是一个开源项目,其组成主要包括一下三个组件: openssl:多用途的命令行工具 libcrypto:加密算法库 libssl:加密模块应用库,实现了ssl及 ...

  3. js multiple packages & lerna.js

    js multiple packages & lerna.js

  4. v-for & for...in vs for...of

    v-for & for...in vs for...of for..in vs for...of for (const key in object) { if (Object.hasOwnPr ...

  5. IndexedDB All In One

    IndexedDB All In One https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API https://develope ...

  6. 什么是USDN稳定币?USDN的应用价值是什么?

    9月22日,美国货币监理署(OCC)发布了一项稳定币指南,主要内容围绕的是稳定币的监管及相关规定.一时间,稳定币得到了市场上广泛的关注.那么,什么是稳定币呢?什么又是USDN稳定币呢? 1.什么是稳定 ...

  7. Java中print、printf、println的区别

    Java中print.printf.println的区别 区别 print:标准输出,但不换行,不可以空参: println:标准输出,但会自动换行,可以空参,可以看做:println()相当于pri ...

  8. 用一次就会爱上的cli工具开发

    本文转载自用一次就会爱上的cli工具开发 写在前面 最近接手任务--使用nodejs开发一个公司内部使用的cli工具,简而言之就是输入一行命令快速搭建好项目结构,也可以通过不同的命令引入不同的文件. ...

  9. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法

    在新的一年我们学习这些有用的方法 JavaScript 为我们提供了许多处理数组的不同方法.我们将在几分钟内为您介绍 7 个基本且常用的数据方法,以提高您的 JS 开发技能. 1. Array.map ...

  10. HarmonyOS三方件开发指南(12)——cropper图片裁剪

    鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] 目录:1. cropper组件功能介绍2. cropper使用方法3. cropper组件开发实现4. ...