Skip to content

Instantly share code, notes, and snippets.

@matthewaveryusa
Last active March 8, 2017 06:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewaveryusa/4837ac824ec5873250ae821c3310c8c1 to your computer and use it in GitHub Desktop.
Save matthewaveryusa/4837ac824ec5873250ae821c3310c8c1 to your computer and use it in GitHub Desktop.
1 thread per connection
//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