C# 使用TcpClient/Socket安全传输/发送大数据包
我正在编写一个基于TCP的客户端,它需要发送和接收数据。我使用了.NET Framework为Socket类提供的C# 使用TcpClient/Socket安全传输/发送大数据包,c#,.net,sockets,tcp,tcpclient,C#,.net,Sockets,Tcp,Tcpclient,我正在编写一个基于TCP的客户端,它需要发送和接收数据。我使用了.NET Framework为Socket类提供的异步编程模型(APM) 连接到套接字后,我开始使用BeginReceive等待套接字上的数据 现在,在等待套接字上的数据时,可能需要通过套接字发送数据。并且send方法可以被多次调用 所以我必须确保 上一次Send调用中的所有字节都已完全发送 我发送数据的方式是安全的,因为在数据发送过程中,可以进行任何发送数据的调用 这是我第一次使用socket,那么我发送数据的方法正确吗?
异步编程模型(APM)
连接到套接字后,我开始使用BeginReceive
等待套接字上的数据
现在,在等待套接字上的数据时,可能需要通过套接字发送数据。并且send方法可以被多次调用
所以我必须确保
- 上一次
调用中的所有字节都已完全发送Send
- 我发送数据的方式是安全的,因为在数据发送过程中,可以进行任何发送数据的调用
private readonly object writeLock = new object();
public void Send(NetworkCommand cmd)
{
var data = cmd.ToBytesWithLengthPrefix();
ThreadPool.QueueUserWorkItem(AsyncDataSent, data);
}
private int bytesSent;
private void AsyncDataSent(object odata)
{
lock (writeLock)
{
var data = (byte[])odata;
int total = data.Length;
bytesSent = 0;
int buf = Globals.BUFFER_SIZE;
while (bytesSent < total)
{
if (total - bytesSent < Globals.BUFFER_SIZE)
{
buf = total - bytesSent;
}
IAsyncResult ar = socket.BeginSend(data, bytesSent, buf, SocketFlags.None, DataSentCallback, data);
ar.AsyncWaitHandle.WaitOne();
}
}
}
全班
namespace Cybotech.Network
{
public delegate void ConnectedDelegate(IPEndPoint ep);
public delegate void DisconnectedDelegate(IPEndPoint ep);
public delegate void CommandReceivedDelagate(IPEndPoint ep, NetworkCommand cmd);
}
using System;
using System.Net;
using System.Net.Sockets;
using Cybotech.Helper;
using Cybotech.IO;
namespace Cybotech.Network
{
public class ClientState : IDisposable
{
private int _id;
private int _port;
private IPAddress _ip;
private IPEndPoint _endPoint;
private Socket _socket;
private ForwardStream _stream;
private byte[] _buffer;
public ClientState(IPEndPoint endPoint, Socket socket)
{
Init(endPoint, socket);
}
private void Init(IPEndPoint endPoint, Socket socket)
{
_endPoint = endPoint;
_ip = _endPoint.Address;
_port = _endPoint.Port;
_id = endPoint.GetHashCode();
_socket = socket;
_stream = new ForwardStream();
_buffer = new byte[Globals.BUFFER_SIZE];
}
public int Id
{
get { return _id; }
}
public int Port
{
get { return _port; }
}
public IPAddress Ip
{
get { return _ip; }
}
public IPEndPoint EndPoint
{
get { return _endPoint; }
}
public Socket Socket
{
get { return _socket; }
}
public ForwardStream Stream
{
get { return _stream; }
}
public byte[] Buffer
{
get { return _buffer; }
set { _buffer = value; }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_stream != null)
{
_stream.Close();
_stream.Dispose();
}
if (_socket != null)
{
_socket.Close();
}
}
}
public void Dispose()
{
Dispose(true);
}
}
}
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Cybotech.Command;
using Cybotech.Network;
namespace ExamServer.Network
{
public class TcpServer : IDisposable
{
private Socket socket;
private bool secure;
private readonly Dictionary<IPEndPoint, ClientState> clients = new Dictionary<IPEndPoint, ClientState>();
//public events
#region Events
public event CommandDelegate CommandReceived;
public event ConnectedDelegate ClientAdded;
public event DisconnectedDelegate ClientRemoved;
#endregion
//event invokers
#region Event Invoke methods
protected virtual void OnCommandReceived(IPEndPoint ep, NetworkCommand command)
{
CommandDelegate handler = CommandReceived;
if (handler != null) handler(ep, command);
}
protected virtual void OnClientAdded(IPEndPoint ep)
{
ConnectedDelegate handler = ClientAdded;
if (handler != null) handler(ep);
}
protected virtual void OnClientDisconnect(IPEndPoint ep)
{
DisconnectedDelegate handler = ClientRemoved;
if (handler != null) handler(ep);
}
#endregion
//public property
public string CertificatePath { get; set; }
public TcpServer(EndPoint endPoint, bool secure)
{
StartServer(endPoint, secure);
}
public TcpServer(IPAddress ip, int port, bool secure)
{
StartServer(new IPEndPoint(ip, port), secure);
}
public TcpServer(string host, int port, bool secure)
{
StartServer(new IPEndPoint(IPAddress.Parse(host), port), secure);
}
private void StartServer(EndPoint ep, bool ssl)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ep);
socket.Listen(150);
this.secure = ssl;
socket.BeginAccept(AcceptClientCallback, null);
}
private void AcceptClientCallback(IAsyncResult ar)
{
Socket client = socket.EndAccept(ar);
var ep = (IPEndPoint) client.RemoteEndPoint;
var state = new ClientState(ep, client);
if (secure)
{
//TODO : handle client for ssl authentication
}
//add client to
clients.Add(ep, state);
OnClientAdded(ep);
client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
//var thread = new Thread(ReceiveDataCallback);
//thread.Start(state);
}
private void ReceiveDataCallback(IAsyncResult ar)
{
ClientState state = (ClientState)ar.AsyncState;
try
{
var bytesRead = state.Socket.EndReceive(ar);
state.Stream.Write(state.Buffer, 0, bytesRead);
// check available commands
while (state.Stream.LengthPrefix > 0)
{
NetworkCommand cmd = NetworkCommand.CreateFromStream(state.Stream);
OnCommandReceived(state.EndPoint, cmd);
}
//start reading data again
state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
}
catch (SocketException ex)
{
if (ex.NativeErrorCode.Equals(10054))
{
RemoveClient(state.EndPoint);
}
}
}
private void RemoveClient(IPEndPoint ep)
{
OnClientDisconnect(ep);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//TODO : dispose all the client related socket stuff
}
}
public void Dispose()
{
Dispose(true);
}
}
}
名称空间Cybotech.Network
{
公共代表无效连接delegate(IPEndPoint ep);
公共代表无效断开delegate(IPEndPoint ep);
公共委托void命令receiveddelagate(IPEndPoint ep,NetworkCommand cmd);
}
使用制度;
Net系统;
使用System.Net.Sockets;
使用Cybotech.Helper;
使用Cybotech.IO;
名称空间Cybotech.Network
{
公共类ClientState:IDisposable
{
私人内部id;
私人国际港口;
私有ip地址;
专用IPEndPoint_端点;
专用插座(u插座),;
私有转发流_流;
专用字节[]_缓冲区;
公共客户端状态(IPEndPoint端点、套接字)
{
Init(端点,套接字);
}
私有void Init(IPEndPoint端点、套接字)
{
_终点=终点;
_ip=_endPoint.Address;
_端口=_endPoint.port;
_id=endPoint.GetHashCode();
_插座=插座;
_stream=新的ForwardStream();
_buffer=新字节[Globals.buffer_SIZE];
}
公共整数Id
{
获取{return\u id;}
}
公共int端口
{
获取{return\u port;}
}
公共Ip地址
{
获取{return\u ip;}
}
公共IPEndPoint端点
{
获取{return\u endPoint;}
}
公用插座
{
获取{return\u socket;}
}
公共转发流
{
获取{return\u stream;}
}
公共字节[]缓冲区
{
获取{return\u buffer;}
设置{u buffer=value;}
}
受保护的虚拟void Dispose(bool disposing)
{
如果(处置)
{
如果(_stream!=null)
{
_stream.Close();
_stream.Dispose();
}
if(_socket!=null)
{
_socket.Close();
}
}
}
公共空间处置()
{
处置(真实);
}
}
}
使用制度;
使用System.Collections.Generic;
Net系统;
使用System.Net.Sockets;
使用Cybotech.命令;
使用Cybotech.网络;
命名空间ExamServer.Network
{
公共类TcpServer:IDisposable
{
专用插座;
私人楼宇安全;
私有只读字典客户端=新字典();
//公共活动
#地区活动
收到公共事件命令Delegate命令;
公共事件连接Delegate客户端添加;
公共事件断开elegate ClientRemoved;
#端区
//事件调用程序
#区域事件调用方法
受保护的虚拟void OnCommandReceived(IPEndPoint ep,NetworkCommand)
{
CommandDelegate处理程序=CommandReceived;
if(handler!=null)handler(ep,command);
}
受保护的虚拟void onclienteded(IPEndPoint ep)
{
ConnectedDelegate处理程序=ClientAdded;
if(handler!=null)handler(ep);
}
受保护的虚拟void OnClientDisconnect(IPEndPoint ep)
{
DisconnectedDelegate处理程序=ClientRemoved;
if(handler!=null)handler(ep);
}
#端区
//公共财产
公共字符串证书路径{get;set;}
公共TcpServer(端点,bool-secure)
{
StartServer(端点,安全);
}
公共TcpServer(ip地址ip、int端口、bool安全)
{
StartServer(新的IPEndPoint(ip,端口),安全);
}
公共TcpServer(字符串主机、int端口、bool-secure)
{
StartServer(新的IPEndPoint(IPAddress.Parse(主机)、端口),安全;
}
私有void StartServer(端点ep、bool ssl)
{
套接字=新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.Tcp);
套扎(ep);
听(150);
this.secure=ssl;
BeginAccept(AcceptClientCallback,null);
}
私有void AcceptClientCallback(IAsyncResult ar)
{
socketclient=Socket.EndAccept(ar);
var ep=(IPEndPoint)client.RemoteEndPoint;
var状态=新的客户端状态(ep、客户端);
如果(安全)
{
//TODO:为ssl身份验证处理客户端
}
//将客户端添加到
添加(ep,状态);
无客户(ep);
client.BeginReceive(state.Buffer,0,state.Buffer.Length,SocketFlags.None,ReceiveDataCallback,state);
//var thread=新线程(ReceiveDataCallback);
//线程启动(状态);
}
私有void ReceiveDataCallback(IAsyncResult ar)
{
ClientState=(ClientState)ar.AsyncState;
尝试
{
namespace Cybotech.Network
{
public delegate void ConnectedDelegate(IPEndPoint ep);
public delegate void DisconnectedDelegate(IPEndPoint ep);
public delegate void CommandReceivedDelagate(IPEndPoint ep, NetworkCommand cmd);
}
using System;
using System.Net;
using System.Net.Sockets;
using Cybotech.Helper;
using Cybotech.IO;
namespace Cybotech.Network
{
public class ClientState : IDisposable
{
private int _id;
private int _port;
private IPAddress _ip;
private IPEndPoint _endPoint;
private Socket _socket;
private ForwardStream _stream;
private byte[] _buffer;
public ClientState(IPEndPoint endPoint, Socket socket)
{
Init(endPoint, socket);
}
private void Init(IPEndPoint endPoint, Socket socket)
{
_endPoint = endPoint;
_ip = _endPoint.Address;
_port = _endPoint.Port;
_id = endPoint.GetHashCode();
_socket = socket;
_stream = new ForwardStream();
_buffer = new byte[Globals.BUFFER_SIZE];
}
public int Id
{
get { return _id; }
}
public int Port
{
get { return _port; }
}
public IPAddress Ip
{
get { return _ip; }
}
public IPEndPoint EndPoint
{
get { return _endPoint; }
}
public Socket Socket
{
get { return _socket; }
}
public ForwardStream Stream
{
get { return _stream; }
}
public byte[] Buffer
{
get { return _buffer; }
set { _buffer = value; }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_stream != null)
{
_stream.Close();
_stream.Dispose();
}
if (_socket != null)
{
_socket.Close();
}
}
}
public void Dispose()
{
Dispose(true);
}
}
}
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Cybotech.Command;
using Cybotech.Network;
namespace ExamServer.Network
{
public class TcpServer : IDisposable
{
private Socket socket;
private bool secure;
private readonly Dictionary<IPEndPoint, ClientState> clients = new Dictionary<IPEndPoint, ClientState>();
//public events
#region Events
public event CommandDelegate CommandReceived;
public event ConnectedDelegate ClientAdded;
public event DisconnectedDelegate ClientRemoved;
#endregion
//event invokers
#region Event Invoke methods
protected virtual void OnCommandReceived(IPEndPoint ep, NetworkCommand command)
{
CommandDelegate handler = CommandReceived;
if (handler != null) handler(ep, command);
}
protected virtual void OnClientAdded(IPEndPoint ep)
{
ConnectedDelegate handler = ClientAdded;
if (handler != null) handler(ep);
}
protected virtual void OnClientDisconnect(IPEndPoint ep)
{
DisconnectedDelegate handler = ClientRemoved;
if (handler != null) handler(ep);
}
#endregion
//public property
public string CertificatePath { get; set; }
public TcpServer(EndPoint endPoint, bool secure)
{
StartServer(endPoint, secure);
}
public TcpServer(IPAddress ip, int port, bool secure)
{
StartServer(new IPEndPoint(ip, port), secure);
}
public TcpServer(string host, int port, bool secure)
{
StartServer(new IPEndPoint(IPAddress.Parse(host), port), secure);
}
private void StartServer(EndPoint ep, bool ssl)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ep);
socket.Listen(150);
this.secure = ssl;
socket.BeginAccept(AcceptClientCallback, null);
}
private void AcceptClientCallback(IAsyncResult ar)
{
Socket client = socket.EndAccept(ar);
var ep = (IPEndPoint) client.RemoteEndPoint;
var state = new ClientState(ep, client);
if (secure)
{
//TODO : handle client for ssl authentication
}
//add client to
clients.Add(ep, state);
OnClientAdded(ep);
client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
//var thread = new Thread(ReceiveDataCallback);
//thread.Start(state);
}
private void ReceiveDataCallback(IAsyncResult ar)
{
ClientState state = (ClientState)ar.AsyncState;
try
{
var bytesRead = state.Socket.EndReceive(ar);
state.Stream.Write(state.Buffer, 0, bytesRead);
// check available commands
while (state.Stream.LengthPrefix > 0)
{
NetworkCommand cmd = NetworkCommand.CreateFromStream(state.Stream);
OnCommandReceived(state.EndPoint, cmd);
}
//start reading data again
state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
}
catch (SocketException ex)
{
if (ex.NativeErrorCode.Equals(10054))
{
RemoveClient(state.EndPoint);
}
}
}
private void RemoveClient(IPEndPoint ep)
{
OnClientDisconnect(ep);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//TODO : dispose all the client related socket stuff
}
}
public void Dispose()
{
Dispose(true);
}
}
}