//g++ -std=c++11 threads.cpp picohttpparser.c -march=native -pthread -O3 -o threads //requires picohttpparser.{c,h} from https://github.com/h2o/picohttpparser #include #include #include #include #include #include #include #include #include #include "picohttpparser.h" void error(const char *msg) { perror(msg); exit(1); } void thread_main(int childfd) { while(1) { char buf[4096], *method, *path; int pret, minor_version; struct phr_header headers[100]; size_t buflen = 0, prevbuflen = 0, method_len, path_len, num_headers; ssize_t rret; while (1) { /* read the request */ while ((rret = read(childfd, buf + buflen, sizeof(buf) - buflen)) == -1 && errno == EINTR) ; if (rret < 0) error("ERROR reading from socket"); else if(rret == 0) { //EOF goto got_eof; } prevbuflen = buflen; buflen += rret; /* parse the request */ num_headers = sizeof(headers) / sizeof(headers[0]); pret = phr_parse_request(buf, buflen, (const char**) &method, &method_len, (const char**) &path, &path_len, &minor_version, headers, &num_headers, prevbuflen); if (pret > 0) goto got_http; else if (pret == -1) error("ERROR http parse error"); /* request is incomplete, continue the loop */ if (buflen == sizeof(buf)) error("ERROR http request too long"); } got_http: //printf("request is %d bytes long\n", pret); //printf("method is %.*s\n", (int)method_len, method); //printf("path is %.*s\n", (int)path_len, path); //printf("HTTP version is 1.%d\n", minor_version); //printf("headers:\n"); //for (int i = 0; i != num_headers; ++i) { // printf("%.*s: %.*s\n", (int)headers[i].name_len, headers[i].name, // (int)headers[i].value_len, headers[i].value); //} const char out[] = "HTTP/1.1 200\r\nServer: Performance Test\r\n\r\n"; int out_written = 0; while(out_written != sizeof(out) -1) { int n = write(childfd, out + out_written, sizeof(out) - 1 - out_written); if(n == -1) { if(errno == EINTR) continue; error("ERROR writing to socket"); } out_written += n; } } got_eof: close(childfd); } int main(int argc, char **argv) { int parentfd; /* parent socket */ int childfd; /* child socket */ int portno; /* port to listen on */ socklen_t clientlen; /* byte size of client's address */ struct sockaddr_in serveraddr; /* server's addr */ struct sockaddr_in clientaddr; /* client addr */ int optval; /* flag value for setsockopt */ if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } portno = atoi(argv[1]); parentfd = socket(AF_INET, SOCK_STREAM, 0); if (parentfd < 0) error("ERROR opening socket"); optval = 1; setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)portno); if (bind(parentfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) error("ERROR on binding"); if (listen(parentfd, 128) < 0) /* allow 5 requests to queue up */ error("ERROR on listen"); clientlen = sizeof(clientaddr); while (1) { childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen); if (childfd < 0) error("ERROR on accept"); std::thread t(thread_main, childfd); t.detach(); } }