]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add an interface to set the TCP_NODELAY flag on an IOStream.
authorBen Darnell <ben@bendarnell.com>
Sun, 5 May 2013 01:50:31 +0000 (21:50 -0400)
committerBen Darnell <ben@bendarnell.com>
Sun, 5 May 2013 01:55:08 +0000 (21:55 -0400)
Use this flag from simple_httpclient (always) and httpserver (when a complete
response is available), and add an accessor for WebSocketHandler.

Also make simple_httpclient send headers and body in a single
IOStream.write call.

tornado/httpserver.py
tornado/iostream.py
tornado/simple_httpclient.py
tornado/websocket.py

index c6488bce5f958c355be281ab739a6ab8f7c5dd97..11f083299eeec9ec696caf133aaa9978c4bb40a4 100644 (file)
@@ -235,6 +235,9 @@ class HTTPConnection(object):
     def finish(self):
         """Finishes the request."""
         self._request_finished = True
+        # No more data is coming, so instruct TCP to send any remaining
+        # data immediately instead of waiting for a full packet or ack.
+        self.stream.set_nodelay(True)
         if not self.stream.writing():
             self._finish_request()
 
@@ -276,6 +279,10 @@ class HTTPConnection(object):
             # directly, because in some cases the stream doesn't discover
             # that it's closed until you try to read from it.
             self.stream.read_until(b"\r\n\r\n", self._header_callback)
+
+            # Turn Nagle's algorithm back on, leaving the stream in its
+            # default state for the next request.
+            self.stream.set_nodelay(False)
         except iostream.StreamClosedError:
             self.close()
 
index ad395f0e2df91879cda903c5ef948708975a5326..064193dee2ef52cfb9dc8147b85ee739aac351ed 100644 (file)
@@ -273,6 +273,19 @@ class BaseIOStream(object):
         """Returns true if the stream has been closed."""
         return self._closed
 
+    def set_nodelay(self, value):
+        """Sets the no-delay flag for this stream.
+
+        By default, data written to TCP streams may be held for a time
+        to make the most efficient use of bandwidth (according to
+        Nagle's algorithm).  The no-delay flag requests that data be
+        written as soon as possible, even if doing so would consume
+        additional bandwidth.
+
+        This flag is currently defined only for TCP-based ``IOStreams``.
+        """
+        pass
+
     def _handle_events(self, fd, events):
         if self.closed():
             gen_log.warning("Got events for closed stream %d", fd)
@@ -726,6 +739,12 @@ class IOStream(BaseIOStream):
             self._run_callback(callback)
         self._connecting = False
 
+    def set_nodelay(self, value):
+        if (self.socket is not None and
+            self.socket.family in (socket.AF_INET, socket.AF_INET6)):
+            self.socket.setsockopt(socket.IPPROTO_TCP,
+                                   socket.TCP_NODELAY, 1)
+
 
 class SSLIOStream(IOStream):
     """A utility class to write to and read from a non-blocking SSL socket.
index 117ce75b88548781193e2611e5096dc45e9c268f..31b5a73d83996abb37cf1de3eb95ee4334170452 100644 (file)
@@ -279,9 +279,11 @@ class _HTTPConnection(object):
             if b'\n' in line:
                 raise ValueError('Newline in header: ' + repr(line))
             request_lines.append(line)
-        self.stream.write(b"\r\n".join(request_lines) + b"\r\n\r\n")
+        request_str = b"\r\n".join(request_lines) + b"\r\n\r\n"
         if self.request.body is not None:
-            self.stream.write(self.request.body)
+            request_str += self.request.body
+        self.stream.set_nodelay(True)
+        self.stream.write(request_str)
         self.stream.read_until_regex(b"\r?\n\r?\n", self._on_headers)
 
     def _release(self):
index 7bc651386b40a2b670e50116a538e0893bd15c1e..dd4e4b475e8d019448c6c0fa36e8c0fd104c9741 100644 (file)
@@ -227,6 +227,20 @@ class WebSocketHandler(tornado.web.RequestHandler):
         """
         return False
 
+    def set_nodelay(self, value):
+        """Set the no-delay flag for this stream.
+
+        By default, small messages may be delayed and/or combined to minimize
+        the number of packets sent.  This can sometimes cause 200-500ms delays
+        due to the interaction between Nagle's algorithm and TCP delayed
+        ACKs.  To reduce this delay (at the expense of possibly increasing
+        bandwidth usage), call ``self.set_nodelay(True)`` once the websocket
+        connection is established.
+
+        See `.IOStream.set_nodelay` for additional details.
+        """
+        self.stream.set_nodelay(value)
+
     def get_websocket_scheme(self):
         """Return the url scheme used for this request, either "ws" or "wss".