View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0002886 | libmicrohttpd | performance | public | 2013-05-19 19:15 | 2013-07-19 13:36 |
| Reporter | giovanni.li | Assigned To | Christian Grothoff | ||
| Priority | normal | Severity | feature | Reproducibility | always |
| Status | closed | Resolution | fixed | ||
| Product Version | 0.9.26 | ||||
| Target Version | 0.9.28 | Fixed in Version | 0.9.28 | ||
| Summary | 0002886: delay in transmission in the function MHD_ContentReaderCallback | ||||
| Description | if in the function MHD_ContentReaderCallback i block the function on busy waiting i have a delay of 20 ms from when the server receives the request when responding to. I upload an example to show the problem in a simple way. | ||||
| Steps To Reproduce | run wireshark and apply the filter "port eq <port>" and then run minimal_example_comet.c | ||||
| Tags | No tags attached. | ||||
| Attached Files | minimal_example_comet.c (3,414 bytes)
/*
This file is part of libmicrohttpd
(C) 2007, 2008 Christian Grothoff (and other contributing authors)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file minimal_example.c
* @brief minimal example for how to generate an infinite stream with libmicrohttpd
* @author Christian Grothoff
*/
#include "platform.h"
#include <microhttpd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
int i=0;
static ssize_t
data_generator (void *cls, uint64_t pos, char *buf, size_t max)
{
struct MHD_Connection *connection = cls;
/* starting header send, disable TCP cork */
{
const int val = 0;
int fd;
fd = MHD_get_connection_info (connection,
MHD_CONNECTION_INFO_CONNECTION_FD)->connect_fd;
setsockopt (fd, IPPROTO_TCP, TCP_CORK, &val,
sizeof (val));
fprintf (stderr, "SSOPT (%d): %s\n", fd, strerror (errno));
}
/* now set nodelay as well */
{
const int val = 1;
int fd;
fd = MHD_get_connection_info (connection,
MHD_CONNECTION_INFO_CONNECTION_FD)->connect_fd;
setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val,
sizeof (val));
fprintf (stderr, "SSOPT (%d): %s\n", fd, strerror (errno));
}
printf(" if-while \n");
if (i > 2){
printf("Wait on while\n Kill process\n");
while(1);
}
if (max < 80)
return 0;
memset (buf, 'A', max - 1);
buf[79] = '\n';
i++;
return 80;
}
static int
ahc_echo (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data, size_t *upload_data_size, void **ptr)
{
static int aptr;
struct MHD_Response *response;
int ret;
if (0 != strcmp (method, "GET"))
return MHD_NO; /* unexpected method */
if (&aptr != *ptr)
{
/* do never respond on first call */
*ptr = &aptr;
return MHD_YES;
}
*ptr = NULL; /* reset when done */
response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
80,
&data_generator, connection, NULL);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
int
main (int argc, char *const *argv)
{
struct MHD_Daemon *d;
if (argc != 2)
{
printf ("%s PORT\n", argv[0]);
return 1;
}
d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
atoi (argv[1]),
NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
if (d == NULL)
return 1;
(void) getc (stdin);
MHD_stop_daemon (d);
return 0;
}
patch.diff (2,788 bytes)
Index: ChangeLog
===================================================================
--- ChangeLog (revision 27206)
+++ ChangeLog (working copy)
@@ -1,3 +1,8 @@
+Mon May 20 12:29:35 CEST 2013
+ Added MHD_CONNECTION_INFO_CONNECTION_FD to allow clients
+ direct access to connection socket; useful for COMET
+ applications that need to disable NAGLE (#2886). -CG
+
Mon May 15 12:49:01 CEST 2013
Fixing #2859. -CG
Index: doc/libmicrohttpd.texi
===================================================================
--- doc/libmicrohttpd.texi (revision 27206)
+++ doc/libmicrohttpd.texi (working copy)
@@ -2138,6 +2138,18 @@
Returns information about @code{struct MHD_Daemon} which manages
this connection.
+@item MHD_CONNECTION_INFO_CONNECTION_FD
+Returns the file descriptor (usually a TCP socket) associated with
+this connection (in the ``connect-fd'' member of the returned struct).
+Note that manipulating the descriptor directly can have problematic
+consequences (as in, break HTTP). Applications might use this access
+to manipulate TCP options, for example to set the ``TCP-NODELAY''
+option for COMET-like applications. Note that MHD will set TCP-CORK
+after sending the HTTP header and clear it after finishing the footers
+automatically (if the platform supports it). As the connection
+callbacks are invoked in between, those might be used to set different
+values for TCP-CORK and TCP-NODELAY in the meantime.
+
@end table
@end deftp
Index: src/include/microhttpd.h
===================================================================
--- src/include/microhttpd.h (revision 27206)
+++ src/include/microhttpd.h (working copy)
@@ -791,8 +791,15 @@
/**
* Get the 'struct MHD_Daemon' responsible for managing this connection.
*/
- MHD_CONNECTION_INFO_DAEMON
+ MHD_CONNECTION_INFO_DAEMON,
+
+ /**
+ * Request the file descriptor for the listening socket.
+ * No extra arguments should be passed.
+ */
+ MHD_CONNECTION_INFO_CONNECTION_FD
+
};
@@ -1852,6 +1859,11 @@
int /* enum gnutls_protocol */ protocol;
/**
+ * Connect socket
+ */
+ int connect_fd;
+
+ /**
* GNUtls session handle, of type "gnutls_session_t".
*/
void * /* gnutls_session_t */ tls_session;
Index: src/microhttpd/connection.c
===================================================================
--- src/microhttpd/connection.c (revision 27206)
+++ src/microhttpd/connection.c (working copy)
@@ -2555,6 +2555,8 @@
return (const union MHD_ConnectionInfo *) &connection->addr;
case MHD_CONNECTION_INFO_DAEMON:
return (const union MHD_ConnectionInfo *) &connection->daemon;
+ case MHD_CONNECTION_INFO_CONNECTION_FD:
+ return (const union MHD_ConnectionInfo *) &connection->socket_fd;
default:
return NULL;
};
| ||||
|
|
the delay is not due to the while loop |
|
|
Ok, the 200 ms are caused by TCP NAGLE (read http://www.techrepublic.com/article/tcpip-options-for-high-performance-data-transmission/1050878 for an explanation). I've now (SVN 27208) extended the MHD API to allow you direct access to the socket so you can disable TCP NAGLE and get rid of those 200 ms. This needs to be done in a rather specific way; I've attached a version of your example that does it and updated the manual (read the DIFF!). |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2013-05-19 19:15 | giovanni.li | New Issue | |
| 2013-05-19 19:15 | giovanni.li | File Added: comet_delay.tar.gz | |
| 2013-05-19 19:41 | giovanni.li | Note Added: 0007107 | |
| 2013-05-20 12:30 | Christian Grothoff | File Added: minimal_example_comet.c | |
| 2013-05-20 12:31 | Christian Grothoff | File Added: patch.diff | |
| 2013-05-20 12:32 | Christian Grothoff | Note Added: 0007108 | |
| 2013-05-20 12:32 | Christian Grothoff | Status | new => resolved |
| 2013-05-20 12:32 | Christian Grothoff | Fixed in Version | => 0.9.28 |
| 2013-05-20 12:32 | Christian Grothoff | Resolution | open => fixed |
| 2013-05-20 12:32 | Christian Grothoff | Assigned To | => Christian Grothoff |
| 2013-05-20 12:33 | Christian Grothoff | Severity | minor => feature |
| 2013-05-20 12:33 | Christian Grothoff | Target Version | => 0.9.28 |
| 2013-07-19 13:36 | Christian Grothoff | Status | resolved => closed |