我如何有效地接收&;使用c#套接字同时发送数据
我有一个C#.net服务器和客户端(TCP)。服务器以异步方式侦听多个客户端。客户端可以发送从屏幕截图到消息、到视频流(实际上只是以极快的速度发送了多个屏幕截图,但从来没有工作过…)到系统信息的数据。我面临的问题是,当所有这些都是可能的时候,服务器只能接收很少的数据。我似乎无法从客户端下载文件并同时收到屏幕截图。或者,当接收多个截图以模拟屏幕共享时,我无法下载文件(这通常会使数据接收过程崩溃) 我甚至认为我的服务器没有正确地接收客户机的数据,因为数据经常损坏并引发异常。我将从我的服务器侦听代码本身开始:我如何有效地接收&;使用c#套接字同时发送数据,c#,.net,sockets,server,client,C#,.net,Sockets,Server,Client,我有一个C#.net服务器和客户端(TCP)。服务器以异步方式侦听多个客户端。客户端可以发送从屏幕截图到消息、到视频流(实际上只是以极快的速度发送了多个屏幕截图,但从来没有工作过…)到系统信息的数据。我面临的问题是,当所有这些都是可能的时候,服务器只能接收很少的数据。我似乎无法从客户端下载文件并同时收到屏幕截图。或者,当接收多个截图以模拟屏幕共享时,我无法下载文件(这通常会使数据接收过程崩溃) 我甚至认为我的服务器没有正确地接收客户机的数据,因为数据经常损坏并引发异常。我将从我的服务器侦听代码本
public void Listen()
{
_socket.Listen(100);
_socket.BeginAccept(new AsyncCallback(AcceptCallback), null);
CSCLog("Server started || Listening...");
void AcceptCallback(IAsyncResult AR)
{
Socket socket = _socket.EndAccept(AR);
clienthandler client = new clienthandler(socket, _dash);
_socketClientList.Add(client);
// Repeat the listening process...
_socket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
}
服务器拥有一个自定义类clienthandler,它需要一个套接字并提供单个套接字“控件”。下面是该类的基本运行情况:
public class clienthandler
{
public Socket _clientSocket;
public clienthandler(Socket paramSocket)
{
_clientSocket = paramSocket;
receiveAll();
}
public void receiveAll()
{
int BUFF_SIZE = 4024 * 2;
byte[] _lengthBuffer = new byte[BUFF_SIZE];
_clientSocket.BeginReceive(_lengthBuffer, 0, _lengthBuffer.Length, 0, new AsyncCallback(LengthCallBack), _clientSocket);
void LengthCallBack(IAsyncResult lengthAR)
{
try
{
Socket buffSocket = (Socket)lengthAR.AsyncState;
int lengthreceived = _clientSocket.EndReceive(lengthAR);
byte[] lengthdata = new byte[lengthreceived];
Array.Copy(_lengthBuffer, lengthdata, lengthreceived);
// Handle the received incoming data length
DataInformation datai = (DataInformation)ObjectHandler.Deserialize(_lengthBuffer);
int datalength = datai.datalength;
Array.Clear(_lengthBuffer, 0, _lengthBuffer.Length);
PrepCol(datai, buffSocket);
// Repeat the data length listening process...
_clientSocket.BeginReceive(_lengthBuffer, 0, _lengthBuffer.Length, 0, new AsyncCallback(LengthCallBack), _clientSocket);
}
catch (Exception ex) { // handle exception... }
}
}
}
为了进一步解释,receiveAll()
函数尝试异步侦听数据。我创建了一个名为DataInformation
的自定义类(它们都存储在客户端和服务器共享的.DLL中),充当通过流发送的数据的头。它只包括对象类型
&int datalength
的枚举,该枚举表示我的客户端随后发送的传入数据量(因为从客户端发送的任何数据都先发送自己的数据信息,然后紧接着发送的是实际数据。两者都是序列化的。)
PropCol()
方法接收反序列化的DataInformation类和套接字对象。然后,它使用提供的数据信息变量(Enum&int datalength.)收集数据:
public void PrepCol(DataInformation paramDatainformation,Socket paramBuffSocket)
{
int datalength=paramDatainformation.datalength;
对象streamobj;
MemoryStream ms=新的MemoryStream();
if(paramDatainformation.objectType==objectType.Universal)
{
//准备并收集传入数据
而(数据长度>0)
{
字节[]缓冲区;
if(数据长度
它利用while
循环同步接收数据,直到收到数据信息所说的所需量为止。它获取数据对象并将其传递到需要对象的CheckData()
方法中。它获取对象并检查它是否是它可以处理的任何对象(如屏幕截图或消息等),如果是,则检查它是否可以处理
我发现最大的问题是,当接收大数据或数据非常快时,receiveAll()
方法中的DataInformation反序列化返回损坏/无效的数据,这些数据根本不好,因为我丢失了可能需要的东西
我的问题实际上归结为我做错了什么?或者我应该如何采取同时接收多个数据的方法
我能提供的更多信息是序列化和去序列化方法在.DLL中。就这些。我为大量代码被丢弃而道歉,但我觉得这些是最相关的事情。谢谢你的时间。 < P>首先,你应该把你的TCP套接字看作连续的数据流。最终,您将遇到这样的情况:读取未完成的字节集,并且无法对其进行反序列化
综上所述,当您从套接字接收下一部分数据时,您需要知道两件事:
- 到目前为止,您收到了多少数据李>
- 开始反序列化过程需要多少数据
Socket.ReceiveAsync()
最后,不要在逻辑中使用Socket
。改用流
下面是我根据某种协议选择的接收和解析二进制数据的方法。我假设您的协议包含一些固定大小的头,后跟数据(文件/屏幕截图/视频等)。数据的大小和类型存储在标题中
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace Test1
{
public interface IData
{
}
public interface IHeader
{
int DataSize { get; }
}
public interface IHeaderParser
{
int HeaderSize { get; }
IHeader Parse(byte[] buffer, int offset);
}
public interface IDataParser
{
IData Parse(byte[] buffer, int offset);
}
public interface IDataParserSelector
{
IDataParser GetParser(IHeader header);
}
public class StreamReceiver : IDisposable
{
public StreamReceiver(
Stream stream,
IHeaderParser headerParser,
IDataParserSelector dataParserSelector)
{
_stream = stream;
_headerParser = headerParser;
_dataParserSelector = dataParserSelector;
}
public virtual void Dispose()
{
_stream.Dispose();
}
public async Task<IData> ReceiveAsync(CancellationToken token)
{
const int headerOffset = 0;
await ReadAsync(headerOffset, _headerParser.HeaderSize, token).ConfigureAwait(false);
var header = _headerParser.Parse(_buffer, headerOffset);
var dataOffset = headerOffset + _headerParser.HeaderSize;
await ReadAsync(dataOffset, header.DataSize, token).ConfigureAwait(false);
var dataParser = _dataParserSelector.GetParser(header);
var data = dataParser.Parse(_buffer, dataOffset);
return data;
}
private async Task ReadAsync(int offset, int count, CancellationToken token)
{
if (_buffer.Length < offset + count)
{
var oldBuffer = _buffer;
_buffer = new byte[offset + count];
Array.Copy(oldBuffer, _buffer, oldBuffer.Length);
}
var nread = 0;
while (nread < count)
{
nread += await _stream.ReadAsync(
_buffer, offset + nread, count - nread, token)
.ConfigureAwait(false);
}
}
private readonly Stream _stream;
private readonly IHeaderParser _headerParser;
private readonly IDataParserSelector _dataParserSelector;
private byte[] _buffer = new byte[0];
}
public class TcpReceiver : StreamReceiver
{
public TcpReceiver(
TcpClient tcpClient,
IHeaderParser headerParser,
IDataParserSelector dataParserSelector)
: base(tcpClient.GetStream(), headerParser, dataParserSelector)
{
_tcpClient = tcpClient;
}
public override void Dispose()
{
base.Dispose();
_tcpClient.Dispose();
}
private readonly TcpClient _tcpClient;
}
}
使用系统;
使用System.IO;
使用System.Net.Sockets;
使用系统线程;
使用System.Threading.Tasks;
名称空间Test1
{
公共接口IData
{
}
公共接口IHeader
{
int DataSize{get;}
}
公共接口IHeaderParser
{
int HeaderSize{get;}
IHeader解析(字节[]缓冲区,int偏移量);
}
公共接口IDataParser
{
IData解析(字节[]缓冲区,int偏移量);
}
公共接口IDataParserSelector
{
IDataParser GetParser(IHeader头);
}
公共类StreamReceiver:IDisposable
{
公共图书馆
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace Test1
{
public interface IData
{
}
public interface IHeader
{
int DataSize { get; }
}
public interface IHeaderParser
{
int HeaderSize { get; }
IHeader Parse(byte[] buffer, int offset);
}
public interface IDataParser
{
IData Parse(byte[] buffer, int offset);
}
public interface IDataParserSelector
{
IDataParser GetParser(IHeader header);
}
public class StreamReceiver : IDisposable
{
public StreamReceiver(
Stream stream,
IHeaderParser headerParser,
IDataParserSelector dataParserSelector)
{
_stream = stream;
_headerParser = headerParser;
_dataParserSelector = dataParserSelector;
}
public virtual void Dispose()
{
_stream.Dispose();
}
public async Task<IData> ReceiveAsync(CancellationToken token)
{
const int headerOffset = 0;
await ReadAsync(headerOffset, _headerParser.HeaderSize, token).ConfigureAwait(false);
var header = _headerParser.Parse(_buffer, headerOffset);
var dataOffset = headerOffset + _headerParser.HeaderSize;
await ReadAsync(dataOffset, header.DataSize, token).ConfigureAwait(false);
var dataParser = _dataParserSelector.GetParser(header);
var data = dataParser.Parse(_buffer, dataOffset);
return data;
}
private async Task ReadAsync(int offset, int count, CancellationToken token)
{
if (_buffer.Length < offset + count)
{
var oldBuffer = _buffer;
_buffer = new byte[offset + count];
Array.Copy(oldBuffer, _buffer, oldBuffer.Length);
}
var nread = 0;
while (nread < count)
{
nread += await _stream.ReadAsync(
_buffer, offset + nread, count - nread, token)
.ConfigureAwait(false);
}
}
private readonly Stream _stream;
private readonly IHeaderParser _headerParser;
private readonly IDataParserSelector _dataParserSelector;
private byte[] _buffer = new byte[0];
}
public class TcpReceiver : StreamReceiver
{
public TcpReceiver(
TcpClient tcpClient,
IHeaderParser headerParser,
IDataParserSelector dataParserSelector)
: base(tcpClient.GetStream(), headerParser, dataParserSelector)
{
_tcpClient = tcpClient;
}
public override void Dispose()
{
base.Dispose();
_tcpClient.Dispose();
}
private readonly TcpClient _tcpClient;
}
}