Advertisement
Guest User

Non blocking + Multi-threaded

a guest
Aug 14th, 2019
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.76 KB | None | 0 0
  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <pthread.h>
  7. #include <stdatomic.h>
  8. #include <sys/types.h>
  9. #include <sys/epoll.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <netinet/tcp.h>
  13. #include <sys/sysinfo.h>
  14.  
  15. #define NUM_EVENTS 64
  16. #define READ_BUFFER (64 * 1024)
  17. #define RESPONSE "HTTP/1.1 200 Ok\r\nContent-Length: 11\r\n\r\nHello World"
  18.  
  19. int find_clrf(const char* buffer, int len) {
  20.     const char* start_buffer = buffer;
  21.     for (; len >= sizeof(int); len--, buffer++)
  22.         if (*((int*)buffer) == *(int*)"\r\n\r\n")
  23.             return buffer - start_buffer;
  24.     return -1;
  25. }
  26.  
  27. typedef struct {
  28.     int value;
  29.     char padding[64 - sizeof(int)];
  30. } Lock;
  31. int efd, server;
  32. Lock locks[1024] = { 0 };
  33.  
  34. void* worker(void* arg) {
  35.     char buffer[READ_BUFFER];
  36.     struct epoll_event events[NUM_EVENTS];
  37.     while (1) {
  38.         int n = epoll_wait(efd, events, NUM_EVENTS, -1);
  39.         for (int i = 0; i < n; i++) {
  40.             int* fd_lock = &locks[events[i].data.fd].value;
  41.             int client, expect,
  42.                 fd = events[i].data.fd,
  43.                 error = events[i].events & (EPOLLHUP | EPOLLERR);
  44.             if (error || atomic_exchange_explicit(fd_lock, 1, memory_order_acquire) != 0) {
  45.                 if (error) close(fd);
  46.                 continue;
  47.             }
  48.            
  49.             do {
  50.                 expect = 2;
  51.                 atomic_store_explicit(fd_lock, expect, memory_order_relaxed);
  52.                 if (fd == server) {
  53.                     while ((client = accept4(server, NULL, NULL, SOCK_NONBLOCK)) > 0) {
  54.                         int opt = 1;
  55.                         events[i].data.fd = client;
  56.                         events[i].events = EPOLLIN | EPOLLET;
  57.                         if (setsockopt(client, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) perror("no delay");
  58.                         if (epoll_ctl(efd, EPOLL_CTL_ADD, client, &events[i]) < 0) perror("epoll add client");
  59.                     }
  60.                 } else {
  61.                     int bytes, offset = 0;
  62.                     while ((bytes = read(fd, buffer + offset, READ_BUFFER - offset)) > 0) {
  63.                         int clrf_offset = 0;
  64.                         while ((clrf_offset = find_clrf(buffer + clrf_offset + offset, bytes)) != -1)
  65.                             if (send(fd, RESPONSE, sizeof(RESPONSE) - 1, MSG_NOSIGNAL) == -1)
  66.                                 break;
  67.                         offset += bytes;
  68.                     }
  69.                     if (bytes == 0 || (bytes == -1 && errno != EAGAIN))
  70.                         close(fd);
  71.                 }
  72.             } while (!atomic_compare_exchange_weak_explicit(
  73.                 fd_lock, &expect, 0, memory_order_release, memory_order_relaxed));
  74.         }
  75.     }
  76. }
  77.  
  78. int main() {
  79.     int opt = 1;
  80.     server = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  81.     if (server < 0) perror("socket create");
  82.     if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) perror("reuse addr");
  83.  
  84.     struct sockaddr_in addr;
  85.     addr.sin_family = AF_INET;
  86.     addr.sin_port = htons(12345);
  87.     addr.sin_addr.s_addr = htonl(INADDR_ANY);
  88.     if (bind(server, (struct sockaddr*)&addr, sizeof(addr)) < 0) perror("bind");
  89.     if (listen(server, SOMAXCONN) < 0) perror("listen");
  90.  
  91.     efd = epoll_create1(0);
  92.     if (efd < 0) perror("epoll");
  93.     struct epoll_event event;
  94.     event.events = EPOLLIN | EPOLLET;
  95.     event.data.fd = server;
  96.     if (epoll_ctl(efd, EPOLL_CTL_ADD, server, &event) < 0) perror("epoll add server");
  97.  
  98.     pthread_t thread;
  99.     for (int i = get_nprocs() - 1; i > 0; i--)
  100.         if (pthread_create(&thread, NULL, worker, NULL) != 0)
  101.             perror("create thread");
  102.     worker(NULL);
  103. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement