簡體   English   中英

從C#套接字讀取確切的字節數

[英]Reading exact number of bytes from c# socket

我正在使用C#套接字(異步模式),並且需要從流中讀取確切的字節數才能正確解析消息。 由於我們系統中的消息非常長,因此好像socket.EndRead操作返回的字節數少於socket.BeginRead請求的字節數。 僅當讀取了確切的字節數時,才有機會使c#套接字標記操作完成嗎??? 是使用NetworkStream的方式嗎?

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

UPD:

我已經用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);
                }

            }

        }

與枚舉器進行良好的調用,盡管我希望您的外部代碼不只是在asyncresults上調用WaitOne,因為這會阻塞正在運行的線程。

如果您喜歡這種風格的異步編碼,請在NuGet上查看Wintellect AsyncEnumerator-它也使用迭代器,使代碼具有很高的資源效率,並添加了更輕松的方式來處理取消和異常,同時確保所有APM結束方法都被調用。

我之前通過以下方式解決了確切的閱讀問題:

1)在套接字上發送的數據上添加長度前綴
2)使用以下方法定義在Socket上工作的幫助程序類:

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)

因此它仍然需要在循環中調用,但是看起來像一個普通的異步操作,例如,通過asyncenumerator調用(沒有取消檢查和異常處理):

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM