locked
UDP blocking and non-blocking - like recvfrom

    Kérdés

  • Hi!
    I've read and tried all the examples about UDP communications.  I'm still having trouble converting a C/C++ application using <winsock2.h> and recvfrom to a .Net application using C#.  Here's the recvfrom documentation - I haven't found a way to implement in C#:

    The recvfrom function reads incoming data on both connected and unconnected sockets and captures the address from which the data was sent. This function is typically used with connectionless sockets. The local address of the socket must be known. For server applications, this is usually done explicitly through bind...

    For message-oriented sockets, data is extracted from the first enqueued message, up to the size of the buffer specified. If the datagram or message is larger than the buffer specified, the buffer is filled with the first part of the datagram, and recvfrom generates the error WSAEMSGSIZE. For unreliable protocols (for example, UDP) the excess data is lost.

    If the from parameter is nonzero and the socket is not connection oriented, (type SOCK_DGRAM for example), the network address of the peer that sent the data is copied to the corresponding sockaddr structure. The value pointed to by fromlen is initialized to the size of this structure and is modified, on return, to indicate the actual size of the address stored in the sockaddr structure.

    If no incoming data is available at the socket, the recvfrom function blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking. In this case, a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK...

    If the socket is connection oriented and the remote side has shut down the connection gracefully, the call to recvfrom will complete immediately with zero bytes received. If the connection has been reset recvfrom will fail with the error
    WSAECONNRESET.

    =====================================================================================

    See continuation below...
    Thanks!


    Mechi

    • Szerkesztette: MechiF 2008. július 21. 6:17 edit
    2008. július 20. 9:28

Válaszok

  • Hi!
    I found a bug that partially fixed the handshake problem.
    For some reason I found that I had to Close() the client.  So, when I re-instantiated the client, a new port number was used.
    Now, I reinstantiate the client with the original port number - so all messages sent and received from the PC all use the same port.

    udpClient.Connect(IPAddress.Parse(mmIPaddr), conPort);
    IPEndPoint localEndPoint = (IPEndPoint)udpClient.Client.LocalEndPoint;
    udpLocalPort = (UInt16)localEndPoint.Port;
    .....
    .....
    udpClient.Close();
    udpClient = new UdpClient(udpLocalPort);

    I still have to figure out why I thought I had to Close the client each Send/Recv.

    Since I set the ReceiveTimeout, I catch the Timeout exception after every Receive:

    rcvdMsg = new byte[MAX_BYTES];
    udpClient.Client.ReceiveTimeout = 100;
    try
    {
        rcvdMsg = udpCliRcv.Receive(ref UDPremote);
    }
    catch (SocketException e) // timed out
    {
        PutMessageOnForm("UdpConnect SocketException: " + e.SocketErrorCode.ToString());
    }

    I hope this helps someone...

    Mechi


    Mechi
    • Megjelölte válaszként: MechiF 2008. július 22. 11:09
    2008. július 22. 10:59

Az összes válasz

  • Hi!
    Now I think I have UDP questions similar to JakeSee (in http://forums.msdn.microsoft.com/en-US/netfxnetcom/thread/378891ae-b1ed-4ba5-a104-23fee5fe8f43)

    When I look at the sniffer on the PC - all UDP messages sent and received, I see that messages have been received even before I send the "handshake" in step 3 above.  I guess the scenario has to be made clearer:

    1. simClient sends message to MiddleMan that wants to connect to a specific device
    2. MiddleMan returns device IP address and port to simClient and to device
    3. simClient sends messages to IP address and port of device and device similarly sends to simClient
    4. simClient waits for answer from device and then establishes P2P (peer-to-peer) communication with device

    After calling BeginReceive, simClient waits with a loop for packetsReceived == trueIf no data arrives, how can I determine if it's because of WSAEWOULDBLOCK (no data received) or WSAECONNRESET (connection reset)?

    The application usually gets past steps 1,2 & 3 - but doesn't receive the messages in step 4 - even though the sniffer on the PC shows that messages have arrived.

    What's happening is that before step 3 finishes (simClient sends UDP messages to internal and external IP addresses of device to ports received in Step 2), the message that simClient waits for in Step 4 is already received. 

    Why, when I do the BeginReceive in Step 4 doesn't the callback function automatically return with the response that was already received?  Or, since it was received beforehand, it was thrown away? 
    Is there any buffer for UDP messages?  
    Now I do the BeginReceive before Step 3 and if something of interest is received, leave Step 3 and continue to Step 4 with the answer... But still I'm not getting the messages that are coming in.  In the callback function, I receive from IP_ANY (any address, any port).

    Thanks for any help!


    Mechi
    • Szerkesztette: MechiF 2008. július 21. 6:18 added
    2008. július 20. 13:15
  • Hi Mech,

    Thanks for the updates.

    [QUOTE]
    There is always the possibility that a connection has been reset - so I can't use a blocking udpClient.Receive unless there's a way to specify a timeout (which I haven't found anywhere)
    [/QUOTE]

    Actually it is possible to set a timeout using the underlying socket object:

    UdpClient Broadcaster = new UdpClient();  
    Broadcaster.Client.ReceiveTimeout = 2000; 

    But the problem of an apparently missing message buffer causes additional messages to be dropped after the recieve. Unlike TCP sockets, you CANNOT do a while(available) loop to get all the mesages in the queue that are recieved during the current message processing code block.


    Jake
    Jake See
    • Megjelölte válaszként: MechiF 2008. július 21. 6:10
    • Válaszként való megjelölést visszavonta: MechiF 2008. július 21. 6:10
    2008. július 20. 15:02
  • Jake - Thanks!
    This definitely helps!
    I hope someone has ideas how to implement the socket-level function of recvfrom, sendto...
    Take care,
    Mechi
    2008. július 21. 6:19
  • Hi!
    I found a bug that partially fixed the handshake problem.
    For some reason I found that I had to Close() the client.  So, when I re-instantiated the client, a new port number was used.
    Now, I reinstantiate the client with the original port number - so all messages sent and received from the PC all use the same port.

    udpClient.Connect(IPAddress.Parse(mmIPaddr), conPort);
    IPEndPoint localEndPoint = (IPEndPoint)udpClient.Client.LocalEndPoint;
    udpLocalPort = (UInt16)localEndPoint.Port;
    .....
    .....
    udpClient.Close();
    udpClient = new UdpClient(udpLocalPort);

    I still have to figure out why I thought I had to Close the client each Send/Recv.

    Since I set the ReceiveTimeout, I catch the Timeout exception after every Receive:

    rcvdMsg = new byte[MAX_BYTES];
    udpClient.Client.ReceiveTimeout = 100;
    try
    {
        rcvdMsg = udpCliRcv.Receive(ref UDPremote);
    }
    catch (SocketException e) // timed out
    {
        PutMessageOnForm("UdpConnect SocketException: " + e.SocketErrorCode.ToString());
    }

    I hope this helps someone...

    Mechi


    Mechi
    • Megjelölte válaszként: MechiF 2008. július 22. 11:09
    2008. július 22. 10:59