I'm working on a real time project on my Debian Wheezy (with real-time patch), it needs a strong reactivity using TCP communication protocol.
When I send a request, the response time is too long (220us) and I don't understand why.
My problem is when I send a request, my application server answers too late for my needs.
So, I decided to write a short program using TCP socket to acquire my server's response time. (see code below)
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
int main(int argc, char* argv[])
{
char sendBuffer [] = "OK";
char buffer [10];
int socket1;
int workingSocket;
socklen_t len;
int nodelay = 1;
struct sockaddr_in sa1;
struct sockaddr sa2;
socket1 = 0;
workingSocket = 0;
len = sizeof(sa1);
memset(&sa1, 0, len);
sa1.sin_addr.s_addr = htonl (INADDR_ANY);
sa1.sin_family = AF_INET;
sa1.sin_port = htons(12345);
socket1 = socket(AF_INET, SOCK_STREAM, 0);
bind(socket1, (struct sockaddr *)&sa1, len);
listen(socket1, 10);
workingSocket = accept(socket1, &sa2, &len);
setsockopt (workingSocket, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay));
// receive and send message back
while (1)
{
recv(workingSocket, buffer, 5, MSG_WAITALL);
send(workingSocket, sendBuffer, 2, 0);
}
}
I check the response time doing the following procedure :
start a wireshark session to trace the network traffic
launch my C server.
send a TCP request for example : $echo 'abcde'|netcat 192.168.0.1 12345
I got a response time of around 200 µs between the moment the string is sent (abcde) and the moment when I receive the reponse on the socket (OK)
This time seems to be very high. I made the same experience on VxWorks and got a response time aproaching 10µs.
Is the Linux kernel really slow or is there a trick to increase the reactivity of the system ?
Thank you for your help and your advices.
Related
I'm following a tutorial for creating an HTTP server with sockets using C. I'm on Windows using the gcc compiler. The server runs and I can even hit it and get data back when using a custom client built from C sockets. But When I try run the command
"curl -o - http://127.0.0.1:8001"
to connect to my server, I receive the error:
curl : Unable to read data from the transport connection: An existing connection was forcibly closed by the remote
host.
My server output shows the connection is trying to be made, but doesn't show any errors. Here is my code..
http_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
int main()
{
//open a file to server
FILE *html_data;
html_data = fopen("index.html", "r");
char response_data[1024];
fgets(response_data, 1024, html_data);
char http_header[2048] = "HTTP/1.1 200 OK\r\n\r\n";
strcat(http_header, response_data);
//create a socket
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM,0);
// specify an address for the socket
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8001);
server_address.sin_addr.s_addr = INADDR_ANY;
//bind the socket to our specified IP and port
bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));
listen(server_socket,5);
int client_socket;
while(1) {
client_socket = accept(server_socket, NULL, NULL);
printf("client socket response: %d\n", client_socket);
perror("socket");
send(client_socket, http_header, sizeof(http_header),0);
close(client_socket);
}
return 0;
}
index.html
<html><body>welcome to the HTTP Server!</body></html>
I think you're pretty close to getting it working. The reason curl is complaining is because it's expecting you to have supplied a Content-Length header. You can do this by updating your existing code as follows:
char response_data[1024];
fgets(response_data, 1024, html_data);
size_t message_length = strlen(response_data);
char http_header[2048];
snprintf(http_header, sizeof(http_header), "HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n", message_length);
strcat(http_header, response_data);
You also need to update your send code to only send the length of the response string.
send(client_socket, http_header, strlen(http_header),0);
You still have some issues with your error checking as mentioned in the comments, but at least with these changes curl should be happy.
While what I mentioned above is the minimal headers that will satisfy curl, there are others that you need to add to make you code conform to Hypertext Transfer Protocol -- HTTP/1.1
Connection: close
Content-Type: text/html
I'm trying to port my desktop app written in C and C++ to webassembly platform and am investigating if it is possible at all. One of important things the app does is communicate by sending and receiving UDP messages. I have implemented minimal UDP client which just creates UDP socket and sends packets to server (which is build natively and is running as separate executable at the same machine). socket, bind and sendto APIs return no error and everything looks working but no messages are receiving on server side and wireshark shows no activity on that port.
Is UDP socket just stubbed at webassembly libc port, or it is implemented on top of some web standard connection (e.g. WebRTC)?
The client code is below. I checked that native build is working properly.
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 512
#define NPACK 100
#define PORT 9930
void diep(char *s)
{
perror(s);
exit(1);
}
#define SRV_IP "127.0.0.1"
int main(void)
{
struct sockaddr_in si_other;
int s, i, slen=sizeof(si_other);
char buf[BUFLEN];
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
diep("socket");
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SRV_IP, &si_other.sin_addr)==0) {
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
for (i=0; i<NPACK; i++) {
printf("Sending packet %d\n", i);
sprintf(buf, "This is packet %d\n", i);
if (sendto(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, slen)==-1)
diep("sendto()");
}
close(s);
return 0;
}
I followed instructions from http://webassembly.org/getting-started/developers-guide/ to build and run it.
Thanks in advance for any help or clues!
I found how UDP sockets are implemented at webassembly. Actually, they are emulated by websockets. It probably would work if both client and server were webassemblies, but my server is built natively. As wasm doesn't support dynamic linking, all the code (including libc implementation) is bundled to one JS file, were we can find UDP sendto implementation:
// if we're emulating a connection-less dgram socket and don't have
// a cached connection, queue the buffer to send upon connect and
// lie, saying the data was sent now.
if (sock.type === 2) {
if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
// if we're not connected, open a new connection
if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
}
dest.dgram_send_queue.push(data);
return length;
}
}
Anything that runs in the browser will not give you native socket access and I suspect that browser vendors would strongly object to any such access as it is a potential security violation.
Perhaps as more and more native applications move to the web as the performance difference shrinks due to webassembly and similar initiatives would make them change their stance, but until then, anything that wants direct socket control would have to remain a native app.
I'm writing a very small C UDP client. I know that a random port is chosen as source port when you send data to the server. I also know that you can use bind to specify yourself the port you want a response.
However, I don't know when is the port randomly chosen? For example, I would like to rely on the sender address to keep track of users. It currently works only if the client does not shutdown, the port is still the same then a simple memcmp is enough to detect the same client.
This small code will use the same source port until it exits:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
int main(void)
{
int s, error, ch;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((error = getaddrinfo("localhost", "9988", &hints, &res)))
errx(1, "%s", gai_strerror(error));
if ((s = socket(res->ai_family, res->ai_socktype, 0)) < 0)
err(1, "socket");
while ((ch = fgetc(stdin)) != EOF)
sendto(s, &ch, 1, 0, res->ai_addr, res->ai_addrlen);
}
And running something like : dmesg | ./client will use the same address until the program exits. However, when you run it again, the port is different.
So is it the socket function that choose a port? Or the system? Is it sure that the port will still be the same during the client lifetime?
If the socket is not explicitly bound, then the OS will bind it (with a random port) when you send the first packet. This binding will be active as long as the socket is open, once it's closed the socket is (of course) unbound.
And due to the connectionless nature of UDP sockets, the "server" (if done correctly) should not keep the address of all "clients" that send to it indefinitely. Instead it should use the source address as received in the recvfrom call, and use that for a reply. The only reason to store the source address for more than just a simple request/response, is if you have a more advanced protocol on top of UDP with your own "connection" handling.
For a programming project in school we have to design a basic client/server setup using tcp protocol and then udp protocol. I already got the TCP working using read() and write() from the C Socket library. I now need to create a "reliable UDP" system. For instance:
"When the server receives the length message it will wait up to 500 milliseconds for that number of bytes to be sent. If it receives the correct number of bytes, it will respond with a string containing the characters "ACK" (a common abbreviation for an acknowledgement). If it does not receive the correct number of bytes by the end of the timeout period, the server will give up and silently exit."
I have the sendto() and recvfrom() functions set up, but I am not sure how to do the timeout feature so that it only waits 500ms for the second msg to be sent. I also have to do it later on the client side if it doesn't receive the "ACK" and resend the length msg + msg a few times. How can do I do the timeout?
Add the following function in your program and use it instead of using the recvfrom function directly.
the following functiong has the same input parameter of recvfrom function + a timeout input parameter in the last
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
int timeout_recvfrom (int sock, char *buf, int *length, struct sockaddr_in *connection, int timeoutinseconds)
{
fd_set socks;
struct timeval t;
FD_ZERO(&socks);
FD_SET(sock, &socks);
t.tv_sec = timeoutinseconds;
if (select(sock + 1, &socks, NULL, NULL, &t) &&
recvfrom(sock, buf, *length, 0, (struct sockaddr *)connection, length)!=-1)
{
return 1;
}
else
return 0;
}
An alternate without using select or poll is using socket options SO_RCVTIMEO and SO_SNDTIMEO
tv.tv_sec = 10; /* seconds */
tv.tv_usec = 0;
if(setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
printf("Cannot Set SO_SNDTIMEO for socket\n");
if(setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
printf("Cannot Set SO_RCVTIMEO for socket\n");
SO_RCVTIMEO and SO_SNDTIMEO socket options
If you have a single socket to either read or write to/from, then this is a better option. Where as if you are using multiple sockets and wish to carry on with the one which completely sent / received data, then perhaps select would be more appropriate.
I've been writing some sockets code in C. I need modify packet headers and control how they're sent out, so I took the raw sockets approach. However, the code I wrote will not compile on BSD systems (Mac OS X/Darwin, FreeBSD, etc.)
I've done a bunch of research on this and have found that BSD systems can't handle raw sockets the way Linux (or even Windows) does. From what I've read, it seems I need to use bpf (berkley packet filter), but I can't figure out how bpf works or how I would go about using it with raw sockets.
If someone could shed some light on this one, I'd be very excited :D
P.S. I'll even be happy with some source code showing how raw sockets are handled in a BSD environment. It doesn't have to be a guide or explanation. I just want to see how it works.
Using raw sockets isn't hard but it's not entirely portable. For instance, both in BSD and in Linux you can send whatever you want, but in BSD you can't receive anything that has a handler (like TCP and UDP).
Here is an example program that sends a SYN.
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
int
main(int argc, char *argv[])
{
int s, rc;
struct protoent *p;
struct sockaddr_in sin;
struct tcphdr tcp;
if (argc != 2)
errx(EX_USAGE, "%s addr", argv[0]);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = 0;
/* Parse command line address. */
if (inet_pton(AF_INET, argv[1], &sin.sin_addr) <= 0)
err(EX_USAGE, "Parse address");
/* Look up tcp although it's 6. */
p = getprotobyname("tcp");
if (p == NULL)
err(EX_UNAVAILABLE, "getprotobyname");
/* Make a new shiny (Firefly) socket. */
s = socket(AF_INET, SOCK_RAW, p->p_proto);
if (s < 0)
err(EX_OSERR, "socket");
memset(&tcp, 0, sizeof(tcp));
/* Fill in some random stuff. */
tcp.th_sport = htons(4567);
tcp.th_dport = htons(80);
tcp.th_seq = 4; /* Chosen by fair dice roll. */
tcp.th_ack = 0;
tcp.th_off = 5;
tcp.th_flags = TH_SYN;
tcp.th_win = htonl(65535);
rc = sendto(s, &tcp, sizeof(tcp), 0, (struct sockaddr *)&sin,
sizeof(sin));
printf("Wrote %d bytes\n", rc);
return 0;
}
Of course, more BSD-specific solutions are available. For instance you could use divert(4) to intercept packets as they traverse your system and alter them.