C# Winform Socket点对点通信
前言
Socket的英文原义是“孔”或“插座”,其实在网络编程中Socket就是这个意思,就像我们打电话,要首先知道对方的手机号一样,这个手机号就相当于一个Socket号、一个插座,在网络编程中就是ip+端口作为一个插座。
实现
System.Net.Sockets命名空间下提供了Socket类,使.net下Socket变得很简单,Socket实现点对点通信有两种方式,一种是用服务器转接,所有的客户端都发送到服务端,客户端只做客户端;另一种是客户端既是服务端又是服务端,就是既监听又发送信息。这篇就用第二种方式简单实现下,首先看下简单示意图:
发送信息代码:
1 string message = txtMsg.Text.Trim();
2 socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
3 string remoteIp = this.txtRemoteIP.Text;
4 string remotePort = this.txtRemotePort.Text;
5 int serverPort = Convert.ToInt32(remotePort);
6 IPAddress serverIp = IPAddress.Parse(remoteIp);
7 IPEndPoint remoteIep = new IPEndPoint(serverIp, serverPort);
8 socketClient.Connect(remoteIep);
9 toolStripStatusLabel1.Text = "与远程计算机" + remoteIp + ":" + remotePort + "建立连接!";
10
11 byte[] byteMessage = Encoding.Default.GetBytes(message);
12 socketClient.Send(byteMessage);
13
14 IPHostEntry host = Dns.GetHostEntry(GetServerIP());
15 string HostName = host.HostName;
16
17 //发送信息
18 string time1 = DateTime.Now.ToString();
19 listBox1.Items.Add(GetServerIP().ToString() + "(" + HostName + ") " + time1);
20 listBox1.Items.Add(message);
21
22 socketClient.Shutdown(SocketShutdown.Both);
23 socketClient.Close();
IPEndPoint从这个单词的意思就可以看出是一个远端的地址信息,Connect方法根据这个地址建立链接,然后调用Send方法向远端发送信息,发送完信息之后要使用Shutdown指向当前Socket是否接受发送消息,下面列出SocketShutdown的枚举值:
值 |
描述 |
---|---|
Send |
禁用此 Socket 上的发送。 |
Receive |
禁用此 Socket 上的接收。 |
Both |
同时禁用此 Socket 上的发送和接收。 |
Shutdown在msdn上解释是这样的:如果当前使用的是面向连接的Socket,则必须先调用 Shutdown 方法,然后才能关闭Socket。这可以确保在已连接的套接字关闭之前,已发送和接收该套接字上的所有数据。Shutdown也是关闭的意思,其实关于Shutdown和Close我在网上找了很多资料,关于Shutdown解释的云里雾里,不是很明白,我这样理解不知道对不对,上面打电话的例子,按号码打通电话说完话按下挂机键,Shutdown的意思这样,确保信息已经发送。
监听代码:
1 socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
2
3 IPAddress ServerIp = GetServerIP();
4 IPEndPoint iep = new IPEndPoint(ServerIp, port);
5 socketServer.Bind(iep);
6
7 while (true)
8 {
9 try
10 {
11 socketServer.Listen(5);
12 allDone.Reset();
13 socketServer.BeginAccept(new AsyncCallback(AcceptCallback), socketServer);
14 allDone.WaitOne();
15 }
16 catch (SocketException ex)
17 {
18 toolStripStatusLabel1.Text += ex.ToString();
19 }
20 }
Bind与本机绑定开通这个“号码”以方便别人可以打进来,Listen(5)5的意思是最大的监听数,BeginAccept的意思是开始一个异步操作来接受一个传入的连接尝试,以异步方式接受连接将使您能够在单独的执行线程中发送和接收数据,回调方法使用EndAccept,并返回新的Socket对象。
1 //异步连接回调函数
2 public void AcceptCallback(IAsyncResult ar)
3 {
4 Socket listener = (Socket)ar.AsyncState;
5 Socket client = listener.EndAccept(ar);
6 allDone.Set();
7 StateObject state = new StateObject();
8 state.workSocket = client;
9 client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state);
10 }
11
12 //异步接收回调函数
13 public void readCallback(IAsyncResult ar)
14 {
15 StateObject state = (StateObject)ar.AsyncState;
16 Socket handler = state.workSocket;
17 int bytesRead = handler.EndReceive(ar);
18 if (bytesRead > 0)
19 {
20 string strmsg = Encoding.Default.GetString(state.buffer, 0, bytesRead);
21
22 //远端信息
23 EndPoint tempRemoteEP = handler.RemoteEndPoint;
24 IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP;
25 IPHostEntry host = Dns.GetHostByAddress(tempRemoteIP.Address);
26 string HostName = host.HostName;
27
28 string ip = tempRemoteIP.Address.ToString() + "(" + HostName + ") " + DateTime.Now.ToString();
29 if (listBox1.InvokeRequired)
30 {
31 MyDelegate md;
32 md = new MyDelegate(ChangeText);
33 listBox1.Invoke(md, ip, strmsg);
34 }
35 }
36 }
listener.EndAccept(ar)和handler.EndReceive(ar)取回远端Socket对象,这边注意下获取IPHostEntry对象并不是用GetHostEntry方法,而是GetHostByAddress方法,使用GetHostEntry方法会产生异常,异步调用传输对象StateObject:
1 //异步传递的状态对象
2 public class StateObject
3 {
4 public Socket workSocket = null;
5 public const int BufferSize = 1024;
6 public byte[] buffer = new byte[BufferSize];
7 }
运行截图:
完整代码:
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.Windows.Forms;
9
10 using System.Threading;
11 using System.Net;
12 using System.Net.Sockets;
13
14 namespace ClientSocket
15 {
16 public partial class Form1 : Form
17 {
18 Socket socketClient;
19 Thread mythread;//创建线程
20 Socket socketServer;
21 int port = 8080;//定义侦听端口号
22 public static ManualResetEvent allDone = new ManualResetEvent(false);
23 public delegate void MyDelegate(string ip,string message);
24
25 public Form1()
26 {
27 InitializeComponent();
28 }
29 private void Form1_Load(object sender, EventArgs e)
30 {
31 mythread = new Thread(new ThreadStart(BeginListen));
32 mythread.Start();
33
34 txtRemoteIP.Text = GetServerIP().ToString();
35 }
36
37 #region server
38 //获取本机IP地址
39 public static IPAddress GetServerIP()
40 {
41 IPHostEntry ieh = Dns.GetHostEntry(Dns.GetHostName());
42 foreach (IPAddress item in ieh.AddressList)
43 {
44 if (item.ToString().IndexOf("192.168.0.")>=0)
45 {
46 return item;
47 }
48 }
49 return null;
50 }
51
52 //异步传递的状态对象
53 public class StateObject
54 {
55 public Socket workSocket = null;
56 public const int BufferSize = 1024;
57 public byte[] buffer = new byte[BufferSize];
58 }
59
60 //监听
61 private void BeginListen()
62 {
63 socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
64
65 IPAddress ServerIp = GetServerIP();
66 IPEndPoint iep = new IPEndPoint(ServerIp, port);
67 socketServer.Bind(iep);
68
69 while (true)
70 {
71 try
72 {
73 socketServer.Listen(5);
74 allDone.Reset();
75 socketServer.BeginAccept(new AsyncCallback(AcceptCallback), socketServer);
76 allDone.WaitOne();
77 }
78 catch (SocketException ex)
79 {
80 toolStripStatusLabel1.Text += ex.ToString();
81 }
82 }
83 }
84
85 //异步连接回调函数
86 public void AcceptCallback(IAsyncResult ar)
87 {
88 Socket listener = (Socket)ar.AsyncState;
89 Socket client = listener.EndAccept(ar);
90 allDone.Set();
91 StateObject state = new StateObject();
92 state.workSocket = client;
93 client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state);
94 }
95
96 //异步接收回调函数
97 public void readCallback(IAsyncResult ar)
98 {
99 StateObject state = (StateObject)ar.AsyncState;
100 Socket handler = state.workSocket;
101 int bytesRead = handler.EndReceive(ar);
102 if (bytesRead > 0)
103 {
104 string strmsg = Encoding.Default.GetString(state.buffer, 0, bytesRead);
105
106 //远端信息
107 EndPoint tempRemoteEP = handler.RemoteEndPoint;
108 IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP;
109 IPHostEntry host = Dns.GetHostByAddress(tempRemoteIP.Address);
110 string HostName = host.HostName;
111
112 string ip = tempRemoteIP.Address.ToString() + "(" + HostName + ") " + DateTime.Now.ToString();
113 if (listBox1.InvokeRequired)
114 {
115 MyDelegate md;
116 md = new MyDelegate(ChangeText);
117 listBox1.Invoke(md, ip, strmsg);
118 }
119 }
120 }
121
122 public void ChangeText(string ip,string message)
123 {
124 listBox1.Items.Add(ip);
125 listBox1.Items.Add(message);
126 }
127
128 #endregion
129
130 #region client
131 //发送信息
132 private void btn_Send_Click(object sender, EventArgs e)
133 {
134 try
135 {
136 string message = txtMsg.Text.Trim();
137 socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
138 string remoteIp = this.txtRemoteIP.Text;
139 string remotePort = this.txtRemotePort.Text;
140 int serverPort = Convert.ToInt32(remotePort);
141 IPAddress serverIp = IPAddress.Parse(remoteIp);
142 IPEndPoint remoteIep = new IPEndPoint(serverIp, serverPort);
143 socketClient.Connect(remoteIep);
144 toolStripStatusLabel1.Text = "与远程计算机" + remoteIp + ":" + remotePort + "建立连接!";
145
146 byte[] byteMessage = Encoding.Default.GetBytes(message);
147 socketClient.Send(byteMessage);
148
149 IPHostEntry host = Dns.GetHostEntry(GetServerIP());
150 string HostName = host.HostName;
151
152 //发送信息
153 string time1 = DateTime.Now.ToString();
154 listBox1.Items.Add(GetServerIP().ToString() + "(" + HostName + ") " + time1);
155 listBox1.Items.Add(message);
156
157 socketClient.Shutdown(SocketShutdown.Both);
158 socketClient.Close();
159 }
160 catch
161 {
162 toolStripStatusLabel1.Text = "无法连接到目标计算机!";
163 return;
164 }
165 }
166
167 private void btnClose_Click(object sender, EventArgs e)
168 {
169 Application.Exit();
170 }
171 #endregion
172 }
173 }
程序下载:Socket点对点通信.rar
C# Winform Socket点对点通信的更多相关文章
- 小菜学习Winform(三)Socket点对点通信
前言 Socket的英文原义是“孔”或“插座”,其实在网络编程中Socket就是这个意思,就像我们打电话,要首先知道对方的手机号一样,这个手机号就相当于一个Socket号.一个插座,在网络编程中就是i ...
- winform socket编程之TCPListener
运行结果: 服务端代码 using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...
- 【转】Winform Socket通信
Socket相关概念[端口] 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应 ...
- Winform Socket通信
Socket相关概念[端口] 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应 ...
- 小菜学习编程-Winform系列(初学者)
前言 记得上次写<小菜的程序员道路(二)>,这篇文章的时候说过,要把工作以来整理的编程知识分享给大家,因为这半年来的工作实在是忙,现在也在忙着公司产品上线,但是答应的一定要实现,大家看我上 ...
- 初学c# -- 学习笔记 小结
学了到了好些东西, 做了一些练习. 一.C# winform Socket 1.程序主要部分只是用了 Panel.Picturebox.Label.RicheditBox四个组件,滚动条.编辑框什么的 ...
- .Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~
原文:.Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~ 目前的企业级开发比较流行的是Web2.0技术,但是由于Web技术基于请求--响应的交互模式 ...
- 简单的Socket通信(简单的在线聊天)---winform
注:本博客适合刚开始学习winform程序的初学者,大牛请绕道(跪求大牛指导文中不足) .....10w字废话自动省略,直接开始正题. 首先从最基本的建立winform开始(本项目用的Vs2017) ...
- 基于.net C# Socket WinForm MQTT 客户端开发
1.什么是MQTT? MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的&quo ...
- C#版 Winform界面 Socket编程 Client客户端
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
随机推荐
- 在Vue中使用Canvas绘制背景
好家伙, 在vue中使用canvas绘制与在html中使用canvas绘制大致相同, 但又有所区别 法一(无图片资源): vue中canvas的使用 - 掘金 (juejin.cn) 找到canca ...
- 【Azure Redis 缓存】Azure Redis Cluster 在增加分片数时失败分析
问题描述 Azure Redis Cluster 在增加分片数时失败,错误消息为: ResponseBody: { "error": { "details": ...
- PostgreSql一个月学习计划
1.背景 国内使用数据库最多的莫过于mysql,大部分程序员第一次接触数据库就是mysql.(毕竟免费的 = =!)但近年来,有一些黑马出现(如下图),其中表现最突出的莫过于PostgreSQL.特规 ...
- java 携带session 前台传递cookie 跨域解决方案 vue + java
前台 axios 设置 withCredentials: true 后台设置 跨域 header("Access-Control-Allow-Origin","源地址&q ...
- roadmap - json格式的 思维导图
roadmap - json格式的 思维导图 前端路线图 http://www.bitcountrys.com/frontend.html https://gitee.com/ironman1987/ ...
- UDP、IMCP、ARP协议通过netmap解析的实现。
上一篇文章我们讲了一个异步的线程池大概需要如何去实现,现在的话,我们如何来解析一个UDP的包. 环境的搭配 这个环境的问题困扰了很久,这个netmap已经不再更新了,支持Ubuntu16.04-Ubu ...
- 自我总结的git的使用
git是什么 git是一个分布式版本控制工具,github是代码托管平台. git有什么用 保存文件的所有修改记录 使用版本号进行区分 随时可浏览历史版本记录 可还原到历史指定版本 对比不同版本的文件 ...
- 逆向通达信Level-2 续九 (无帐号打开itrend研究版)
此itrend研究版的版本比较旧. 本篇演示三图,用例进程同为0x4970. 1. itrend不支持脱机,游客登陆.没有帐号不能打开.现在以无帐号打开. 2. itrend支持高清,当打开主界面就会 ...
- 记一次kafka无法生产发送消息排查经历
参考,欢迎点击原文:https://stackoverflow.com/questions/37902167/kafka-error-while-fetching-metadata-with-corr ...
- Tomcat异常之 Exception loading sessions from persistent storage解决方案
启动项目时报以下异常 严重: Exception loading sessions from persistent storage java.io.EOFException 遇到上述异常,删除Tomc ...