I use the .NET UDPClient often and I have always used the Socket.ReceiveBufferSize and have good results. Internally it calls Socket.SetSocketOption with the ReceiveBuffer parameter. Here is a some quick, simple, code you can test with:
public static void Main(string[] args)
{
IPEndPoint remoteEp = null;
UdpClient client = new UdpClient(4242);
client.Client.ReceiveBufferSize = 4096;
Console.Write("Start sending data...");
client.Receive(ref remoteEp);
Console.WriteLine("Good");
Thread.Sleep(5000);
Console.WriteLine("Stop sending data!");
Thread.Sleep(1500);
int count = 0;
while (true)
{
client.Receive(ref remoteEp);
Console.WriteLine(string.Format("Count: {0}", ++count));
}
}
Try adjusting the value passed into the ReceiveBufferSize. I tested sending a constant stream of data for the 5 seconds, and got 10 packets. I then increased x4 and the next time got 38 packets.
I would look to other places in your network where you may be dropping packets. Especially since you mention on your other post that you are sending 10KB packets. The 10KB will be fragmented when it is sent to packets the size of MTU. If any 1 packet in the series is dropped the entire packet will be dropped.
How can I know if after calling recv
first time the read buffer is empty or
not? If it's not empty I would have to
call recv again, but if I do that when
it's empty I would have it blocking
for much time.
You can use the select
or poll
system calls along with your socket descriptor to tell if there is data waiting to be read from the socket.
However, usually there should be an agreed-upon protocol that both sender and receiver follow, so that both parties know how much data is to be transferred. For example, perhaps the sender first sends a 2-byte integer indicating the number of bytes it will send. The receiver then first reads this 2-byte integer, so that it knows how many more bytes to read from the socket.
Regardless, as Tony pointed out below, a robust application should use a combination of length-information in the header, combined with polling the socket for additional data before each call to recv
, (or using a non-blocking socket). This will prevent your application from blocking in the event that, for example, you know (from the header) that there should still be 100 bytes remaining to read, but the peer fails to send the data for whatever reason (perhaps the peer computer was unexpectedly shut off), thus causing your recv
call to block.
How can I know how many bytes I have
readed into recv_buffer? I can't use
strlen because the message I receive
can contain null bytes.
The recv
system call will return the number of bytes read, or -1 if an error occurred.
From the man page for recv(2):
[recv] returns the number of bytes
received, or -1 if an error occurred.
The return value will be 0 when the
peer has performed an orderly
shutdown.
Best Answer
The answers to these questions vary depending on whether you are using a stream socket (
SOCK_STREAM
) or a datagram socket (SOCK_DGRAM
) - within TCP/IP, the former corresponds to TCP and the latter to UDP.How do you know how big to make the buffer passed to
recv()
?SOCK_STREAM
: It doesn't really matter too much. If your protocol is a transactional / interactive one just pick a size that can hold the largest individual message / command you would reasonably expect (3000 is likely fine). If your protocol is transferring bulk data, then larger buffers can be more efficient - a good rule of thumb is around the same as the kernel receive buffer size of the socket (often something around 256kB).SOCK_DGRAM
: Use a buffer large enough to hold the biggest packet that your application-level protocol ever sends. If you're using UDP, then in general your application-level protocol shouldn't be sending packets larger than about 1400 bytes, because they'll certainly need to be fragmented and reassembled.What happens if
recv
gets a packet larger than the buffer?SOCK_STREAM
: The question doesn't really make sense as put, because stream sockets don't have a concept of packets - they're just a continuous stream of bytes. If there's more bytes available to read than your buffer has room for, then they'll be queued by the OS and available for your next call torecv
.SOCK_DGRAM
: The excess bytes are discarded.How can I know if I have received the entire message?
SOCK_STREAM
: You need to build some way of determining the end-of-message into your application-level protocol. Commonly this is either a length prefix (starting each message with the length of the message) or an end-of-message delimiter (which might just be a newline in a text-based protocol, for example). A third, lesser-used, option is to mandate a fixed size for each message. Combinations of these options are also possible - for example, a fixed-size header that includes a length value.SOCK_DGRAM
: An singlerecv
call always returns a single datagram.Is there a way I can make a buffer not have a fixed amount of space, so that I can keep adding to it without fear of running out of space?
No. However, you can try to resize the buffer using
realloc()
(if it was originally allocated withmalloc()
orcalloc()
, that is).