本篇博客示例适用于上位机与机器人之间的通讯

①  首先先介绍一下TcpClient和TcpListener:

1、TcpClient 类

为 TCP 网络服务提供客户端连接。
TcpClient 类提供了一些简单的方法,用于在同步阻塞模式下通过网络来连接、发送和接收流数据。

为使 TcpClient 连接并交换数据,使用 TCP ProtocolType 创建的 TcpListener 或 Socket 必须侦听是否有传入的连接请求。可以使用下面两种方法之一连接到该侦听器:

创建一个 TcpClient,并调用三个可用的 Connect 方法之一。
使用远程主机的主机名和端口号创建 TcpClient。此构造函数将自动尝试一个连接。
 
要发送和接收数据,请使用 GetStream 方法来获取一个 NetworkStream。调用 NetworkStream 的 Write 和 Read 方法与远程主机之间发送和接收数据。使用 Close 方法释放与 TcpClient 关联的所有资源。

2、TcpListener 类

从 TCP 网络客户端侦听连接。
TcpListener 类提供一些简单方法,用于在阻塞同步模式下侦听和接受传入连接请求。可使用 TcpClient 或 Socket 来连接 TcpListener。可使用 IPEndPoint、本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener。可以将本地 IP 地址指定为 Any,将本地端口号指定为 0(如果希望基础服务提供程序为您分配这些值)。如果选择这样做,可使用 LocalEndpoint 来标识已指定的信息。

Start 方法用来开始侦听传入的连接请求。Start 将对传入连接进行排队,直至您调用 Stop 方法或它已经完成 MaxConnections 排队为止。可使用 AcceptSocket 或 AcceptTcpClient 从传入连接请求队列提取连接。这两种方法将阻塞。如果要避免阻塞,可首先使用 Pending 方法来确定队列中是否有可用的连接请求。

调用 Stop 方法来关闭 TcpListener。

注意    Stop 方法不会关闭任何已接受的连接。需要用户负责分别关闭这些连接。

②  完整代码示例:

代码结构简介:1、面向接口编程​    2、单例模式​​​​​​    3、异步

