Last active
March 8, 2017 06:27
-
-
Save matthewaveryusa/4837ac824ec5873250ae821c3310c8c1 to your computer and use it in GitHub Desktop.
1 thread per connection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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 <unistd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <netdb.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <thread> | |
#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 <port>\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(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment