TCP Socket服务端客户端(二)
本文服务端客户端封装代码转自https://blog.csdn.net/zhujunxxxxx/article/details/44258719,并作了简单的修改。
1)服务端
此类主要处理服务端相关消息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace TcpSocketServer
{
/// <summary>
/// Socket异步TCP服务器
/// 建议把close方法改为私有,即服务端不主动关闭连接
/// 客户端主动关闭连接后,其receive仍在
/// </summary>
public class TCPServerAsync : IDisposable
{
#region Fields
{
/// <summary>
/// Socket异步TCP服务器
/// 建议把close方法改为私有,即服务端不主动关闭连接
/// 客户端主动关闭连接后,其receive仍在
/// </summary>
public class TCPServerAsync : IDisposable
{
#region Fields
private int _maxClient;// 服务器程序允许的最大客户端连接数
private int _clientCount;// 当前的连接的客户端数
private Socket _serverSock;// 服务器使用的异步socket
private List<ClientInfo> _clients;// 客户端会话列表
private Socket _serverSock;// 服务器使用的异步socket
private List<ClientInfo> _clients;// 客户端会话列表
private bool disposed = false;//内存释放
#endregion
#region Properties
public bool IsRunning { get; private set; }// 服务器是否正在运行
public IPAddress Address { get; private set; }// 监听的IP地址
public int Port { get; private set; }// 监听的端口
public Encoding Encoding { get; set; }// 通信使用的编码
public Encoding Encoding { get; set; }// 通信使用的编码
#endregion
#region 构造函数
#region 构造函数
/// <summary>
/// 异步Socket TCP服务器
/// </summary>
public TCPServerAsync(int listenPort)
: this(IPAddress.Any, listenPort, 1024)
{
}
/// 异步Socket TCP服务器
/// </summary>
public TCPServerAsync(int listenPort)
: this(IPAddress.Any, listenPort, 1024)
{
}
public TCPServerAsync(IPEndPoint localEP)
: this(localEP.Address, localEP.Port, 1024)
{
}
: this(localEP.Address, localEP.Port, 1024)
{
}
public TCPServerAsync(IPAddress localIPAddress, int listenPort, int maxClient)
{
this.Address = localIPAddress;
this.Port = listenPort;
this.Encoding = Encoding.Default;
{
this.Address = localIPAddress;
this.Port = listenPort;
this.Encoding = Encoding.Default;
_maxClient = maxClient;
_clients = new List<ClientInfo>();
_serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
_clients = new List<ClientInfo>();
_serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
#endregion
#region Method
/// <summary>
/// 启动服务器
/// </summary>
public void Start()
{
if (!IsRunning)
{
IsRunning = true;
_serverSock.Bind(new IPEndPoint(this.Address, this.Port));
_serverSock.Listen(1024);
_serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
}
}
/// 启动服务器
/// </summary>
public void Start()
{
if (!IsRunning)
{
IsRunning = true;
_serverSock.Bind(new IPEndPoint(this.Address, this.Port));
_serverSock.Listen(1024);
_serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
}
}
/// <summary>
/// 启动服务器
/// </summary>
/// <param name="backlog">
/// 服务器所允许的挂起连接序列的最大长度
/// </param>
public void Start(int backlog)
{
if (!IsRunning)
{
IsRunning = true;
_serverSock.Bind(new IPEndPoint(this.Address, this.Port));
_serverSock.Listen(backlog);
_serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
}
}
/// 启动服务器
/// </summary>
/// <param name="backlog">
/// 服务器所允许的挂起连接序列的最大长度
/// </param>
public void Start(int backlog)
{
if (!IsRunning)
{
IsRunning = true;
_serverSock.Bind(new IPEndPoint(this.Address, this.Port));
_serverSock.Listen(backlog);
_serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
}
}
/// <summary>
/// 停止服务器
/// </summary>
public void Stop()
{
if (IsRunning)
{
IsRunning = false;
_serverSock.Close();
//TODO 关闭对所有客户端的连接
CloseAllClient();
}
}
/// 停止服务器
/// </summary>
public void Stop()
{
if (IsRunning)
{
IsRunning = false;
_serverSock.Close();
//TODO 关闭对所有客户端的连接
CloseAllClient();
}
}
#region Close
/// <summary>
/// 关闭一个与客户端之间的会话
/// </summary>
/// <param name="state">需要关闭的客户端会话对象</param>
public void Close(ClientInfo state)
{
if (state != null)
{
//state.Datagram = null;
state.RecvDataBuffer = null;
/// <summary>
/// 关闭一个与客户端之间的会话
/// </summary>
/// <param name="state">需要关闭的客户端会话对象</param>
public void Close(ClientInfo state)
{
if (state != null)
{
//state.Datagram = null;
state.RecvDataBuffer = null;
_clients.Remove(state);
_clientCount--;
//TODO 触发关闭事件
state.Close();
}
}
/// <summary>
/// 关闭所有的客户端会话,与所有的客户端连接会断开
/// </summary>
public void CloseAllClient()
{
foreach (ClientInfo client in _clients)
{
Close(client);
}
_clientCount = 0;
_clients.Clear();
}
#endregion
_clientCount--;
//TODO 触发关闭事件
state.Close();
}
}
/// <summary>
/// 关闭所有的客户端会话,与所有的客户端连接会断开
/// </summary>
public void CloseAllClient()
{
foreach (ClientInfo client in _clients)
{
Close(client);
}
_clientCount = 0;
_clients.Clear();
}
#endregion
/// <summary>
/// 处理客户端连接
/// </summary>
/// <param name="ar"></param>
private void HandleAcceptConnected(IAsyncResult ar)
{
if (IsRunning)
{
Socket server = (Socket)ar.AsyncState;
Socket client = server.EndAccept(ar);
/// 处理客户端连接
/// </summary>
/// <param name="ar"></param>
private void HandleAcceptConnected(IAsyncResult ar)
{
if (IsRunning)
{
Socket server = (Socket)ar.AsyncState;
Socket client = server.EndAccept(ar);
//检查是否达到最大的允许的客户端数目
if (_clientCount >= _maxClient)
{
//C-TODO 触发事件
RaiseOtherException(null);
}
else
{
ClientInfo state = new ClientInfo(client);
lock (_clients)
{
_clients.Add(state);
_clientCount++;
RaiseClientConnected(state); //触发客户端连接事件
}
state.RecvDataBuffer = new byte[client.ReceiveBufferSize];
//开始接受来自该客户端的数据
client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
new AsyncCallback(HandleDataReceived), state);
}
//接受下一个请求
server.BeginAccept(new AsyncCallback(HandleAcceptConnected), ar.AsyncState);
}
}
/// <summary>
/// 处理客户端数据
/// </summary>
/// <param name="ar"></param>
private void HandleDataReceived(IAsyncResult ar)
{
if (IsRunning)
{
ClientInfo state = (ClientInfo)ar.AsyncState;
Socket client = state.ClientSocket;
try
{
//异步接收,当客户端退出的时候会再次执行EndReceive
int recv = client.EndReceive(ar);
if (_clientCount >= _maxClient)
{
//C-TODO 触发事件
RaiseOtherException(null);
}
else
{
ClientInfo state = new ClientInfo(client);
lock (_clients)
{
_clients.Add(state);
_clientCount++;
RaiseClientConnected(state); //触发客户端连接事件
}
state.RecvDataBuffer = new byte[client.ReceiveBufferSize];
//开始接受来自该客户端的数据
client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
new AsyncCallback(HandleDataReceived), state);
}
//接受下一个请求
server.BeginAccept(new AsyncCallback(HandleAcceptConnected), ar.AsyncState);
}
}
/// <summary>
/// 处理客户端数据
/// </summary>
/// <param name="ar"></param>
private void HandleDataReceived(IAsyncResult ar)
{
if (IsRunning)
{
ClientInfo state = (ClientInfo)ar.AsyncState;
Socket client = state.ClientSocket;
try
{
//异步接收,当客户端退出的时候会再次执行EndReceive
int recv = client.EndReceive(ar);
//客户端主动断开连接时(采用close关闭)recv == 0
//所以执行回掉RaiseClientDisconnected,并在回掉函数中关闭连接
//以不在RaiseClientDisconnected回掉中关闭连接为优,即直接调用Close关闭
if (recv == 0)
{
//C- TODO 触发事件 (关闭客户端)
//Close(state);
RaiseClientDisconnected(state);
return;
}
//TODO 处理已经读取的数据 ps:数据在state的RecvDataBuffer中
state._recvdBufferLength = recv;
//C- TODO 触发数据接收事件
RaiseDataReceived(state);
}
catch (SocketException)
{
//C- TODO 异常处理
RaiseNetError(state);
//客户端主动断开连接时(直接关闭程序,而非采用close关闭)引发以尝
//所以执行回掉RaiseClientDisconnected,并在回掉函数中关闭连接
//以不在回掉中关闭连接为优,直接/Close(state)关闭
state._recvdBufferLength = 0;
RaiseClientDisconnected(state);
return;
}
//所以执行回掉RaiseClientDisconnected,并在回掉函数中关闭连接
//以不在RaiseClientDisconnected回掉中关闭连接为优,即直接调用Close关闭
if (recv == 0)
{
//C- TODO 触发事件 (关闭客户端)
//Close(state);
RaiseClientDisconnected(state);
return;
}
//TODO 处理已经读取的数据 ps:数据在state的RecvDataBuffer中
state._recvdBufferLength = recv;
//C- TODO 触发数据接收事件
RaiseDataReceived(state);
}
catch (SocketException)
{
//C- TODO 异常处理
RaiseNetError(state);
//客户端主动断开连接时(直接关闭程序,而非采用close关闭)引发以尝
//所以执行回掉RaiseClientDisconnected,并在回掉函数中关闭连接
//以不在回掉中关闭连接为优,直接/Close(state)关闭
state._recvdBufferLength = 0;
RaiseClientDisconnected(state);
return;
}
//继续接收来自来客户端的数据
//ps: 如果未接收到数据则始终处于挂起状态;
//pss:当收到close消息,server主动关闭连接(212行RaiseDataReceived中进行了关闭)时由于已经关闭连接,所以下述代码会有异常
//后续可在应用只要不是通过客户端发消息主动close就可避免此问题,所以在此加一个异常处理,或者加一个bool变量判断是否断掉
try
{
client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
new AsyncCallback(HandleDataReceived), state);
}
catch{}
}
}
//ps: 如果未接收到数据则始终处于挂起状态;
//pss:当收到close消息,server主动关闭连接(212行RaiseDataReceived中进行了关闭)时由于已经关闭连接,所以下述代码会有异常
//后续可在应用只要不是通过客户端发消息主动close就可避免此问题,所以在此加一个异常处理,或者加一个bool变量判断是否断掉
try
{
client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
new AsyncCallback(HandleDataReceived), state);
}
catch{}
}
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="state">接收数据的客户端会话</param>
/// <param name="data">数据报文</param>
public void Send(ClientInfo state, byte[] data)
{
RaisePrepareSend(state);
Send(state.ClientSocket, data);
}
/// 发送数据
/// </summary>
/// <param name="state">接收数据的客户端会话</param>
/// <param name="data">数据报文</param>
public void Send(ClientInfo state, byte[] data)
{
RaisePrepareSend(state);
Send(state.ClientSocket, data);
}
/// <summary>
/// 异步发送数据至指定的客户端
/// </summary>
/// <param name="client">客户端</param>
/// <param name="data">报文</param>
public void Send(Socket client, byte[] data)
{
if (!IsRunning)
throw new InvalidProgramException("This TCP Scoket server has not been started.");
/// 异步发送数据至指定的客户端
/// </summary>
/// <param name="client">客户端</param>
/// <param name="data">报文</param>
public void Send(Socket client, byte[] data)
{
if (!IsRunning)
throw new InvalidProgramException("This TCP Scoket server has not been started.");
if (client == null)
throw new ArgumentNullException("client");
throw new ArgumentNullException("client");
if (data == null)
throw new ArgumentNullException("data");
client.BeginSend(data, 0, data.Length, SocketFlags.None,
new AsyncCallback(SendDataEnd), client);
}
throw new ArgumentNullException("data");
client.BeginSend(data, 0, data.Length, SocketFlags.None,
new AsyncCallback(SendDataEnd), client);
}
/// <summary>
/// 发送数据完成处理函数
/// </summary>
/// <param name="ar">目标客户端Socket</param>
private void SendDataEnd(IAsyncResult ar)
{
((Socket)ar.AsyncState).EndSend(ar);
RaiseCompletedSend(new TcpSocketServer.ClientInfo((Socket)ar.AsyncState));
}
#endregion
/// 发送数据完成处理函数
/// </summary>
/// <param name="ar">目标客户端Socket</param>
private void SendDataEnd(IAsyncResult ar)
{
((Socket)ar.AsyncState).EndSend(ar);
RaiseCompletedSend(new TcpSocketServer.ClientInfo((Socket)ar.AsyncState));
}
#endregion
#region 事件
#region 客户端连接事件
public event EventHandler<TCPMessageArgs> ClientConnecting;//客户端正在连接事件
public event EventHandler<TCPMessageArgs> ClientConnected; //客户端连接事件
public event EventHandler<TCPMessageArgs> ClientDisconnected;//客户端断开连接
//挂起事件
private void RaiseClientConnecting(ClientInfo state)
{
if(ClientConnecting!=null)
{
ClientConnecting(this, new TCPMessageArgs(state));
}
}
private void RaiseClientConnected(ClientInfo state)
{
if (ClientConnected != null)
{
ClientConnected(this, new TCPMessageArgs(state));
}
}
private void RaiseClientDisconnected(ClientInfo state)
{
if (ClientDisconnected != null)
{
ClientDisconnected(this, new TCPMessageArgs(state));
}
}
#endregion
public event EventHandler<TCPMessageArgs> ClientConnecting;//客户端正在连接事件
public event EventHandler<TCPMessageArgs> ClientConnected; //客户端连接事件
public event EventHandler<TCPMessageArgs> ClientDisconnected;//客户端断开连接
//挂起事件
private void RaiseClientConnecting(ClientInfo state)
{
if(ClientConnecting!=null)
{
ClientConnecting(this, new TCPMessageArgs(state));
}
}
private void RaiseClientConnected(ClientInfo state)
{
if (ClientConnected != null)
{
ClientConnected(this, new TCPMessageArgs(state));
}
}
private void RaiseClientDisconnected(ClientInfo state)
{
if (ClientDisconnected != null)
{
ClientDisconnected(this, new TCPMessageArgs(state));
}
}
#endregion
#region 数据发送事件
public event EventHandler<TCPMessageArgs> PrepareSend;//数据准备发送事件
public event EventHandler<TCPMessageArgs> DataSending;//数据正在发送事件
public event EventHandler<TCPMessageArgs> CompletedSend;//数据发送结束事件
public event EventHandler<TCPMessageArgs> DataReceived;//接受到客户端数据事件
//挂起事件
private void RaisePrepareSend(ClientInfo state)
{
if (PrepareSend != null)
{
PrepareSend(this, new TCPMessageArgs(state));
}
}
private void RaiseDataSending(ClientInfo state)
{
if (PrepareSend != null)
{
DataSending(this, new TCPMessageArgs(state));
}
}
private void RaiseDataReceived(ClientInfo state)
{
if (DataReceived != null)
{
DataReceived(this, new TCPMessageArgs(state));
}
}
private void RaiseCompletedSend(ClientInfo state)
{
if (CompletedSend != null)
{
CompletedSend(this, new TCPMessageArgs(state));
}
}
#endregion
public event EventHandler<TCPMessageArgs> PrepareSend;//数据准备发送事件
public event EventHandler<TCPMessageArgs> DataSending;//数据正在发送事件
public event EventHandler<TCPMessageArgs> CompletedSend;//数据发送结束事件
public event EventHandler<TCPMessageArgs> DataReceived;//接受到客户端数据事件
//挂起事件
private void RaisePrepareSend(ClientInfo state)
{
if (PrepareSend != null)
{
PrepareSend(this, new TCPMessageArgs(state));
}
}
private void RaiseDataSending(ClientInfo state)
{
if (PrepareSend != null)
{
DataSending(this, new TCPMessageArgs(state));
}
}
private void RaiseDataReceived(ClientInfo state)
{
if (DataReceived != null)
{
DataReceived(this, new TCPMessageArgs(state));
}
}
private void RaiseCompletedSend(ClientInfo state)
{
if (CompletedSend != null)
{
CompletedSend(this, new TCPMessageArgs(state));
}
}
#endregion
#region 关闭连接事件
public event EventHandler<TCPMessageArgs> ClientClose;//关闭客户端事件
public event EventHandler<TCPMessageArgs> AllClientsClose;//关闭所有客户端事件
//挂起事件
private void RaiseClientClose(ClientInfo state)
{
if(ClientClose!=null)
{
ClientClose(this, new TcpSocketServer.TCPMessageArgs(state));
}
}
private void RaiseAllClientClose(ClientInfo state)
{
if (AllClientsClose != null)
{
AllClientsClose(this, new TcpSocketServer.TCPMessageArgs(state));
}
}
#endregion
public event EventHandler<TCPMessageArgs> ClientClose;//关闭客户端事件
public event EventHandler<TCPMessageArgs> AllClientsClose;//关闭所有客户端事件
//挂起事件
private void RaiseClientClose(ClientInfo state)
{
if(ClientClose!=null)
{
ClientClose(this, new TcpSocketServer.TCPMessageArgs(state));
}
}
private void RaiseAllClientClose(ClientInfo state)
{
if (AllClientsClose != null)
{
AllClientsClose(this, new TcpSocketServer.TCPMessageArgs(state));
}
}
#endregion
#region 其他事件
public event EventHandler<TCPMessageArgs> NetError;// 网络错误事件
public event EventHandler<TCPMessageArgs> OtherException;//其他异常
//挂起事件
private void RaiseNetError(ClientInfo state)
{
if (OtherException != null)
{
OtherException(this, new TCPMessageArgs(state));
}
}
private void RaiseOtherException(ClientInfo state)
{
RaiseOtherException(state);
}
#endregion
public event EventHandler<TCPMessageArgs> NetError;// 网络错误事件
public event EventHandler<TCPMessageArgs> OtherException;//其他异常
//挂起事件
private void RaiseNetError(ClientInfo state)
{
if (OtherException != null)
{
OtherException(this, new TCPMessageArgs(state));
}
}
private void RaiseOtherException(ClientInfo state)
{
RaiseOtherException(state);
}
#endregion
#endregion
#region 释放
/// <summary>
/// Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release
/// both managed and unmanaged resources; <c>false</c>
/// to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
try
{
Stop();
if (_serverSock != null)
{
_serverSock = null;
}
}
catch (SocketException)
{
//TODO
RaiseOtherException(null);
}
}
disposed = true;
}
}
#endregion
}
}
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release
/// both managed and unmanaged resources; <c>false</c>
/// to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
try
{
Stop();
if (_serverSock != null)
{
_serverSock = null;
}
}
catch (SocketException)
{
//TODO
RaiseOtherException(null);
}
}
disposed = true;
}
}
#endregion
}
}
2)客户端
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace TcpSocketClient { public class TCPClientAsync { #region 字段 private Socket clientSock; //private byte[] recvBuffer; private ClientInfo state; #endregion #region 属性 public IPAddress Address { get; private set; }// 监听的IP地址 public int Port { get; private set; }// 监听的端口 public bool IsConnected { get;private set; } #endregion #region 构造方法 public TCPClientAsync(IPAddress ipAddress,int port) { this.Address = ipAddress; this.Port = port; clientSock=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } public TCPClientAsync(IPEndPoint ipEndPort) :this(ipEndPort.Address,ipEndPort.Port) { } #endregion #region Method public void Connect()//开始连接 { if(!IsConnected) { //clientSock.BeginConnect(Address, Port, new AsyncCallback(HandleConnectAccepted), clientSock); clientSock.BeginConnect(Address, Port, iAsyncResult=> { try { clientSock.EndConnect(iAsyncResult); IsConnected = true; state = new TcpSocketClient.ClientInfo(clientSock); RaiseConnectAccepted(state);//挂起连接事件 } catch { //TODO连接失败 RaiseConnectFailed(); } }, null); } } //private void HandleConnectAccepted(IAsyncResult iAsyncResult) //{ // clientSock.EndConnect(iAsyncResult); // IsConnected = true; //} public void Send(byte[] data) { if (!IsConnected) return; //clientSock.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(HandleDataSend), null); clientSock.BeginSend(data, 0, data.Length, SocketFlags.None, iAsyncResult=> { clientSock.EndSend(iAsyncResult); RaiseDataSend(state); }, null); } public void Receive() { if (!IsConnected) return; state.RecvDataBuffer = new byte[clientSock.ReceiveBufferSize]; clientSock.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None, new AsyncCallback(HandleDataReceive), null); } private void HandleDataReceive(IAsyncResult iAsyncResult) { int recv = 0; try { recv = clientSock.EndReceive(iAsyncResult); if (recv == 0)//客户端主动断开连接时recv=0 { Close(); RaiseServerCloseLink(); return; } state._recvdBufferLength = recv; RaiseDataReceived(state); } catch(Exception ex) { //TODO 信息获取失败 string str = ex.Message; return; } //if (!IsConnected) return; clientSock.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None, new AsyncCallback(HandleDataReceive), null); } //private void HandleDataSend(IAsyncResult iAsyncResult) //{ // clientSock.EndSend(iAsyncResult); //} public void Close() { //关闭数据的接受和发送 clientSock.Shutdown(SocketShutdown.Both); //清理资源 clientSock.Close(); state = null; IsConnected = false; GC.Collect(); } #endregion #region 事件 public event EventHandler<TCPMessageArgs> ConnectAccepted;//连接事件 public event EventHandler<TCPMessageArgs> DataSend;//数据发送事件 public event EventHandler<TCPMessageArgs> DataReceived;//数据发送事件 public event EventHandler<TCPMessageArgs> ErrorException;//错误信息 public event EventHandler<TCPMessageArgs> ServerCloseLink;//服务端关闭连接 public event EventHandler<TCPMessageArgs> ConnectFailed;//连接失败 private void RaiseConnectAccepted(ClientInfo state) { if (ConnectAccepted != null) { ConnectAccepted(this, new TCPMessageArgs(state)); } } private void RaiseDataSend(ClientInfo state) { if (DataSend != null) { DataSend(this, new TcpSocketClient.TCPMessageArgs(state)); } } private void RaiseDataReceived(ClientInfo state) { if(DataReceived!=null) { DataReceived(this, new TcpSocketClient.TCPMessageArgs(state)); } } private void RaiseErrorException() { if(ErrorException!=null) { ErrorException(this, null); } } private void RaiseServerCloseLink() { if(ServerCloseLink!=null) { ServerCloseLink(this, null); } } private void RaiseConnectFailed() { if(ConnectFailed!=null) { ConnectFailed(this,null); } } #endregion } }
3)消息类
此类存储相关消息
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TcpSocketServer { /// <summary> /// Socket TCP事件参数 /// </summary> public class TCPMessageArgs : EventArgs { /// <summary> /// 提示信息 /// </summary> public string _msg; /// <summary> /// 客户端状态封装类 /// </summary> public ClientInfo state; /// <summary> /// 是否已经处理过了 /// </summary> // public bool IsHandled { get; set; } public TCPMessageArgs(string msg) { this._msg = msg; //IsHandled = false; } public TCPMessageArgs(ClientInfo state) { this.state = state; // IsHandled = false; } public TCPMessageArgs(string msg, ClientInfo state) { this._msg = msg; this.state = state; //IsHandled = false; } } }
4)服务端存储所有客户端类
通过
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; using System.Xml; namespace TcpSocketServer { /// <summary> /// 客户端信息 /// </summary> public class ClientInfo { #region 字段 public int _recvdBufferLength;//接收到的数据长度 private byte[] _recvBuffer;// 接收数据缓冲区 private string _datagram;// 客户端发送到服务器的报文 private Socket _clientSock;// 客户端的Socket private string tempMsg = string.Empty; #endregion #region 属性 /// <summary> /// 接收数据缓冲区 /// </summary> public byte[] RecvDataBuffer { get { return _recvBuffer; } set { _recvBuffer = value; } } /// <summary> /// 存取会话的报文 /// </summary> public string Datagram { get { _datagram = Encoding.Default.GetString(_recvBuffer, 0, _recvdBufferLength); return _datagram; } } public List<MsgProtocol> MsgList { get { _datagram = Encoding.Default.GetString(_recvBuffer, 0, _recvdBufferLength); return HandlerRecvdString(_datagram); } } /// <summary> /// 获得与客户端会话关联的Socket对象 /// </summary> public Socket ClientSocket { get { return _clientSock; } } #endregion public ClientInfo(Socket clientSocket) { _clientSock = clientSocket; } public void Close() { //关闭数据的接受和发送 _clientSock.Shutdown(SocketShutdown.Both); //清理资源 _clientSock.Close(); } public List<MsgProtocol> HandlerRecvdString(string msg) { List<MsgProtocol> msgProList = new List<MsgProtocol>(); if (!String.IsNullOrEmpty(tempMsg)) { msg = tempMsg + msg; } string pattern = "(^<protocol>.*?</protocol>)"; if (Regex.IsMatch(msg, pattern)) { //匹配协议内容 string message = Regex.Match(msg, pattern).Groups[0].Value; //将匹配的内容添加到集合 msgProList.Add(HandleMsg(message)); tempMsg = string.Empty; //截取未匹配字符串,进行下一次匹配 msg = msg.Substring(message.Length); if (!String.IsNullOrEmpty(msg)) { msgProList.AddRange(HandlerRecvdString(msg)); } } else { tempMsg = msg; } return msgProList; } private MsgProtocol HandleMsg(string msg) { MsgProtocol msgProtocol = new TcpSocketServer.MsgProtocol(); XmlDocument xml = new XmlDocument(); xml.LoadXml(msg); XmlNode node = xml.DocumentElement; XmlNode message = node.FirstChild;// xml.SelectSingleNode("message"); if(message.Attributes["type"].Value==MsgType.TEXT.ToString()) { TextProtocol text = new TcpSocketServer.TextProtocol(message.Attributes["content"].Value); msgProtocol.type = MsgType.TEXT; msgProtocol.textProtocol = text; } else { FileProtocol file = new TcpSocketServer.FileProtocol(message.Attributes["content"].Value, message.Attributes["file"].Value); msgProtocol.type = MsgType.FILE; msgProtocol.fileProtocol = file; } return msgProtocol; } } }
5)消息协议
处理每次消息发送时粘包问题
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace TcpSocketServer { public enum MsgType { UNKNOWN = 0, TEXT = 1, FILE = 2 } public class TextProtocol { public string content; private MsgType type=MsgType.TEXT; public TextProtocol(string content) { this.content = content; } //public byte[] ToBytes() //{ // string msgPackage = ToString(); // return Encoding.Default.GetBytes(msgPackage); //} public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("<message "); sb.Append(string.Format("type=\"{0}\"", type.ToString())); sb.Append(string.Format(" content=\"{0}\"", content)); sb.Append("/>"); return sb.ToString(); } } public class FileProtocol { public string filePath; public string content; private string fileName; private MsgType type = MsgType.FILE; public FileProtocol(string content,string filePath) { this.filePath = filePath; this.content = content; } public FileProtocol(string filePath) { this.filePath = filePath; } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("<message "); sb.Append(string.Format("type=\"{0}\"", type.ToString())); sb.Append(string.Format(" file=\"{0}\"", GetFileName())); sb.Append(string.Format(" content=\"{0}\"", GetFileContent())); sb.Append("/>"); return sb.ToString(); } public byte[] ToBytes() { return Encoding.Default.GetBytes(content); } private string GetFileName() { if(File.Exists(filePath)) { return Path.GetFileName(filePath); } else { return ""; } } private string GetFileContent() { if(File.Exists(filePath)) { byte[] bytes = File.ReadAllBytes(filePath); content = Encoding.Default.GetString(bytes); } return content; } } public class MsgProtocol { //公共字段 //public string fileName; public MsgType type = MsgType.UNKNOWN; public TextProtocol textProtocol; public FileProtocol fileProtocol; public MsgProtocol() { } public MsgProtocol(TextProtocol textProtocol) { this.type = MsgType.TEXT; this.textProtocol = textProtocol; } public MsgProtocol(FileProtocol fileProtocol) { this.type = MsgType.FILE; this.fileProtocol = fileProtocol; } public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("<protocol>"); if(type==MsgType.TEXT) { sb.Append(textProtocol.ToString()); } else { sb.Append(fileProtocol.ToString()); } sb.Append("</protocol>"); return sb.ToString(); } public byte[] ToBytes() { return Encoding.Default.GetBytes(this.ToString()); } //public MsgProtocol(string filePath,MsgType type) //{ // type = MsgType.FILE; // this.fileName = fileName; // this.file //} } }
6)主程序应用
1、服务端
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TcpSocketServer { class Program { private static TCPServerAsync tcpServer; static void Main(string[] args) { tcpServer = new TcpSocketServer.TCPServerAsync(8899); tcpServer.DataReceived += new EventHandler<TcpSocketServer.TCPMessageArgs>(OnDataReceived); tcpServer.ClientConnected += new EventHandler<TcpSocketServer.TCPMessageArgs>(OnClientConnected); tcpServer.ClientDisconnected += new EventHandler<TcpSocketServer.TCPMessageArgs>(OnClientDisconnected); tcpServer.Start(); Console.ReadKey(); } public static void OnDataReceived(object obj,TCPMessageArgs message) { ClientInfo state = message.state; string sendData = "Server "; //byte[] data = state.RecvDataBuffer; //string strData = Encoding.Default.GetString(data); //Console.WriteLine(message.state.Datagram); #region 协议功能测试 List<MsgProtocol> msgList = state.MsgList; foreach (MsgProtocol msgProtocol in msgList) { if (msgProtocol.type == MsgType.TEXT) { Console.WriteLine(msgProtocol.textProtocol.content); sendData += msgProtocol.textProtocol.content; } else { Console.WriteLine(msgProtocol.fileProtocol.filePath); sendData += msgProtocol.fileProtocol.filePath; } } #endregion if (message.state.Datagram=="close") { tcpServer.Close(message.state); return; } //数据处理后发送回客户端 //string sendData = "Server " + message.state.Datagram; //byte[] sendBytes = Encoding.Default.GetBytes(sendData); //tcpServer.Send(state, sendBytes); #region 协议功能测试 MsgProtocol protocol = new TcpSocketServer.MsgProtocol(new TcpSocketServer.TextProtocol(sendData)); tcpServer.Send(state, protocol.ToBytes()); #endregion } public static void OnClientConnected(object obj, TCPMessageArgs message) { Console.WriteLine("Connect:" + message.state.ClientSocket.RemoteEndPoint.ToString()); } public static void OnClientDisconnected(object obj, TCPMessageArgs message) { Console.WriteLine("Disconnect:" + message.state.ClientSocket.RemoteEndPoint.ToString()); tcpServer.Close(message.state); } } }
2、客户端调用
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; namespace TcpSocketClient { class Program { private static TCPClientAsync tcpclient; private static bool b_Connecting = true; static void Main(string[] args) { IPAddress ip = IPAddress.Parse("192.168.8.15"); tcpclient = new TcpSocketClient.TCPClientAsync(ip, 8899); tcpclient.ConnectAccepted += new EventHandler<TcpSocketClient.TCPMessageArgs>(OnConnected); tcpclient.DataReceived += new EventHandler<TcpSocketClient.TCPMessageArgs>(OnReceived); tcpclient.ServerCloseLink += new EventHandler<TCPMessageArgs>(OnDisConnected); tcpclient.Connect(); while(b_Connecting) { string msg = Console.ReadLine(); if(msg=="exit") { tcpclient.Close(); //b_Connecting = false; break; } if(msg=="close") { //tcpclient.IsConnected = false; } //byte[] data = Encoding.Default.GetBytes(msg); //tcpclient.Send(data); //tcpclient.Receive(); MsgProtocol msgProtocol = new TcpSocketClient.MsgProtocol(new TcpSocketClient.TextProtocol(msg)); tcpclient.Send(msgProtocol.ToBytes()); } } public static void OnConnected(object obj,TCPMessageArgs msg) { Console.WriteLine("Connected......."); tcpclient.Receive(); } public static void OnReceived(object obj, TCPMessageArgs msg) { //Console.WriteLine("Receivedd "+msg.state.Datagram); List<MsgProtocol> msgList = msg.state.MsgList; foreach(MsgProtocol msgProtocol in msgList) { if(msgProtocol.type==MsgType.TEXT) { Console.WriteLine(msgProtocol.textProtocol.content); } else { Console.WriteLine(msgProtocol.fileProtocol.filePath); } } } public static void OnDisConnected(object obj,TCPMessageArgs msg) { Console.WriteLine("Server Disconnected"); } } }
PS:未作客户端短线重连