c#_TcpListener&TcpClient
Posted x1angzeeD.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#_TcpListener&TcpClient相关的知识,希望对你有一定的参考价值。
本篇博客示例适用于上位机与机器人之间的通讯
① 首先先介绍一下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);
else
MessageBox.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);
else
MessageBox.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 notification
Buffer.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#_TcpListener&TcpClient的主要内容,如果未能解决你的问题,请参考以下文章