2011-11-17 35 views
6

Gần đây tôi đã giải quyết một hành vi lạ của phương thức nhận đồng bộ .Net. Tôi cần viết một ứng dụng có các nút giao tiếp với nhau bằng cách gửi/nhận dữ liệu. Mỗi máy chủ có một vòng lặp nhận được đồng bộ, sau khi nhận được một lớp serialized nó deserializes và xử lý nó. Sau đó nó sẽ gửi không đồng bộ lớp tuần tự này đến một số nút đã chọn (sử dụng AsynchSendTo)..NET C# Nhận đồng bộ không chặn

MSDN nói rõ rằng:

"Nếu bạn đang sử dụng một Socket hướng kết nối, phương pháp Nhận sẽ đọc dữ liệu càng nhiều càng tốt có sẵn, lên đến kích thước của bộ đệm Nếu. máy chủ từ xa tắt kết nối Ổ cắm bằng phương pháp Shutdown và tất cả dữ liệu có sẵn đã được nhận, phương thức Nhận sẽ hoàn tất ngay lập tức và trả về số byte không. "

Trong trường hợp của tôi không đúng. Có một số trường hợp ngẫu nhiên khi nhận không chặn và trả về 0 byte (không xác định situtation) ngay lập tức sau khi thiết lập kết nối. Tôi chắc chắn 100% người gửi đã gửi ít nhất 1000 byte. Một điều thú vị nữa: khi đặt Sleep (500) trước khi nhận được mọi thứ hoạt động tốt. Dưới đây là mã nhận:

_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
try 
{ 
    _listener.Bind(_serverEndpoint); 
    _listener.Listen(Int32.MaxValue); 
    while (true) 
    { 
     Console.WriteLine("Waiting for connection..."); 
     Socket handler = _listener.Accept(); 

     int totalBytes = 0; 
     int bytesRec; 
     var bytes = new byte[DATAGRAM_BUFFER]; 
     do 
     { 
      //Thread.Sleep(500); 
      bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 
      totalBytes += bytesRec; 
     } while (bytesRec > 0); 

     handler.Shutdown(SocketShutdown.Both); 
     handler.Close(); 
    } 
} 
catch (SocketException e) 
{ 
    Console.WriteLine(e); 
} 

Cũng phần gửi:

public void AsynchSendTo(Datagram datagram, IPEndPoint recipient) 
{ 

    byte[] byteDatagram = SerializeDatagram(datagram); 
    try 
    { 
     var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket)); 
    } 
    catch (SocketException e) 
    { 
     Console.WriteLine(e); 
    } 
} 

public void ConnectCallback(IAsyncResult result) 
{ 
    try 
    { 
     var stateObject = (StateObject)result.AsyncState; 
     var socket = stateObject.Socket; 
     socket.EndConnect(result); 
     socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("catched!" + ex.ToString()); 
    } 
} 

public void SendCallback(IAsyncResult result) 
{ 
    try 
    { 
     var client = (Socket)result.AsyncState; 
     client.EndSend(result); 
     client.Shutdown(SocketShutdown.Both); 
     client.Close(); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
    } 
} 

class StateObject 
{ 
    public Byte[] Data { get; set; } 
    public int Size; 
    public Socket Socket; 
} 

Câu hỏi của tôi: tôi sử dụng đồng bộ nhận một cách sai? Tại sao nó không chặn sự kiện mặc dù có dữ liệu để nhận?

+0

Vì câu hỏi của bạn không cụ thể về vấn đề bạn đang gặp phải, được giải quyết bằng chế độ ngủ trước khi đọc. Vì nửa giây mỗi vòng lặp thực sự có thể mất một số điện thoại với độ trễ nếu rất nhiều đang được đọc cùng một lúc, bạn đã thử ngủ sau khi đọc với một thời gian ngủ nhỏ hơn như 100msecs? Điều này đã làm việc cho tôi với việc đọc từ các cổng nối tiếp nhưng đó cũng là khi một sự kiện nhận dữ liệu cũng xảy ra. – jlafay

+0

Đây không phải là cách Socket hoạt động. Bắt đầu chẩn đoán điều này bằng cách xóa tất cả các khối try/catch. –

Trả lời

4

Bạn đang tự bắn mình dưới chân.

bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 

Lúc đầu của kết nối, Available sẽ là 0, buộc nó phải quay trở lại ngay lập tức với 0. Thay vào đó, bạn nên xác định số byte được miễn phí trong bộ đệm của bạn (ví dụ bytes.Length-totalBytes), sau đó nó cũng sẽ chặn.

6

Bạn có thể gặp sự cố đồng thời tại đây. Sau khi bạn chấp nhận một kết nối, bạn nhảy thẳng vào nhận. Quá trình gửi có thể không có đủ thời gian để đến cuộc gọi để gửi và vì vậy, handler.Available của bạn là 0 và trả về nhận.

Đây cũng là lý do tại sao "lỗi" không xảy ra khi bạn thêm giấc ngủ 500 ms.

+0

Bạn nói đúng, nhưng trễ 7 phút;) – Lucero

+0

Tôi nghĩ rằng tôi cũng đã thêm lý do tại sao 500 ms sửa lỗi đó. Tôi không sao chép câu trả lời của bạn ... – Tudor

+0

Xin lỗi, ý định của tôi là * không * để làm cho câu trả lời của bạn trông như thể nó được sao chép từ tôi. Tuy nhiên, về cơ bản họ nói cùng một - tôi ngầm giải quyết các hành vi khác nhau với sự chậm trễ với câu "Lúc đầu ...". ;) – Lucero

Các vấn đề liên quan