Maybe this is a very simple question but I did not find an answer to that. I use boost asios tcp class for handling a simple byte protocol. I do async_read_some and the handler does some work. After the handler has been completed I start another async_read_some. Let's assume this handler does a lot of computing. Is there any posibility that incoming data between the handler work and the next call to async_read_some get lost?
No, your OS would continue receiving data until its receive buffers/TCP receive window are full. Once the receive buffer is full, TCP's flow control will make sure that the sender doesn't send more data than the receiver can receive and such no data will be lost.
See https://www.brianstorti.com/tcp-flow-control/ for a good explanation/example.
https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_control
Related
I'm trying to create a server with blocking sockets (one new thread for each new client). This thread should be able to receive commands from the client (and send back the result) and periodically send commands to the client (and request back the result).
What I've thought is creating two threads for each client, one for recv, second for send. However:
it's double of the normal thread overhead.
due to request/response design, recv I do in the first thread (to wait for client's commands) can be the request I look for in the second thread (client's result to my send) and vice versa. Making it all properly synced is probably a hell story. So now I'm thinking to do that from a single thread this way:
In a loop:
setsockopt(SO_RCVTIMEO, &small_timeout); // set the timeout for the recv (like 1000 ms).
recv(); // check for client's requests first. if returns WSAETIMEDOUT than I assume no data is requested and do nothing. if I get a normal request I handle it.
if (clientbufferToSend != nullptr) send(clientbufferToSend); // now when client's request has been processed we check the command list we have to send to the client. if there is commands in queue, we send them. SO_SNDTIMEO timeout can be set to a large value so we don't deadlock if client looses connection.
setsockopt(SO_RCVTIMEO, &large_timeout); // set the timeout for the recv (as large as SO_SNDTIMEO, just to not deadlock if anything).
recv(); // now we wait the response from the client.
Is this the legal way to do what I want? Or are there better alternatives (preferrably with blocking sockets and threads)?
P.S. Does recv() with timeout returns WSAETIMEDOUT only if no data is available? Can it return this error if there is the data, but recv() wasn't fast enough to handle it all, thus returning partial data?
One approach is only create a background thread for reading from that socket. Write on whatever random thread your unsolicited events are raised.
You’ll need following stuff.
A critical section or mutex per socket to serialize writes, like when background thread is sending response to client-initiated message, and other thread wants to send message to the same client.
Some other synchronization primitive like a conditional variable for client thread to sleep while waiting for responses.
The background thread which receives messages needs to distinguish client-initiated messages (which need to be responded by the same background thread) from responses to server-initiated messages. If your network protocol doesn’t have that data you’ll have to change the protocol.
This will work OK if your server-initiated events are only happening on a single thread, e.g. they come from some serialized source like a device or OS interface.
If however the event source is multithreaded as well, and you want good performance, you gonna need non-trivial complexity to dispatch the responses to the correct server thread, like 1 conditional variable per client thread, maybe some queues, etc.
I want to increase the throughput of my udp gameserver which uses Boost ASIO.
Right now, everytime i need to send a packet, i am putting it in a queue, then checking if there is a pending async_send_to operation, if yes, do nothing, if not, call async_send_to.
Then i wait for the write handler to be called and then call async_send_to for the next packet in queue, if any.
The documentation says that it is the way to do it "for TCP socket", but there is NOTHING on the whole internet about UDP socket.
Try it, search it on stackoverflow, you will see nobody talks about this, and for the 2 questions you will find, the question is left ignored by users.
Why is it kept a secret?
And for the 1million dollar question, can i safely call async_send_to multiple time in a row WITHOUT waiting for the write handler to be called?
Thanks in advance.
This logic is meaningless for the UDP protocol since it doesn't need to block send operation. A datagram is either delivered or lost. UDP don't have to store it in the output buffer and resend indefinitely many times until it get ACK packet.
No, you cannot safely call async_send_to multiple times in a row WITHOUT waiting for the write handler to be called. See Asynchronous IO with Boost.Asio to see precisely why.
However, asio supports scatter gather and so you can call async_send_to with multiple buffers, e.g.:
typedef std::deque<boost::asio::const_buffer> ConstBuffers;
std::string msg_1("Blah");
...
std::string msg_n("Blah");
ConstBuffers buffers;
buffers.push_back(msg_1);
...
buffers.push_back(msg_n);
socket_.async_send_to(buffers, tx_endpoint_, write_handler);
So you could increase your throughput by double buffering your message queue and using gathered writes...
In my socket communication I have a server where at each connection I want to read data first and after I finished reading, I want to write a response. However I want to do it asynchronously, so I can process many incoming connections. The problem with async_read and async_write is, that obviously they are asynchronous and when I start to read, the write operation immediately starts too.
So basically my question is:
How to start reading from a socket, then interrupt reading (when I decided by the communication protocol that all data has been sent) and then start writing and finally close the socket?
Concerning the second part of your question, look for example at this link.
The async_read function has the parameters CompletionCondition completion_condition and ReadHandler handler. These are callbacks. The completion condition should return 0 if you decide that you've read everything you need. Once you are done reading, the handler callback is called. You can call async_write from the handler.
Hi I'm working on a networking project. I've a socket that is listening incoming data. Now I want to archive this: Socket will receive only 100 packets. And there is 3-4 clients. They are sending random data packets infinitely. I'll receive 100 packets and later I'll process them. After process I'll re-start receiving. But at this time there are some pending send() >> recv() operations. Now I want to cancel/discard pending recv operations. I think we'll recv datas and we'll not process them. Any other suggestions? (sorry for bad question composition)
Shutdown and close the connection. That will cancel everything immediately.
Better yet, rearchitect your application and network protocol so that you can reliably tell how much data to receive.
On Windows you can cancel outstanding receives using CancelIO, but that might result in lost data if the receive just happened to read something.
You can use select() or poll() loops.
you can use signal. recv() will return on receiving a signal so you can send a signal from another task to the task that blocks on recv(). But you need to make sure you don't specify SA_RESTART (see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html)
Read http://en.wikipedia.org/wiki/Asynchronous_I/O for more details
I would go with non-blocking sockets + cancellation socket.
You'll have to read into dedicated incremental buffer (as recv() may not receive all the data expected at once - this would be the case if you can only process full messages) and return to select()/poll() in your loop, where you can safely sit and wait for:
next data
next connection
cancellation event from a cancellation socket, to which your other thread will send a cancellation signal (some trivial send()).
UPD: the trivial event may be the number of the socket in the array or its handle - something to identify which one you'd like to cancel.
I'm using boost::asio and sending a list to a client and closing the socket when finished. Somehow the client sometimes gets an End Of File error before he has received everything.
I'm guessing this has to do with the server closing the socket right after sending the last list entry. Is there an easy way to solve this async_send to call the handler only after the data has been successfully sent?
Or is my End Of File error coming from something else?
Boost.Asio is an operating system independent abstraction layer over TCP and UDP sockets. They provide no guarantee that the other application has received and processed the data. You will need to include this logic in your application, you may want to study the OSI model.
If you're closing the socket immediately after async_send() returns, this is incorrect. You should close it only after the completion handler is invoked.