I love seeing that there's a cross-platform standard for TCP/IP sockets emerging for C++ in boost. And so far I've been able to find help for all topics I've run into. But now I'm stuck on an odd behavior. I'm developing using Xcode 7.3.1 on an late-2013 iMac.
I'm developing a simple web server for a special purpose. The code below is a pared down version that demonstrates the bad behavior:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
int main(int argc, const char * argv[]) {
static asio::io_service ioService;
static tcp::acceptor tcpAcceptor(ioService, tcp::endpoint(tcp::v4(), 2080));
while (true) {
// creates a socket
tcp::socket* socket = new tcp::socket(ioService);
// wait and listen
tcpAcceptor.accept(*socket);
asio::streambuf inBuffer;
istream headerLineStream(&inBuffer);
char buffer[1];
asio::read(*socket, asio::buffer(buffer, 1)); // <--- Yuck!
asio::write(*socket, asio::buffer((string) "HTTP/1.1 200 OK\r\n\r\nYup!"));
socket->shutdown(asio::ip::tcp::socket::shutdown_both);
socket->close();
delete socket;
}
return 0;
}
When I access this service, under a certain set of conditions, the browser will choke for upwards of 20 seconds. If I pause the program running in debug mode, I can see that the asio::read() call is blocking. It's literally waiting for even a single character to appear from the browser. Why is this?
Let me clarify, because what I have to do to reproduce this on my machine is strange. Once I start the program (for debugging), I open the "page" from Chrome (as http://localhost:2080/). I can hit Refresh many times and it works just fine. But then I use Firefox (or Safari) and it hangs for maybe 20 seconds, whence the page shows up as expected. Now get this. If, during that delay in Firefox, I hit Refresh in Chrome, the Firefox page shows up immediately, too. In another experiment, I hit Refresh in Chrome (works fine) and then hit Refresh in both Firefox and Safari. Both of them hang. I hit Refresh in Chrome and all 3 show up immediately.
In a change to this experiment, as soon as I start this program, I hit Refresh in either Firefox or Safari and they work just fine. No matter how many times I refresh. And going back and forth between them. I'm literally holding down CMD-R to rapid-fire refresh these browsers. But as soon as I refresh Chrome on the same page and then try refreshing the other two browsers, they hang again.
Having done web programming since around 1993, I know the HTTP standard well. The most basic workflow is that the browser initiates a TCP connection. As soon as the web server accepts the connection, the client sends an HTTP header. Something like "GET /\r\n\r\n" for the root page ("/"). The server typically reads all the header lines and stops until it gets to the first blank line, which signals the end of the headers and beginning of the uploaded content (e.g., POSTed form content), which the web application is free to consume or ignore. The server responds when it is ready with its own HTTP headers, starting typically with "HTTP/1.1 200 OK\r\n", followed by the actual page content (or binary file contents, etc).
In my app, I'm actually using asio::read_until(*socket, inBuffer, "\r\n\r\n") to read the entire HTTP header. Since that was hanging, I thought maybe those other browsers were sending corrupt headers or something. Hence my trimming down of the sample to just reading a single character (should be the "G" in "GET /"). One single character. Nope.
As a side note, I know I'm doing this synchronously, but I really wanted a simple, linear demo to show this bad behavior. I'm assuming that's not what's causing this problem, but I know it's possible.
Any thoughts here? In my use case, this is sufferable, since the server does eventually respond, but I'd really rather understand eliminate this bad behavior.
It seems this results from a design quirk in Chrome. See this post:
server socket receives 2 http requests when I send from chrome and receives one when I send from firefox
I see what's happening now. Chrome makes 2 connection requests. The first is for the desired page and contains a proper request HTTP header. The second connection, once accepted, does not contain even a single byte of input data. So my attempt to read that first byte goes unrewarded. Fortunately, the read attempt times out. That's easy enough to recover from with a try/catch.
This appears to be a greedy optimization to speed up Chrome's performance. That is, it holds the next connection open until the browser needs something from the site, whence it sends the HTTP request on that open socket. It then immediately opens a new connection, again in anticipation of a future request. Although I get how this speeds Chrome's experience up, this seems a dubious design because of the added burden it places on the server.
This is a good argument for opening a separate thread to handle each accepted socket. A thread could patiently hang out waiting for the never-forthcoming request while other threads handle other requests. To that end, I wrapped up everything after tcpAcceptor.accept(*socket); in a new thread so the loop can continue waiting for the next request.
Related
I have some application-level security measures. I'd like to just kill the client connection if we suspect that the current request is suspicious rather than returning a proper response. To produce an ambiguous response to the client that seeks to avoid an outright acknowledgement that they found a webserver. What about being able to call a function right when the incoming connection is accepted and the header bytes are first read? I've tried to just close the request stream from a before_request function or close the response stream in a after_request function, but the former has no effect and the latter will just close the socket after already having written the status and headers.
I did a heavy number of searches into both the lifecycles of Flask and Werkzeug, but didn't turn up anything. It seems like no one has ever asked the connection-abort question before.
It seems like I should be able to catch where the start_response callback is called by Flask and either write my own or intercept it and return my own no-op write function so that the client connection is effectively never acted on, but this requires more research. I couldn't seem to find anywhere in Flask or Werkzeug that actually calls start_response or anything that might refer to this by an alternate name before I ran out of time to look.
Reference: https://github.com/pallets/werkzeug/blob/c7ae2fea4fb229ffd71187c2b665874c91b96277/src/werkzeug/serving.py#L250
We're working with a C++ webrtc data channels library and in our test application, upon sending a few small packets that would totally amount to about 256kB, the usrsctp_sendv() call returns -1 (with errno as EWOULDBLOCK/EAGAIN which means "Resource is temporarily unavailable"). We believe this is because we're hitting the usrsctp's send buffer limit, which is 256 kB by default. We've tried adding several sleep delays in between each send call hoping it clears that buffer, but nothing works.
The receiving side, (a JS web page) does indeed receive all the bytes that we've sent up until it errors out. It's also worth noting that this only happens when we try to send data from the C++ application to the JS and not the other way around. We tried looking around mozilla's datachannels implementation, but can't seem to draw any conclusions on what the issue could be about.
It is hard to answer such question straight away. I would start looking into wireshark traces in order to see if your remote side (JS page) actually acknowledges data you send (e.i. if SACK chunks are sent back) and what is the value of received buffer (a_rwnd) reported in these SACKs. It might be possible that it is not an issue on your side, but you are getting EWOULDBLOCKS just because sending side SCTP cannot flush the data from buffers because it is still awaiting for delivery confirmation from remote end.
Please provide more details about your case, also if this is possible provide sample code for your JS page.
I am creating a network client application that sends requests to a server using a QTcpSocket and expects responses in return. No higher protocol involved (HTTP, etc.), they just exchange somewhat simple custom strings.
In order to test, I have created a TCP server in Python that listens on a socket and logs the strings it receives and those it sends back.
I can send the first request OK and get the expected response. However, when I send the second request, it does not seem to get written to the network.
I have attached debug slots to the QTcpSocket's notification signals, such as bytesWritten(...), connected(), error(), stateChanged(...), etc. and I see the connection being established, the first request sent, the first response processed, the number of bytes written - it all adds up...
Only the second request never seems to get sent :-(
After attempting to send it, the socket sends an error(RemoteHostClosedError) signal followed by ClosingState and UnconnectedState state change signals.
Before I go any deeper into this, a couple of (probably really basic) questions:
do I need to "clear" the underlying socket in any way after reading ?
is it possible / probable that not reading all the data the server has sent me prevents me from writing ?
why does the server close the connection ? Does it always do that so quickly or could that be a sign that something is not right ? I tried setting LowDelay and KeepAlive socket options, but that didn't change anything. I've also checked the socket's state() and isValid() and they're good - although the latter also returns true when unconnected...
In an earlier version of the application, I closed and re-opened the connection before sending a request. This worked ok. I would prefer keeping the connection open though. Is that not a reasonable approach ? What is the 'canonical' way to to implement TCP network communication ? Just read/write or re-open every time ?
Does the way I read from the socket have any impact on how I can write to it ? Most sample code uses readAll(...) to get all available data; I read piece by piece as I need it and << to a QTextStream when writing...
Could this possibly be a bug in the Qt event loop ? I have observed that the output in the Qt Creator console created with QDebug() << ... almost always gets cut short, i.e. just stops. Sometimes some more output is printed when I shut down the application.
This is with the latest Qt 5.4.1 on Mac OS X 10.8, but the issue also occurs on Windows 7.
Update after the first answer and comments:
The test server is dead simple and was taken from the official Python SocketServer.TCPServer Example:
import SocketServer
class MyTCPHandler(SocketServer.StreamRequestHandler):
def handle(self):
request = self.rfile.readline().strip()
print "RX [%s]: %s" % (self.client_address[0], request)
response = self.processRequest(request)
print "TX [%s]: %s" % (self.client_address[0], response)
self.wfile.write(response)
def processRequest(self, message):
if message == 'request type 01':
return 'response type 01'
elif message == 'request type 02':
return 'response type 02'
if __name__ == "__main__":
server = SocketServer.TCPServer(('localhost', 12345), MyTCPHandler)
server.serve_forever()
The output I get is
RX [127.0.0.1]: request type 01
TX [127.0.0.1]: response type 01
Also, nothing happens when I re-send any message after this - which is not surprising as the socket was closed. Guess I'll have to figure out why it is closed...
Next update:
I've captured the network traffic using Wireshark and while all the network stuff doesn't really tell me a lot, I do see the first request and the response. Right after the client [ACK]nowledges the response, the server sends a Connection finish (FIN). I don't see the second request anywhere.
Last update:
I have posted a follow-up question at Python: SocketServer closes TCP connection unexpectedly.
Only the second request never seems to get sent :-(
I highly recommend running a program like WireShark and seeing what packets are actually getting sent and received across the network. (As it is, you can't know for sure whether the bug is on the client side or in the server, and that is the first thing you need to figure out)
do I need to "clear" the underlying socket in any way after reading ?
No.
is it possible / probable that not reading all the data the server has
sent me prevents me from writing ?
No.
why does the server close the connection ?
It's impossible to say without looking at the server's code.
Does it always do that so quickly or could that be a sign that
something is not right ?
Again, this would depend on how the server was written.
This worked ok. I would prefer keeping the connection open though. Is
that not a reasonable approach ?
Keeping the connection open is definitely a reasonable approach.
What is the 'canonical' way to to implement TCP network communication
? Just read/write or re-open every time ?
Neither was is canonical; it depends on what you are attempting to accomplish.
Does the way I read from the socket have any impact on how I can write
to it ?
No.
Could this possibly be a bug in the Qt event loop ?
That's extremely unlikely. The Qt code has been used for years by tens of thousands of programs, so any bug that serious would almost certainly have been found and fixed long ago. It's much more likely that either there is a bug in your client, or a bug in your server, or a mismatch between how you expect some API call to behave and how it actually behaves.
I am using gsoap for Symbian S60 3rd Edition FP2 in a Qt application. I am making several requests to a WS every 5 seconds. After 2 hours the application stops being able to connect to the WS and I get this Error 28: SOAP_TCP_ERROR from gsoap. If I stop the application and start it again it is able to connect to the WS again. Why is this happening?
I've put the gsoap WS call in a for loop and it stops connecting to the WS at the 892th time, every time I run it.
You can do several things as a prework:
enable DBGLOG at gsoap
use soap_faultdetail at client side.
I'm 99% sure that it will give you a tcp connection timeout error which means that connection handshake has just failed.
If it is so, it means that WS has not accepted the connection for some reason. The source of problems might lay somewhere between proxy/firewall/os/buggy ws/driver to name just few of them. Because of that, one can use reconnection attempt. I'm not familiar with symbian, but in the windows OS reconnection is performed behind the scenes:
see: https://technet.microsoft.com/en-us/library/cc938209.aspx
By default, reconnection attempt is made twice but this behaviour could be changed either by registry parameter, driver or winsock.
I think you have to write explicit connection-retry subroutine at your application level and force gSOAP to use it (see hooks section at gSOAP documentations) or just call soap_connect couple of times if it returns error.
NOTE: introduction of connection_timeout at gsoap level may be confusing.
If you will decide to put this one (if you do not already have this) in your code, perform some tests wether the reconnection attempt is really perfomed within this timeout or not.
What I'm just trying to say is that your application could set timeout to 30 minutes, but your OS will put SYN packet into the WS host just couple of times within let's say couple of first seconds. If the WS host will not respond with SYN-ACK for some reason, your gsoap's tcp_connect subroutine will fall into 30minutes waste-of-time-loop.
I recently starting diving into http programming in C and have a functioning server that can handle GET and POST. My question comes in to my site load times and how I should send the response headers and response message.
I notice in Chromes resource tracking tool that there is almost no (a few ms) connecting/sending/proxy/blocking/waiting time in most cases (on the same network as the server), but the receive time can vary wildly. I'm not entirely sure what the receive time is including. I mostly see a long receive (40 to 140ms or more) time on the png files and sometimes javascript files and rarely other files, but it's not really consistent.
Could anyone shed some light on this for me?
I haven't done much testing yet, but I was wondering if I changed the method which I use to send the header/message would help. I currently have every file for the site cached in server memory along with it's header (all in the same char*). When I send the file that was requested, I just do 1 send() call with the header/file combo (it does not involve any string operations b/c it is all done in advance on server start up).
Would it be better to break it into multiple small send() calls?
Just some stats that I get with Chrome dev tools (again, on local network through a wireless router connection), the site loads in from 120ms to 570ms. It's 19 files at a total of 139.85KB. The computer it's on is a Asus 901 netbook (atom 1.6ghz, 2gb ddr2) with TinyCore linux. I know there are some optimizations I could be doing with how threads start up and a few other things, but not sure that's affecting it to much atm.
If you're sending the entire response in one send(), you should set the TCP_NODELAY socket option.
If that doesn't help, you may want to try using a packet capturing tool like Wireshark to see if you can spot where the delay is introduced.