Hi! Sometimes, after calling the FreeRTOS_send function, the actual socket data transfer is delayed. This can be observed when the browser page is refreshed repeatedly. This seems to be affected by the tcpMAXIMUM_TCP_WAKEUP_TIME_MS parameter in FreeRTOS_TCP_IP.h, which defaults to 20000U. Is it possible to reduce this value to 50, 20, 10 or 5ms. Maybe some other solution to the latency problem is possible? How to send data to physical interfaces immediately?
can you provide a wireshark trace of the traffic? One of the admins should ensble you soon to upload a pcap.
Wireshark trace of the traffic when tcpMAXIMUM_TCP_WAKEUP_TIME_MS = 20000U:
20s delay from calling the FreeRTOS_send function to actual send of “HTTP/1.1 101 …”
In case you want avoid Nagle algorithm and send immediately you should use FREERTOS_MSG_DONTWAIT flag on send. Do you ?
Sorry, but the FREERTOS_MSG_DONTWAIT flag does not fix the problem
Can you share the code configuring your TCP socket, for example, the TCP window configuration?
Not very important, but I wonder why you are using TCP port 8081, in stead of 80 or 8080?
Can you do the same test while using port 8080?
Here is the packet list:
1 2 SYN
2 1 SYN+ACK
1 2 ACK /* SYN phase OK */
1 2 GET / HTTP/1.1
2 1 ACK
2 1 Reply "HTTP/1.1 101" Switching protocols
We (DUT) send the reply containing error code 101
, in stead of "HTTP/1.1 200 OK"
.
And also the client task gets no attention until the max-timer goes off.
Strange.
Did you write a webserver your self? Can you find the context in the sourcecode where it replies with a 101
error?
Does the webserver “see” the GET command?
What timeouts and buffer sizes are used by the HTTP server and client sockets?
Note that these properties can be (should be) set in server socket. All child sockets of the server will inherit these properties, see prvTCPSocketCopy()
.
At the moment the connection starts, the buffer sizes and timeout values should be correct.
The macro tcpMAXIMUM_TCP_WAKEUP_TIME_MS
was created to help detecting dead sockets. Normally we should not see this timer become active.
PCAP: thanks for the PCAP, but if possible could you filter your HTTP conversation and send a PCAP in a ZIP file?
Thanks
Hi!
We made our own http server with websocket server on the device.
- the browser requests a page index.html from the device
- index.html contains a java script with a websocket connection on a given port.
- websocket server of the device transfers data to the index.html page (to the browser) and it sees the GET command.
We test stability by frequently refreshing the page in the browser and the problem with data transfer delay occurs at some of the iterations of page refresh.
Port 8081 is a websocket connection, which we believe can be on any port.
Reply “HTTP/1.1 101” Switching protocols is the default response for protocol switching to websocket.
ipconfigNETWORK_MTU 1500U
Ready to provide more information if needed.
PCAP: Frame 82 was transmitted with a delay of 20 sec.
mypcap.zip (3.1 KB)
void Web_socket_server_serve(Socket_t SocketCon) {
static char SocketBuffer[LENGTH_WEB_SERVER_ARRAY];
static char str_buf1[LENGTH_WEB_SERVER_ARRAY];
static char str_buf2[LENGTH_WEB_SERVER_ARRAY];
char out_buffer[64];
uint8_t hash[20] = { 0 };
char *istr;
size_t len;
TickType_t xReceiveTimeOut = pdMS_TO_TICKS(100);
BaseType_t bytesReceived, bytesSent;
FreeRTOS_setsockopt(SocketCon, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof(xReceiveTimeOut));
while (1) {
bytesReceived = FreeRTOS_recv(SocketCon, SocketBuffer, sizeof(SocketBuffer), 0);
if (bytesReceived > 0) {
if (bytesReceived >= 5) {
if (strncmp((char*) SocketBuffer, "GET /", 5) == 0) {
istr = strstr(SocketBuffer, "Sec-WebSocket-Key:");
istr[43] = 0;
snprintf((char*) out_buffer, sizeof(out_buffer), "%s%s", istr + 19, guid_str);
strcpy(str_buf1, "HTTP/1.1 101 Switching Protocols\r\n");
strcat(str_buf1, "Upgrade: websocket\r\n");
strcat(str_buf1, "Connection: Upgrade\r\n");
strcat(str_buf1, "Sec-WebSocket-Accept: ");
mbedtls_sha1((const unsigned char*) out_buffer, 60, hash);
mbedtls_base64_encode((unsigned char*) str_buf2, 100, &len, hash, 20);
str_buf2[len] = 0;
strcat(str_buf1, (char*) str_buf2);
strcat(str_buf1, "\r\n\r\n");
bytesSent = FreeRTOS_send(SocketCon, str_buf1, strnlen(str_buf1, sizeof(str_buf1)), 0);
/*
FreeRTOS_send function is executed without errors, but in fact (as we see at wireshark trace) data is transmitted after the time specified in
tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000U
*/
if (bytesSent <= 0) {
DebugHandler("FreeRTOS_send websocket error %d\r\n", bytesSent);
}
continue;
}
}
SomeCodeWithWebsocketParse();
}
else if (bytesReceived == 0) {
__NOP();
}
else {
return;
}
}
}
void WebSocketTCP_thread(void *arg) {
struct freertos_sockaddr xClient = { 0 };
struct freertos_sockaddr xBindAddress = { 0 };
Socket_t xListeningSocket, xConnectedSocket;
TickType_t xReceiveTimeOut = portMAX_DELAY;
socklen_t xClientAddressLength = sizeof(xClient);
xBindAddress.sin_len = sizeof(xBindAddress);
xBindAddress.sin_port = FreeRTOS_htons(8081);
xBindAddress.sin_address.ulIP_IPv4 = FREERTOS_INADDR_ANY;
xBindAddress.sin_family = FREERTOS_AF_INET4;
xListeningSocket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);
FreeRTOS_setsockopt(xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof(xReceiveTimeOut));
FreeRTOS_bind(xListeningSocket, &xBindAddress, sizeof(xBindAddress));
FreeRTOS_listen(xListeningSocket, 2);
while (1) {
xConnectedSocket = FreeRTOS_accept(xListeningSocket, &xClient, &xClientAddressLength);
Web_socket_server_serve(xConnectedSocket);
FreeRTOS_closesocket(xConnectedSocket);
}
}
Thanks for the attachments. Now I understand a lot more of what it is doing.
If I were to write this websocket server, I would either:
-
Handle each socket in a separate task
If you have at most 2 client sockets, you will need 3 tasks (one for the parent socket) -
Use a single socket by setting the option
FREERTOS_SO_REUSE_LISTEN_SOCKET
, which allows for 1 client only (small footprint).
I went through your sample source and wrote a proposal for change:
web_socket.new.c (4.5 KB)
Would it be possible to try out the attached code?
Thanks
Thanks for your proposal!
Unfortunately, it didn’t help us in solving the problem with the delay of the socket actually sending data.
What do you mean by dead sockets?
For what reason does the macro tcpMAXIMUM_TCP_WAKEUP_TIME_MS have a default value of 20000ms? Can we change it to 50, 20 or 10ms and how safe is that?
We have done a lot of experiments and this is the only possible solution to the problem so far. Are there any other suggestions for this problem? Perhaps some additional logs are needed?