How to get over 65000 bytes in a C ++ socket using recv ()

I am developing a client server application (TCP) on Linux using C ++. I want to send more than 65,000

bytes at a time. In TCP, the maximum packet size is 65,535

only bytes.

How can I send all bytes losslessly?

Below is my server side code.

//Receive the message from client socket
if((iByteCount = recv(GetSocketId(), buffer, MAXRECV, MSG_WAITALL)) > 0) 
{
     printf("\n Received bytes %d\n", iByteCount);

     SetReceivedMessage(buffer);
     return LS_RESULT_OK;
}

      

If I use MSG_WAITALL

, it takes a long time to receive bytes, so how can I set the flag to receive more than 1 million bytes at a time.

Edit: MTU size is 1500 bytes, but the absolute limit on TCP packet size if 65535.

+3


source to share


4 answers


Your problem may be related to the kernel buffer sizes. Try adding the following to your code:

int buffsize = 1024*1024;
setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize));

      

You may need to increase some sysctl variables as well:



sysctl -w net.core.rmem_max=8388608
sysctl -w net.core.wmem_max=8388608

      

Note, however, that using TCP to fill your entire buffer is generally a bad idea. You should rather call recv () multiple times. The only good reason you want more than 64K is for improved performance. However, Linux should already have autotuning, which will incrementally increase buffer sizes as needed.

+3


source


Based on the comments above, you don't seem to understand how it works recv

or how it should be used.

You really want to call recv

in a loop until you know the expected amount of data has been received, or until you get a "zero read byte" result, which means the other end has closed the connection. Always, no exceptions.

If you need to do other things at the same time (probably with the server process!), You probably want to first check that the descriptor is ready with poll

or epoll

. This allows you to multiplex the sockets as they become available.

The reason you want to do it this way is never different from the fact that you don't know how the data will be sent and how (or when) the packets will arrive. In addition, recv

it makes no guarantees as to the amount of data read at a time. It will offer what it has in its buffers at the time you call it, no more and no less (it can block if there is nothing there, but then you still have no guarantee that any particular the amount of data will be returned when it resumes, it might still return, for example 50 bytes!).

Even if you are only sending, say, only 5000 bytes, it is perfectly correct for TCP to split it into 5 (or 10 or 20) packets, and for recv

- 500 (or 100 or 20), or 1) bytes at a time, each time when you call it. This is how it works.
TCP makes sure that whatever you send will eventually reach the other end or result in an error. And it makes sure that everything you send comes in order. This does not guarantee anything else. First of all, it does not guarantee that any particular amount of data will be ready at any given time. You must be prepared for this, and the only way to do this is to call recv

multiple times. Otherwise, you will always lose data under some circumstances.

MSG_WAITALL

should in principle make it work as you expect, but this is bad behavior and is not guaranteed. If the socket (or some other structure in the networking stack) operates on a soft or hard limit, it may not match your request. Some of the limitations are also unclear. For example, the number for SO_RCVBUF

should be twice as large as you would expect in Linux due to implementation details.



The correct behavior of a server application should never depend on assumptions such as "it fits into the receive buffer". Your application should be prepared, in principle, to receive terabytes of data using a 1 kilobyte receive buffer and, in the case of 1 byte blocks at a time, if required. A larger receive buffer will make it more efficient, but what does it ... it should still work anyway.

The fact that you only see dips above some "huge" limit is just luck (or rather, bad luck). The fact that it appears to "work fine" up to this limit suggests that you are doing the right thing, but it is not. It's an unfortunate coincidence that it works.

EDIT:
As requested in the comment below, this is what it might look like (Code is clearly untested, beware of emptor.)

std::vector<char> result;
int size;

char recv_buf[250];

for(;;)
{
    if((size = recv(fd, recv_buf, sizeof(recv_buf), 0)) > 0)
    {
        for(unsigned int i = 0; i < size; ++i)
            result.push_back(recv_buf[i]);
    }
    else if(size == 0)
    {
        if(result.size() < expected_size)
        {
            printf("premature close, expected %u, only got %u\n", expected_size, result.size());
        }
        else
        {
            do_something_with(result);
        }
        break;
    }
    else
    {
        perror("recv");
        exit(1);
    }
}

      

This will receive any amount of data you want (or it operator new

doesn't throw away a bad_alloc

few hundred megabytes after the vector is allocated, but that's another story ...).

If you want to handle multiple connections, you need to add poll

either epoll

or kqueue

or similar functionality (or ... fork

), I'll leave that as an exercise for the reader.

+6


source


in tcp max package sixe is 65635, bytes

No, it is not. TCP is a byte-stream byte-stream protocol over IP packets, and the protocol has unlimited transmission sizes over any one connection. Look at all these 100MB downloads: how do you think they work?

Just send and receive data. You will receive it.

+3


source


I would suggest looking into kqueue or something similar. When notifying an event, there is no need for a loop on recv

. Just call the read function on event EV_READ

and use one function call recv

on the socket that raised the event. Your function can have a buffer size of 10 bytes or how much you want, it doesn't matter because if you didn't read the whole message the first time, you just get another EV_READ event on the socket and you remember your read function when the data is read, you will receive an EOF event. No need to fuss with loops that may or may not block other incoming connections.

0


source







All Articles