前言

  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点对点通信的更多相关文章

  1. 小菜学习Winform(三)Socket点对点通信

    前言 Socket的英文原义是“孔”或“插座”,其实在网络编程中Socket就是这个意思,就像我们打电话,要首先知道对方的手机号一样,这个手机号就相当于一个Socket号.一个插座,在网络编程中就是i ...

  2. winform socket编程之TCPListener

    运行结果: 服务端代码 using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

  3. 【转】Winform Socket通信

    Socket相关概念[端口] 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应 ...

  4. Winform Socket通信

    Socket相关概念[端口] 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应 ...

  5. 小菜学习编程-Winform系列(初学者)

    前言 记得上次写<小菜的程序员道路(二)>,这篇文章的时候说过,要把工作以来整理的编程知识分享给大家,因为这半年来的工作实在是忙,现在也在忙着公司产品上线,但是答应的一定要实现,大家看我上 ...

  6. 初学c# -- 学习笔记 小结

    学了到了好些东西, 做了一些练习. 一.C# winform Socket 1.程序主要部分只是用了 Panel.Picturebox.Label.RicheditBox四个组件,滚动条.编辑框什么的 ...

  7. .Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~

    原文:.Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~ 目前的企业级开发比较流行的是Web2.0技术,但是由于Web技术基于请求--响应的交互模式 ...

  8. 简单的Socket通信(简单的在线聊天)---winform

    注:本博客适合刚开始学习winform程序的初学者,大牛请绕道(跪求大牛指导文中不足) .....10w字废话自动省略,直接开始正题. 首先从最基本的建立winform开始(本项目用的Vs2017) ...

  9. 基于.net C# Socket WinForm MQTT 客户端开发

    1.什么是MQTT? MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的&quo ...

  10. C#版 Winform界面 Socket编程 Client客户端

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

随机推荐

  1. 【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数

    问题描述 在Azure App Service for Windows的环境中,部署.NET应用,其中使用了 SAP NetWeaver RFC函数 (需要加载 sapnwrfc.dll).详细的错误 ...

  2. 【Azure 事件中心】Flink消费Event Hub中事件, 使用Azure默认示例代码,始终获取新产生的事件,如何消费旧事件呢?

    问题描述 根据Azure Event Hub示例文档,[将 Apache Flink 与适用于 Apache Kafka 的 Azure 事件中心配合使用],配置好 consumer.config 文 ...

  3. 【Azure 应用服务】如何定期自动重启 Azure App Service Plan(应用服务计划)

    问题描述 如何定期自动重启 Azure App Service Plan(应用服务计划)? 因一个App Service Plan 下包含多个应用服务,如果能统一通过应用服务计划来重启所有的应用,则有 ...

  4. 【Azure Redis 缓存】Azure Redis加入VNET后,在另一个区域(如中国东部二区)的VNET无法访问Redis服务(注:两个VNET已经结对,相互之间可以互ping)

    问题描述 为了保护Redis资源,把它与VNET集成后,实现只能通过VNET内网访问.在东二的区域中部署两个Redis服务后,发现一个奇怪的现象:东1区中的VM资源通过全局对等互联(Peering)实 ...

  5. 答应我,在vue中不要滥用watch好吗?

    前言 上周五晚上8点,开开心心的等着产品验收完毕后就可以顺利上线.结果产品突然找到我说要加需求,并且维护这一块业务的同事已经下班走了,所以只有我来做.虽然内心一万头草泥马在狂奔,但是嘴里还是一口答应没 ...

  6. goland快键键防忘

    环境: debian下的goland 2018实测: 鼠标button2 == 鼠标中键 光标移动: 跳转光标到刚才的位置: ctrl+win+alt+左/右 按词左右移动光标: ctrl + 左/右 ...

  7. 使用 Docker 部署 Fiora 在线聊天室平台

    一.Fiora 介绍 Fiora 简介 Fiora 是一款开源免费的在线聊天系统. GitHub:https://github.com/yinxin630/fiora Fiora 功能 注册账号并登录 ...

  8. vscode ctrl + d 删除当前行 更改快捷键

    vscode 删除当前行 更改快捷键

  9. PlacementList must be sorted by first 8 bits of display_id 问题

    问题暂未解决 [37484:0811/103448.115:ERROR:display_layout.cc(551)] PlacementList must be sorted by first 8 ...

  10. C++学习笔记之进阶编程

    目录 进阶编程 STL(Standard Template Library) 容器(container) 仿函数(functor) 算法(algorithm) transform 查找 全排列 迭代器 ...