public interface IAsyncTcpSever
{bool IsRunning { get; }List<Object> Clients { get; }  //连入的客户端列表IPAddress Address { get; }int Port { get; }void StartSever();void StartSever(int backlog);void StopSever();void Send(TCPClientState state, string msg);  //发消息选择指定的客户端在客户端列表中选择
}public class x1angzzzAsyncTcpSever : IAsyncTcpSever
{#region  全局变量
private TcpListener _listener;  // 服务器使用的异步TcpListener
private List<Object> _clients;  // 客户端列表
private Encoding _encoding;     // 编码格式
#endregion#region  属性
public bool IsRunning { get; private set; }  // 服务器是否正在运行
public List<Object> Clients { get { return _clients; } }  // 客户端
public IPAddress Address { get; private set; }  // IP地址
public int Port { get; private set; }           // 端口号
#endregion#region 构造函数
private static x1angzzzAsyncTcpSever _instance;
private static object Singleton_Lock = new object();
public static x1angzzzAsyncTcpSever GetInstance(int listenPort, Encoding encoding)
{if (_instance == null){lock (Singleton_Lock){if (_instance == null)_instance = new x1angzzzAsyncTcpSever(listenPort, encoding);}}return _instance;
}
public static x1angzzzAsyncTcpSever GetInstance(IPAddress localIPAddress, int listenPort, Encoding encoding)
{if (_instance == null){lock (Singleton_Lock){if (_instance == null)_instance = new x1angzzzAsyncTcpSever(localIPAddress, listenPort, encoding);}}return _instance;
}
private x1angzzzAsyncTcpSever(int listenPort, Encoding encoding)     // 任意IP均可: this(IPAddress.Any, listenPort, encoding) { }
private x1angzzzAsyncTcpSever(IPAddress localIPAddress, int listenPort, Encoding encoding)  // 常规IP+Port+编码格式
{Address = localIPAddress;Port = listenPort;this._encoding = encoding;_clients = new List<Object>();_listener = new TcpListener(Address, Port);_listener.AllowNatTraversal(true);
}
#endregion#region 开启/停止/发送/接受消息的事件处理函数
public void StartSever()
{if (!IsRunning){IsRunning = true;_listener.Start();_listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), _listener);}elseMessageBox.Show("服务端正在运行!", "Infromation", MessageBoxButtons.OK,MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
public void StartSever(int backlog)  // 服务器所允许的挂起连接序列的最大长度
{if (!IsRunning){IsRunning = true;_listener.Start(backlog);_listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), _listener);}elseMessageBox.Show("服务端正在运行!", "Infromation", MessageBoxButtons.OK,MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
public void StopSever()
{if (IsRunning){var dr = MessageBox.Show("是否主动关闭客户端?", "Warning",           MessageBoxButtons.OKCancel,MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);if (dr == DialogResult.Cancel) return;IsRunning = false;_listener.Stop();lock (_clients){CloseAllClient();  // 关闭所有客户端连接_listener.Stop();}
}
GC.SuppressFinalize(this);在对象创建的时候CLR会对带有终结器的对象进行标记(这使创建成本变高)}
public void Send(TCPClientState state, string msg)
{byte[] data = System.Text.Encoding.Default.GetBytes(msg);Send(state.TcpClient, data);
}
public void ReceivedRecallMethod(string msg)
{//接收消息之后的事件处理函数
}
#endregion#region 内部函数
private void HandleDataReceived(IAsyncResult ar)  // 数据接受回调函数
{if (IsRunning){TCPClientState state = (TCPClientState)ar.AsyncState;NetworkStream stream = state.NetworkStream;int recv = 0;try { recv = stream.EndRead(ar); }catch { recv = 0; }if (recv == 0){lock (_clients)  // 连接已经被关闭{_clients.Remove(state);return;}}byte[] buff = new byte[recv];  // received byte and trigger event notificationBuffer.BlockCopy(state.Buffer, 0, buff, 0, recv);string str = string.Empty;if (recv != 0){str = _encoding.GetString(buff, 0, recv);Action<string> action = ReceivedRecallMethod;action.Invoke(str);}// continue listening for tcp datagram packets   stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);}
}
private void CloseAllClient()
{try{foreach (TCPClientState client in _clients) //这里好像报了一个无关紧要的错,所以我加了个try,catch{if (client != null){client.Close();_clients.Remove(client);}}}catch { }_clients.Clear();
}
private void Send(TcpClient client, byte[] data)
{if (!IsRunning){var dr = MessageBox.Show("服务端尚未启用!是否启用?", "Warning", MessageBoxButtons.OKCancel,MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);if (dr == DialogResult.OK){//这里调用StartSever方法,怎样写看你实际应用}return;}if (client == null){MessageBox.Show("未检测到客户端!", "Warning", MessageBoxButtons.OK,MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);return;}if (data == null){MessageBox.Show("发送内容不可为空!", "Error", MessageBoxButtons.OK,MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);return;}client.GetStream().BeginWrite(data, 0, data.Length,(IAsyncResult ar) => { ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); }, client);
}
#endregion }public class TCPClientState
{public TcpClient TcpClient { get; private set; }public byte[] Buffer { get; private set; }public NetworkStream NetworkStream{get { return TcpClient.GetStream(); }}public TCPClientState(TcpClient tcpClient, byte[] buffer){if (tcpClient == null)throw new ArgumentNullException("tcpClient");if (buffer == null)throw new ArgumentNullException("buffer");this.TcpClient = tcpClient;this.Buffer = buffer;}public void Close(){//关闭数据的接受和发送TcpClient.Close();Buffer = null;}
}

c#_TcpListenerTcpClient相关推荐

最新文章

  1. C++宏assert()
  2. 自动刷新某个指定网页
  3. 影响声音定位的几个因素
  4. MySQL 架构组成—存储引擎
  5. Java 基本功之(三)Java 核心技术
  6. spark集群测试小案例
  7. 一台机子上运行使用不同Java版本的多个tomcat
  8. android gpu linux,Arm发布针对Mali GPU的Android Linux Vulkan用户空间驱动(HiKey 960,Firefly-RK3288主板)...
  9. OpenShift 4 之通过Dockerfile部署容器应用
  10. 【前端】【labelme】labelme 保存 imageData 的 base64编码机制 —— python 源码探究与 js 实现
  11. win10安装pycocotools遇到的问题
  12. $(document).ready()和onload区别
  13. 微信小程序开发--【初体验】(一)
  14. 驱动研究日记-内核同步
  15. jquery楼层效果
  16. 地址解析:使用Google API将地址文本转换为经纬度
  17. CodeForces 1009D Relatively Prime Graph 贪心+枚举
  18. 【数据分析与挖掘(二)】面试题汇总(附答案)
  19. CVPR 2019 | 「识面知心」——基于自监督学习的微表情特征表达
  20. JWT的数据格式详解

热门文章

  1. Matlab如何从dat或者txt文件读入数据
  2. oracle pl sql注意问题,Oracle PL/SQL编写PL/SQL代码的注意事项
  3. 键盘输入_键盘输入技巧
  4. pip在windows下安装配件/宏包
  5. 上线。我都惊呆了。。。
  6. Python_模块介绍
  7. 几何画板表现两集合的差集的教程
  8. !--处理:借款冲销不自动冲减预算--
  9. pthread_create()之前的属性设置
  10. window下启动nexus出错Unsupported major.minor version 51