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 ...
随机推荐
- picgo如何设置又拍云图床
1. 打开又拍云官网.正常注册,并且实名认证. 2. 选择产品,然后选择云存储,激活后进入控制台. 3. 创建云存储服务.注意服务名称.后续会用到 4. 新建一个操作员,并且给权限全部打勾. 添加好操 ...
- 前端面试题(四)—— 事件委托(Event Delegation)
一.什么是事件委托 事件委托(Event Delegation)是一种常用的技术. 它利用事件冒泡的特性,在父元素上监听事件,而不是在子元素上直接添加事件监听器. 通过在父元素上捕获事件,然后根据事件 ...
- 第一百零九篇:基本数据类型(String类型)
好家伙, 本篇内容为<JS高级程序设计>第三章学习笔记 1.String类型 字符串类型是最常用的几个基本类型之一 字符串可以使用双引号,单引号以及反引号(键盘左Tab上面那个)标示 ...
- C++的智能指针
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问题 ,指针指针需要的是浅拷贝,并且需要处理资源释放问题 ...
- 小程序开发:接入腾讯云的人像动漫化api接口
接口如下: 图片的传参方式有两种,一种是传图片的base64,一种是图片url: 我打算免费版使用base64,如果付费用户支持永久存储历史的图片记录(图片存储到腾讯云对象存储中). 前端框架我用的u ...
- 十五: InnoDB的存储结构
InnoDB的存储结构 1.数据库的存储结构:页 索引结构给我们提供了高效的索引方式,不过索引|信息以及数据记录都是保存在文件上的,确切说是存储在页结构中.另一方面,索引是在存储引擎中实现的,MySQ ...
- Java 设计模式----单例模式--饿汉式
1 package com.bytezreo.singleton; 2 3 /** 4 * 5 * @Description 单例设计模式 例子-----饿汉式 6 * @author Bytezer ...
- MacOS安装gRPC C++
从源码安装gRPC C++ 环境准备 $ [sudo] xcode-select --install $ brew install autoconf automake libtool shtool $ ...
- 感慨 vscode 支持win7最后一个版本 1.70.3 于2022年7月发布
为什么 家里电脑一直是win7,也懒的升级,nodejs也不能用最新的,没想到vscode也停产了 https://code.visualstudio.com/updates/v1_70 后记 别用u ...
- vscode ctrl + 鼠标左键 点击 不进入组件,弹出一个框再点才进入的问题 目录名和vue文件名 开头不能大写 需从起生效
vscode ctrl + 鼠标左键 点击 不进入组件,弹出一个框再点才进入的问题 目录名和vue文件名 开头不能大写 需从起生效 就是这个,很讨厌,原来是开头不能大写字母的问题造成的. 小写字母就没 ...