从 c# 套接字读取确切的字节数

本文关键字:字节数 读取 套接字 | 更新日期: 2023-09-27 18:35:49

我正在使用 C# 套接字(异步模式),需要从流中读取确切的字节数才能正确解析消息。 由于我们系统中的消息很长,看起来像套接字。结束读取操作返回的字节数少于套接字中请求的字节数。开始阅读。只有在读取确切的字节数时,才有机会使 C# 套接字标记操作完成???网络流是???的方式''

IAsyncRes ar = socket.BeginRead(1Mb byte message)
ar.Handle.Wait() // --> will signal ONLY when 1Mb us read !!!!
socket.EndRead() 

上级:

我已经用 c# 迭代器解决了它。(此处未显示运行 irator 循环并负责执行 MoveNext 的线程)

protected IEnumerator<IAsyncResult> EnumReceiveExact(byte[] array)
        {

            int offset = 0;
            while (offset < array.Length)
            {
                SocketError err = SocketError.Success;
                IAsyncResult ar = _socket.BeginReceive(array, offset, array.Length - offset, SocketFlags.None, out err, null, null);
                Console.WriteLine("{0}:err:{1}", this, err);
                if (err != SocketError.Success)
                {
                    _socket.Close();
                    throw new Exception("Error " + err);
                }
                yield return ar;
                while (!ar.IsCompleted)
                {
                    yield return ar;
                }
                offset += _socket.EndReceive(ar, out err);
                if (err != SocketError.Success)
                {
                    _socket.Close();
                    throw new Exception("Error " + err);
                }
            }
        }

从 c# 套接字读取确切的字节数

与枚举器的良好调用,尽管我希望您的外部代码不只是在异步结果上调用 WaitOne,因为这会阻止正在运行的线程。

如果你喜欢这种异步编码风格,请查看NuGet上的Wintellect AsyncEnumerator - 它也使用迭代器,使代码非常节省资源,并添加更简单的方法来处理取消和异常,同时确保APM结束方法都被调用。

我之前已经通过以下方式解决了确切的读取问题:

1) 为套接字
上发送的数据添加长度前缀2) 使用以下方法定义在套接字上运行的帮助程序类:

public IAsyncResult BeginRead(AsyncCallback callback)
// Calculate whether to read length header or remaining payload bytes
// Issue socket recieve and return its IAsyncResult
public MemoryStream EndRead(IAsyncResult result)
// Process socket read, if payload read completely return as a memorystream
// If length header has been recieved make sure buffer is big enough
// If 0 bytes recieved, throw SocketException(10057) as conn is closed
public IAsyncResult BeginSend(AsyncCallback callback, MemoryStream data)
// Issue sends for the length header or payload (data.GetBuffer()) on the first call
public Boolean EndSend(IAsyncResult result)
// Process bytes sent, return true if payload sent completely.
// If 0 bytes sent, throw SocketException(10057)

所以它仍然需要在循环中调用,但看起来像一个正常的异步操作,例如通过异步枚举器调用(没有取消检查和异常处理):

do
{
    socketHelper.BeginSend(ae.End(1, ar => socketHelper.EndSend(ar)), sendData);
    yield return 1;
    doneSend = socketHelper.EndSend(ae.DequeueAsyncResult());
} 
while (!doneSend);