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的主要内容,如果未能解决你的问题,请参考以下文章