gpt4 book ai didi

c# - 使用 TcpClient/Socket 安全传输/发送大数据包

转载 作者:可可西里 更新时间:2023-11-01 02:33:40 24 4
gpt4 key购买 nike

我正在编写一个需要发送和接收数据的基于 TCP 的客户端。我使用了 .NET Framework 为 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();
}
}
}

对象如何变成byte[],有时NetworkCommand可以有0.5 MB

    public byte[] ToBytesWithLengthPrefix()
{
var stream = new MemoryStream();
try
{
Serializer.SerializeWithLengthPrefix(stream, this, PrefixStyle.Fixed32);
return stream.ToArray();
}
finally
{
stream.Close();
stream.Dispose();
}
}

完成类(class)

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);
}
}
}

最佳答案

同一个客户端将无法向您发送数据,除非他发送完当前字节。

因此在服务器端,您将收到完整的数据,不会被来自该客户端的其他新消息打断,但要考虑到如果发送的消息太大,并非所有发送的消息都会被一次点击接收,但仍然,接收完成后最后是一条消息。

关于c# - 使用 TcpClient/Socket 安全传输/发送大数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17356507/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com