Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我如何有效地接收&;使用c#套接字同时发送数据_C#_.net_Sockets_Server_Client - Fatal编程技术网

我如何有效地接收&;使用c#套接字同时发送数据

我如何有效地接收&;使用c#套接字同时发送数据,c#,.net,sockets,server,client,C#,.net,Sockets,Server,Client,我有一个C#.net服务器和客户端(TCP)。服务器以异步方式侦听多个客户端。客户端可以发送从屏幕截图到消息、到视频流(实际上只是以极快的速度发送了多个屏幕截图,但从来没有工作过…)到系统信息的数据。我面临的问题是,当所有这些都是可能的时候,服务器只能接收很少的数据。我似乎无法从客户端下载文件并同时收到屏幕截图。或者,当接收多个截图以模拟屏幕共享时,我无法下载文件(这通常会使数据接收过程崩溃) 我甚至认为我的服务器没有正确地接收客户机的数据,因为数据经常损坏并引发异常。我将从我的服务器侦听代码本

我有一个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;
    }
}