+++ /dev/null
-#
-
-```shell
-
-
-sudo ip netns exec net1 iperf3 -s -p 5001
------------------------------------------------------------
-Server listening on 5001 (test #1)
------------------------------------------------------------
-
-```
-
-#
-
-```shell
-iperf$ sudo iperf3 -c 192.168.62.6 -p 5001 -t 60 -i
-1
-Connecting to host 192.168.62.6, port 5001
-[ 5] local 192.168.62.5 port 41342 connected to 192.168.62.6 port 5001
-[ ID] Interval Transfer Bitrate Retr Cwnd
-[ 5] 0.00-1.00 sec 4.91 GBytes 42.2 Gbits/sec 0 478 KBytes
-[ 5] 1.00-2.00 sec 5.00 GBytes 42.9 Gbits/sec 0 600 KBytes
-[ 5] 2.00-3.00 sec 5.06 GBytes 43.5 Gbits/sec 0 600 KBytes
-[ 5] 3.00-4.00 sec 5.03 GBytes 43.2 Gbits/sec 0 600 KBytes
-^C[ 5] 4.00-4.53 sec 2.67 GBytes 43.6 Gbits/sec 0 600 KBytes
-- - - - - - - - - - - - - - - - - - - - - - - - -
-[ ID] Interval Transfer Bitrate Retr
-[ 5] 0.00-4.53 sec 22.8 GBytes 43.2 Gbits/sec 0 sender
-[ 5] 0.00-4.53 sec 0.00 Bytes 0.00 bits/sec receiver
-iperf3: interrupt - the client has terminated
-
-```
-
-```shell
-
-Accepted connection from 192.168.62.5, port 41336
-[ 5] local 192.168.62.6 port 5001 connected to 192.168.62.5 port 41342
-[ ID] Interval Transfer Bitrate
-[ 5] 0.00-1.00 sec 4.91 GBytes 42.2 Gbits/sec
-[ 5] 1.00-2.00 sec 5.02 GBytes 43.1 Gbits/sec
-[ 5] 2.00-3.00 sec 5.08 GBytes 43.7 Gbits/sec
-[ 5] 3.00-4.00 sec 5.06 GBytes 43.4 Gbits/sec
-[ 5] 3.00-4.00 sec 5.06 GBytes 43.4 Gbits/sec
-- - - - - - - - - - - - - - - - - - - - - - - - -
-[ ID] Interval Transfer Bitrate
-[ 5] 0.00-4.00 sec 22.8 GBytes 48.9 Gbits/sec receiver
-iperf3: the client has terminated
------------------------------------------------------------
-Server listening on 5001 (test #2)
------------------------------------------------------------
-
-```
-
-
-#
-
-```shell
-
-192.168.62.5 -> 192.168.62.6
-41440 -> 9999
-
-0000 68 68 77 68 72 33 66 73 68 36 33 70 36 7a 65 63 hhwhr3fsh63p6zec
-0010 74 76 79 71 6c 6f 66 36 6b 77 6e 6f 6c 36 70 6f tvyqlof6kwnol6po
-0020 6e 7a 75 70 00 nzup.
-
-
-
-```
-
-#
-
-```shell
-192.168.62.6 -> 192.168.62.5
-9999 -> 41440
-
- TCP payload (1 byte)
-Data (1 byte)
-
-0000 09 .
- Data: 09
- [Length: 1]
-
-
-```
-
-#
-
-```shell
-
-192.168.62.5 -> 192.168.62.6
-41440 -> 9999
-
-Data (4 bytes)
-
-0000 00 00 00 7c ...|
- Data: 0000007c
- [Length: 4]
-
-
-
-```
-
-```shell
-
-192.168.62.5 -> 192.168.62.6
-41440 -> 9999
-
- TCP payload (124 bytes)
-Data (124 bytes)
-
-0000 7b 22 74 63 70 22 3a 74 72 75 65 2c 22 6f 6d 69 {"tcp":true,"omi
-0010 74 22 3a 30 2c 22 74 69 6d 65 22 3a 31 30 2c 22 t":0,"time":10,"
-0020 6e 75 6d 22 3a 30 2c 22 62 6c 6f 63 6b 63 6f 75 num":0,"blockcou
-0030 6e 74 22 3a 30 2c 22 70 61 72 61 6c 6c 65 6c 22 nt":0,"parallel"
-0040 3a 31 2c 22 6c 65 6e 22 3a 31 33 31 30 37 32 2c :1,"len":131072,
-0050 22 70 61 63 69 6e 67 5f 74 69 6d 65 72 22 3a 31 "pacing_timer":1
-0060 30 30 30 2c 22 63 6c 69 65 6e 74 5f 76 65 72 73 000,"client_vers
-0070 69 6f 6e 22 3a 22 33 2e 31 36 22 7d ion":"3.16"}
-
-
-
-```
-
-#
-
-```shell
-
-192.168.62.6 -> 192.168.62.5
-9999 -> 41440
-
- TCP payload (1 byte)
-Data (1 byte)
-
-0000 0a .
- Data: 0a
- [Length: 1]
-
-```
-
-#
-
-```shell
-
-
-192.168.62.5 -> 192.168.62.6
-41448 -> 9999
-
- TCP payload (37 bytes)
-Data (37 bytes)
-
-0000 68 68 77 68 72 33 66 73 68 36 33 70 36 7a 65 63 hhwhr3fsh63p6zec
-0010 74 76 79 71 6c 6f 66 36 6b 77 6e 6f 6c 36 70 6f tvyqlof6kwnol6po
-0020 6e 7a 75 70 00 nzup.
-
-```
-
-#
-
-```shell
-
-192.168.62.6 -> 192.168.62.5
-9999 -> 41440
-
- TCP payload (1 byte)
-Data (1 byte)
-
-0000 01 .
- Data: 01
- [Length: 1]
-```
-
-```shell
-
-192.168.62.6 -> 192.168.62.5
-9999 -> 41440
-
-
- TCP payload (1 byte)
-Data (1 byte)
-
-0000 02 .
- Data: 02
- [Length: 1]
-
-
-```
-
-#
-
-```shell
-
-192.168.62.5 -> 192.168.62.6
-41448 -> 9999
-
- TCP payload (7240 bytes)
-Data (7240 bytes)
-
-0000 55 7c 4c 02 5e 17 5c bc 5b da b6 c0 6f 5d f6 d7 U|L.^.\.[...o]..
-0010 c5 df 58 8d e3 e1 5c cc a8 26 ce c0 77 08 e7 8b ..X...\..&..w...
-0020 c3 bc 5d 60 bc 19 6b 6b 94 f1 f3 e8 ae f3 fd b4 ..]`..kk........
-0030 2b b9 2f ca 77 2b 43 15 62 56 eb 13 ff b0 c7 82 +./.w+C.bV......
-0040 b9 6e 78 a1 3c 2d 90 6e b8 48 73 f8 8e d8 5c 20 .nx.<-.n.Hs...\
-
-```
-
-
-#
-
-
-```shell
-
-Data (1 byte)
- Data: 0d
- [Length: 1]
-
-
-```
-
-#
-
-```shell
-
-Frame 55388: 70 bytes on wire (560 bits), 70 bytes captured (560 bits) on interface veth11, id 0
-Ethernet II, Src: 82:c8:ff:58:e7:e7 (82:c8:ff:58:e7:e7), Dst: 46:5f:bb:78:a9:5e (46:5f:bb:78:a9:5e)
-Internet Protocol Version 4, Src: 192.168.62.5, Dst: 192.168.62.6
-Transmission Control Protocol, Src Port: 33886, Dst Port: 9999, Seq: 166, Ack: 6, Len: 4
-Data (4 bytes)
- Data: 00000145
- [Length: 4]
-
-
-```
-
-```shell
-
-0000 46 5f bb 78 a9 5e 82 c8 ff 58 e7 e7 08 00 45 00 F_.x.^...X....E.
-0010 01 79 14 2c 40 00 40 06 27 f7 c0 a8 3e 05 c0 a8 .y.,@.@.'...>...
-0020 3e 06 84 5e 27 0f 99 98 11 ab 94 a1 6d 1f 80 18 >..^'.......m...
-0030 01 f6 fe c7 00 00 01 01 08 0a 9d eb 12 cb f2 7d ...............}
-0040 0e eb 7b 22 63 70 75 5f 75 74 69 6c 5f 74 6f 74 ..{"cpu_util_tot
-0050 61 6c 22 3a 39 39 2e 38 39 31 31 32 35 35 39 32 al":99.891125592
-0060 33 34 36 33 37 2c 22 63 70 75 5f 75 74 69 6c 5f 34637,"cpu_util_
-0070 75 73 65 72 22 3a 31 2e 31 39 33 33 34 33 30 35 user":1.19334305
-0080 30 38 32 39 39 33 31 32 2c 22 63 70 75 5f 75 74 08299312,"cpu_ut
-0090 69 6c 5f 73 79 73 74 65 6d 22 3a 39 38 2e 36 39 il_system":98.69
-00a0 37 37 38 32 35 34 31 35 31 36 34 34 36 2c 22 73 7782541516446,"s
-00b0 65 6e 64 65 72 5f 68 61 73 5f 72 65 74 72 61 6e ender_has_retran
-00c0 73 6d 69 74 73 22 3a 31 2c 22 63 6f 6e 67 65 73 smits":1,"conges
-00d0 74 69 6f 6e 5f 75 73 65 64 22 3a 22 63 75 62 69 tion_used":"cubi
-00e0 63 22 2c 22 73 74 72 65 61 6d 73 22 3a 5b 7b 22 c","streams":[{"
-00f0 69 64 22 3a 31 2c 22 62 79 74 65 73 22 3a 37 36 id":1,"bytes":76
-0100 39 38 39 30 37 31 33 36 2c 22 72 65 74 72 61 6e 98907136,"retran
-0110 73 6d 69 74 73 22 3a 30 2c 22 6a 69 74 74 65 72 smits":0,"jitter
-0120 22 3a 30 2c 22 65 72 72 6f 72 73 22 3a 30 2c 22 ":0,"errors":0,"
-0130 6f 6d 69 74 74 65 64 5f 65 72 72 6f 72 73 22 3a omitted_errors":
-0140 30 2c 22 70 61 63 6b 65 74 73 22 3a 30 2c 22 6f 0,"packets":0,"o
-0150 6d 69 74 74 65 64 5f 70 61 63 6b 65 74 73 22 3a mitted_packets":
-0160 30 2c 22 73 74 61 72 74 5f 74 69 6d 65 22 3a 30 0,"start_time":0
-0170 2c 22 65 6e 64 5f 74 69 6d 65 22 3a 31 2e 30 30 ,"end_time":1.00
-0180 35 31 33 33 7d 5d 7d 5133}]}
-
-
-```
-
-
-#
-
-```shell
-
-
-Data (1 byte)
- Data: 0e
- [Length: 1]
-
-```
-
-
-#
-
-```c
-
-static uint8_t ctl_hello[37] = {0};
-static uint8_t ctl_hellow_answer[1] = {0x09};
-static uint32_t ctl_info_size = 0;
-static uint8_t* ctl_info = NULL;
-static uint8_t ctl_info_answer[1] = {0x0a};
-static uint8_t ctl_start_1[1] = {0x01};
-static uint8_t ctl_start_2[1] = {0x02};
-static uint8_t ctl_end_1[1] = {0x0d};
-static uint8_t ctl_end_2[1] = {0x0e};
-
-```
-
-#
-
-```c
-
-
-
-```
\ No newline at end of file
+++ /dev/null
-GCC_FLAGS := -Wall -O2 -g
-
-all: iperf_s.o
-
- gcc $(GCC_FLAGS) -I. -o iperf_s.out main.c iperf_s.o -lpthread
-
-
-iperf_s.o:
-
- gcc $(GCC_FLAGS) -c -I. -o iperf_s.o iperf_s.c
-
-clean:
- rm -r *.o *.a *.so *.out
\ No newline at end of file
+++ /dev/null
-#include "iperf_s.h"
-
-
-static uint8_t ctl_hello[37] = {0};
-static uint8_t ctl_hellow_answer[1] = {0x09};
-static uint32_t ctl_info_size = 0;
-static uint8_t* ctl_info = NULL;
-static uint8_t ctl_info_answer[1] = {0x0a};
-static uint8_t ctl_start_1[1] = {0x01};
-static uint8_t ctl_start_2[1] = {0x02};
-static uint8_t ctl_end_1[1] = {0x0d};
-static uint8_t ctl_end_2[1] = {0x0e};
-
-static uint8_t hello[37] = {0};
-
-int make_socket_non_blocking(int sfd){
- int flags, s;
-
- flags = fcntl (sfd, F_GETFL, 0);
- if (flags == -1){
- printf("fcntl get");
- return -1;
- }
-
- flags |= O_NONBLOCK;
- s = fcntl (sfd, F_SETFL, flags);
- if (s == -1){
- printf("fcntl set");
- return -2;
- }
- return 0;
-}
-
-void* ctl_thread(void* varg){
-
- pthread_mutex_unlock(&lock);
- sleep(timeout);
- write(ctl_fd, ctl_end_1, 1);
- read(ctl_fd, &ctl_info_size, 4);
- uint32_t isize = ntohl(ctl_info_size);
- ctl_info = (uint8_t*)malloc(isize * sizeof(uint8_t));
- read(ctl_fd, ctl_info, isize);
- printf("%s\n",ctl_info);
- write(ctl_fd, &ctl_info_size, 4);
- write(ctl_fd, ctl_info, isize);
- write(ctl_fd, ctl_end_2, 1);
- free(ctl_info);
-
- //close(ctl_fd);
-
- pthread_exit(NULL);
-
-}
-
-void ctl_runner(){
-
-
- pthread_t tid;
-
- pthread_mutex_lock(&lock);
-
- read(ctl_fd, ctl_hello, 37);
- write(ctl_fd, ctl_hellow_answer, 1);
- read(ctl_fd, &ctl_info_size, 4);
-
- uint32_t isize = ntohl(ctl_info_size);
- ctl_info = (uint8_t*)malloc(isize * sizeof(uint8_t));
- read(ctl_fd, ctl_info, isize);
- write(ctl_fd, ctl_info_answer, 1);
-
- pthread_create(&tid, NULL, ctl_thread, NULL);
-
- free(ctl_info);
-
-}
-
-int run_select(int fd, struct sockaddr_in* servaddr){
-
- int connections = 0;
-
- int max_fd = 0;
- int event = 0;
- fd_set readfds;
- int servlen;
- int client_fds[MAXCLIENT] = {0};
- int valread;
- int n;
- int client_fd;
-
- int keep = 1;
-
- servlen = sizeof(*servaddr);
-
- while(keep){
-
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
- max_fd = fd;
-
- for(int i = 0; i < client_num; i++){
- client_fd = client_fds[i];
-
- if(client_fd > 0){
- FD_SET(client_fd, &readfds);
- }
- if(client_fd > max_fd){
- max_fd = client_fd;
- }
-
- }
-
- event = select(max_fd + 1, &readfds, NULL, NULL, NULL);
-
- if ((event < 0 ) && (errno != EINTR)){
- printf("select error\n");
- break;
- }
-
- do {
- if(FD_ISSET(fd, &readfds)){
- int added = 0;
- event -= 1;
- client_fd = accept(fd, (struct sockaddr*)servaddr, (socklen_t*)&servlen);
-
- if(client_fd < 0){
- printf("failed to accept\n");
- break;
- }
-
- if(ctl_fd == 0){
-
- ctl_fd = client_fd;
-
- ctl_runner(ctl_fd);
-
- break;
-
- } else {
-
- read(client_fd, hello, 37);
- connections += 1;
-
- if(connections == client_num){
- pthread_mutex_lock(&lock);
- write(ctl_fd, ctl_start_1, 1);
- write(ctl_fd, ctl_start_2, 1);
- pthread_mutex_unlock(&lock);
- }
-
- }
-
- if(make_socket_non_blocking(client_fd) < 0){
- printf("accept non-blocking failed\n");
- break;
- }
- for(int i = 0; i < client_num; i++){
- if(client_fds[i] == 0){
- client_fds[i] = client_fd;
- added = 1;
- break;
- }
- }
- if(added != 1){
- printf("accept slot full\n");
- break;
- }
-
- }
- } while(0);
-
- for(int i = 0; i < client_num; i++){
- if(event == 0){
- break;
- }
- client_fd = client_fds[i];
- if(client_fd == 0){
- continue;
- }
- if(FD_ISSET(client_fd, &readfds)){
- valread = 0;
- n = 0;
- event -= 1;
- while(valread < MAXBUFFLEN){
- n = read(client_fd, client_buff[i] + valread, MAXBUFFLEN - valread);
- if(n < 0 && errno != EAGAIN){
-
- printf("fatal\n");
-
- keep = 0;
- break;
- } else if (n < 0 && errno == EAGAIN){
-
- break;
- }
- valread += n;
- }
-
- }
- }
-
- }
-
- return 0;
-}
-
-
-int run_poll(int fd, struct sockaddr_in* servaddr){
-
-
- int connections = 0;
-
- int event = 0;
- struct pollfd* pollfds = NULL;
- int servlen;
- int valread;
- int n;
- int client_fd;
-
- int keep = 1;
-
- servlen = sizeof(*servaddr);
-
- pollfds = (struct pollfd*)malloc((client_num + 1) * sizeof(struct pollfd));
-
- memset(pollfds, 0, (client_num + 1) * sizeof(struct pollfd));
-
- pollfds[0].fd = fd;
- pollfds[0].events = POLLIN;
-
- for(int i = 1; i < client_num + 1; i++){
-
- pollfds[i].fd = 0;
- pollfds[i].events = POLLIN;
-
- }
-
- while(keep){
-
- event = poll(pollfds, client_num + 1, -1);
-
- if ((event < 0 ) && (errno != EINTR)){
- printf("poll error\n");
- break;
- }
-
- do {
-
- if(pollfds[0].revents & POLLIN){
-
- int added = 0;
-
- event -= 1;
-
- client_fd = accept(fd, (struct sockaddr*)servaddr, (socklen_t*)&servlen);
- if(client_fd < 0){
- printf("failed to accept\n");
- break;
- }
-
- if(ctl_fd == 0){
-
- ctl_fd = client_fd;
-
- ctl_runner(ctl_fd);
-
- break;
-
- } else {
-
- read(client_fd, hello, 37);
- connections += 1;
-
- if(connections == client_num){
- pthread_mutex_lock(&lock);
- write(ctl_fd, ctl_start_1, 1);
- write(ctl_fd, ctl_start_2, 1);
- pthread_mutex_unlock(&lock);
- }
-
- }
-
- if(make_socket_non_blocking(client_fd) < 0){
- printf("accept non-blocking failed\n");
- break;
- }
-
- for(int i = 1; i < client_num + 1; i++){
- if(pollfds[i].fd == 0){
- pollfds[i].fd = client_fd;
- added = 1;
- break;
- }
- }
- if(added != 1){
- printf("accept slot full\n");
- break;
- }
-
- }
-
- } while(0);
-
- for(int i = 1; i < client_num + 1; i++){
-
- if(event == 0){
- break;
- }
-
- if(pollfds[i].fd == 0){
- continue;
- }
-
- if(pollfds[i].revents & POLLIN){
-
- valread = 0;
- n = 0;
- event -= 1;
- while(valread < MAXBUFFLEN){
- n = read(pollfds[i].fd, client_buff[i] + valread, MAXBUFFLEN - valread);
- if(n < 0 && errno != EAGAIN){
-
- printf("fatal\n");
-
- keep = 0;
- break;
- } else if (n < 0 && errno == EAGAIN){
-
- break;
- }
- valread += n;
- }
-
- }
-
- }
-
- }
-
-poll_out:
-
- free(pollfds);
-
- return 0;
-}
-
-
-int run_epoll(int fd, struct sockaddr_in* servaddr){
-
- int connections = 0;
-
- int event;
- struct epoll_event ev;
- struct epoll_event* evs = NULL;
- int servlen;
- int valread;
- int n;
- int client_fd;
-
- int keep = 1;
-
- int eplfd = 0;
-
- servlen = sizeof(*servaddr);
-
- eplfd = epoll_create1(0);
-
- if(eplfd == -1){
- printf("failed to create epoll fd\n");
- return -1;
- }
-
- evs = (struct epoll_event*)malloc((client_num + 1) * sizeof(struct epoll_event));
-
- memset(evs, 0, (client_num + 1) * sizeof(struct epoll_event));
-
- ev.data.fd = fd;
- ev.events = EPOLLIN;
-
- if(epoll_ctl(eplfd, EPOLL_CTL_ADD, fd, &ev) < 0){
- printf("epoll add failed\n");
- return -1;
- }
-
- while(keep){
-
- event = epoll_wait(eplfd, evs, client_num + 1, -1);
-
- for(int i = 0 ; i < event; i++){
-
- if (
- evs[i].events & EPOLLHUP ||
- evs[i].events & EPOLLERR ||
- (!(evs[i].events & EPOLLIN))
- ){
- continue;
- }
-
- if(evs[i].data.fd == fd){
-
- int added = 0;
-
- client_fd = accept(fd, (struct sockaddr*)servaddr, (socklen_t*)&servlen);
- if(client_fd < 0){
- printf("failed to accept\n");
- continue;
- }
- if(ctl_fd == 0){
-
- ctl_fd = client_fd;
-
- ctl_runner(ctl_fd);
-
- continue;
-
- } else {
-
- int nn = read(client_fd, hello, 37);
-
- connections += 1;
-
- if(connections == client_num){
-
- pthread_mutex_lock(&lock);
- write(ctl_fd, ctl_start_1, 1);
- write(ctl_fd, ctl_start_2, 1);
- pthread_mutex_unlock(&lock);
- }
-
- }
-
- if(make_socket_non_blocking(client_fd) < 0){
- printf("accept non-blocking failed\n");
- continue;
- }
-
-
- ev.data.fd = client_fd;
- ev.events = EPOLLIN ;
-
- if(epoll_ctl(eplfd, EPOLL_CTL_ADD, client_fd, &ev) < 0){
- printf("epoll add client failed\n");
- continue;
- }
-
- } else {
-
- valread = 0;
- n = 0;
- while(valread < MAXBUFFLEN){
- n = read(evs[i].data.fd, client_buff[i] + valread, MAXBUFFLEN - valread);
- if(n < 0 && errno != EAGAIN){
-
- printf("fatal\n");
-
- keep = 0;
- break;
- } else if (n < 0 && errno == EAGAIN){
-
- break;
- }
- valread += n;
- }
-
- }
-
- }
-
- }
-
-epoll_out:
-
- free(evs);
-
- return 0;
-}
\ No newline at end of file
+++ /dev/null
-#ifndef _IPERF_S_H_
-#define _IPERF_S_H_
-
-#include <stdio.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <pthread.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <errno.h>
-
-#define MAXCLIENT 129
-#define MAXBUFFLEN 65536
-
-extern char mode;
-extern unsigned short port;
-extern int client_num;
-extern int timeout;
-extern int ctl_fd;
-extern uint8_t client_buff[MAXCLIENT][MAXBUFFLEN];
-
-extern pthread_mutex_t lock;
-
-int make_socket_non_blocking (int sfd);
-
-void* ctl_thread(void* varg);
-
-void ctl_runner();
-
-int run_select(int fd, struct sockaddr_in* servaddr);
-
-int run_poll(int fd, struct sockaddr_in* servaddr);
-
-int run_epoll(int fd, struct sockaddr_in* servaddr);
-
-
-
-
-#endif
\ No newline at end of file
+++ /dev/null
-#include "iperf_s.h"
-
-
-char mode = 's';
-unsigned short port = 5001;
-int client_num = 1;
-int timeout = 5;
-
-int ctl_fd = 0;
-uint8_t client_buff[MAXCLIENT][MAXBUFFLEN];
-
-pthread_mutex_t lock;
-
-static void help(){
-
- printf("arguments: mode port client_num timeout\n");
-
- printf("mode: s - select, p - poll, e - epoll\n");
-}
-
-int main(int argc, char** argv){
-
- int result = -1;
-
- int sockfd;
- int opt = 1;
- struct sockaddr_in servaddr;
-
- if(argc != 5){
-
- help();
-
- return -1;
- }
-
- memset(client_buff, 0, MAXCLIENT * MAXBUFFLEN);
-
- if(strcmp(argv[1], "s") == 0){
-
- mode = 's';
- } else if(strcmp(argv[1], "p") == 0){
-
- mode = 'p';
- } else if(strcmp(argv[1], "e") == 0){
-
- mode = 'e';
- } else {
-
- printf("invalid mode: %s\n", argv[1]);
- help();
-
- return -1;
- }
-
- sscanf(argv[2], "%hd", &port);
-
- printf("port to use: %hd\n", port);
-
- sscanf(argv[3], "%d", &client_num);
-
- printf("client num: %d\n", client_num);
-
- if(client_num > MAXCLIENT){
-
- printf("too many clients: %d\n", client_num);
-
- return -1;
- }
-
- sscanf(argv[4], "%d", &timeout);
-
- printf("timeout: %d\n", timeout);
-
- pthread_mutex_init(&lock, NULL);
-
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd == -1) {
- printf("socket creation failed\n");
- return -1;
- } else {
- printf("socket successfully created\n");
- }
-
- if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
- printf("setsockopt failed\n");
- return -1;
- }
-
- memset(&servaddr, 0, sizeof(servaddr));
-
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(port);
-
- if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
- printf("socket bind failed\n");
- return -1;
- }
-
- if(make_socket_non_blocking(sockfd) < 0){
- printf("non-blocking failed\n");
- return -1;
- }
-
- if ((listen(sockfd, client_num + 1)) != 0) {
- printf("listen failed\n");
- return -1;
- }
- if(mode == 's'){
-
- result = run_select(sockfd, &servaddr);
-
- } else if (mode == 'p') {
-
- result = run_poll(sockfd, &servaddr);
-
- } else if (mode == 'e') {
-
- result = run_epoll(sockfd, &servaddr);
- }
-
- return result;
-}
\ No newline at end of file
+++ /dev/null
-#!/bin/bash
-
-
-echo "creating interface..."
-
-sudo ip netns add net1
-
-sudo ip link add dev veth11 type veth peer name veth12 netns net1
-
-sudo ip link set up veth11
-
-sudo ip netns exec net1 ip link set up veth12
-
-sudo ip addr add 192.168.62.5/24 dev veth11
-
-sudo ip netns exec net1 ip addr add 192.168.62.6/24 dev veth12
-
-echo "creating interface!"
--- /dev/null
+#
+
+```shell
+
+./setup.sh
+
+```
+
+#
+
+
+```shell
+
+make
+
+
+```
+
+
+#
+
+```c
+
+
+
+#define MAXCLIENT 10000
+#define CLIENTS_PER_THREAD 100
+#define THREAD_ITER 100
+#define MAXBUFFLEN 65536
+#define PORT 9999
+
+extern char mode;
+extern char server_mode;
+
+extern int client_num;
+extern uint8_t** client_buff;
+
+extern int wfds[MAXCLIENT];
+extern uint8_t wbuff[MAXCLIENT / CLIENTS_PER_THREAD][MAXBUFFLEN];
+extern atomic_uint_fast8_t wdones[MAXCLIENT / CLIENTS_PER_THREAD];
+
+
+void* run_client_thread(void* varg);
+
+int make_socket_non_blocking (int sfd);
+
+
+
+int run_select(int fd, struct sockaddr_in* servaddr);
+
+int run_poll(int fd, struct sockaddr_in* servaddr);
+
+int run_epoll(int fd, struct sockaddr_in* servaddr);
+
+```
+
+
+#
+
+```c
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ max_fd = fd;
+
+ for(int i = 0; i < client_num; i++){
+ client_fd = client_fds[i];
+
+ if(client_fd > 0){
+ FD_SET(client_fd, &readfds);
+ }
+ if(client_fd > max_fd){
+ max_fd = client_fd;
+ }
+
+ }
+
+ event = select(max_fd + 1, &readfds, NULL, NULL, NULL);
+
+```
+
+#
+
+```c
+
+ pollfds[0].fd = fd;
+ pollfds[0].events = POLLIN;
+
+ for(int i = 1; i < client_num + 1; i++){
+
+ pollfds[i].fd = 0;
+ pollfds[i].events = POLLIN;
+
+ }
+
+ while(keep){
+
+ event = poll(pollfds, client_num + 1, -1);
+
+
+ do {
+
+ if(pollfds[0].revents & POLLIN){
+
+...
+
+
+ for(int i = 1; i < client_num + 1; i++){
+
+ idx = i - 1;
+
+ if(event == 0){
+ break;
+ }
+
+ if(pollfds[i].fd == 0){
+ continue;
+ }
+
+ if(pollfds[i].revents & POLLIN){
+
+
+```
+
+#
+
+```c
+
+
+ ev.data.fd = fd;
+ ev.events = EPOLLIN;
+
+ if(epoll_ctl(eplfd, EPOLL_CTL_ADD, fd, &ev) < 0){
+ printf("epoll add failed\n");
+ return -1;
+ }
+
+ while(keep){
+
+ event = epoll_wait(eplfd, evs, client_num + 1, -1);
+
+ for(int i = 0 ; i < event; i++){
+
+ if (
+ evs[i].events & EPOLLHUP ||
+ evs[i].events & EPOLLERR ||
+ (!(evs[i].events & EPOLLIN))
+ ){
+ continue;
+ }
+
+ if(evs[i].data.fd == fd){
+
+...
+
+ } else {
+
+ if(connections != MAXCLIENT){
+
+ continue;
+ } else {
+
+ if(connections_printed == 0){
+
+ printf("connection reached: %d\n", connections);
+ connections_printed = 1;
+ }
+ }
+
+ idx = epoll_get_idx(client_fds, evs[i].data.fd);
+
+ if(idx < 0){
+ printf("epoll get slot failed\n");
+ continue;
+ }
+
+```
+
+
+#
+
+
+```shell
+
+...
+DESCRIPTION top
+ WARNING: select() can monitor only file descriptors numbers that
+ are less than FD_SETSIZE (1024)—an unreasonably low limit for many
+ modern applications—and this limitation will not change. All
+ modern applications should instead use poll(2) or epoll(7), which
+ do not suffer this limitation.
+...
+
+# https://man7.org/linux/man-pages/man2/select.2.html
+```
+
+
+#
+
+
+```c
+
+#define MAXCLIENT 1000
+
+```
+
+
+#
+
+```shell
+
+make clean
+
+make
+
+```
+
+
+#
+
+```shell
+
+ten-k$ sudo ip netns exec net1 ./tenk.out s s
+socket successfully created
+server mode: select
+
+
+```
+
+```shell
+ten-k$ ./tenk.out c 192.168.62.6
+creating connections: 1000
+connectons : 0...
+connectons : 100...
+connectons : 200...
+connectons : 300...
+connectons : 400...
+connectons : 500...
+connectons : 600...
+connectons : 700...
+connectons : 800...
+connectons : 900...
+created connections: 1000
+creating threads: 10
+created threads: 10
+running...
+done
+sec: 0 ms: 152
+```
+
+#
+
+```shell
+
+ten-k$ sudo ip netns exec net1 ./tenk.out s
+p
+socket successfully created
+server mode: poll
+```
+
+```shell
+
+ten-k$ ./tenk.out c 192.168.62.6
+client mode: address: 192.168.62.6
+creating connections: 1000
+connectons : 0...
+connectons : 100...
+connectons : 200...
+connectons : 300...
+connectons : 400...
+connectons : 500...
+connectons : 600...
+connectons : 700...
+connectons : 800...
+connectons : 900...
+created connections: 1000
+creating threads: 10
+created threads: 10
+running...
+done
+sec: 0 ms: 193
+```
+
+#
+
+```shell
+
+ten-k$ sudo ip netns exec net1 ./tenk.out s
+e
+socket successfully created
+server mode: epoll
+
+```
+
+
+```shell
+ten-k$ ./tenk.out c 192.168.62.6
+client mode: address: 192.168.62.6
+creating connections: 1000
+connectons : 0...
+connectons : 100...
+connectons : 200...
+connectons : 300...
+connectons : 400...
+connectons : 500...
+connectons : 600...
+connectons : 700...
+connectons : 800...
+connectons : 900...
+created connections: 1000
+creating threads: 10
+created threads: 10
+running...
+done
+sec: 0 ms: 125
+
+```
+
+#
+
+```c
+#define MAXCLIENT 10000
+
+```
+
+#
+
+```shell
+
+make clean
+make
+
+```
+
+#
+
+```shell
+sudo ip netns exec net1 /bin/bash
+
+
+```
+
+```shell
+
+sudo -i
+
+```
+
+#
+
+```shell
+ten-k# ulimit -n
+1024
+
+ten-k# ulimit -n 10240
+
+
+ten-k# ulimit -n
+10240
+```
+
+#
+
+```shell
+ten-k# ./tenk.out s s
+socket successfully created
+server mode: select
+*** bit out of range 0 - FD_SETSIZE on fd_set ***: terminated
+Aborted (core dumped)
+
+```
+
+```shell
+
+connection with the server failed: 5118
+created connections: 10000
+creating threads: 100
+```
+
+#
+
+```shell
+
+ten-k# ./tenk.out s p
+socket successfully created
+server mode: poll
+```
+```shell
+ten-k# ./tenk.out c 192.168.62.6
+client mode: address: 192.168.62.6
+creating connections: 10000
+connectons : 0...
+connectons : 100...
+connectons : 200...
+connectons : 300...
+connectons : 400.
+...
+connectons : 9500...
+connectons : 9600...
+connectons : 9700...
+connectons : 9800...
+connectons : 9900...
+created connections: 10000
+creating threads: 100
+created threads: 100
+running...
+done
+sec: 3 ms: 453
+
+```
+
+#
+
+```shell
+ten-k# ./tenk.out s e
+socket successfully created
+server mode: epoll
+```
+
+```shell
+ten-k# ./tenk.out c 192.168.62.6
+client mode: address: 192.168.62.6
+creating connections: 10000
+connectons : 0...
+connectons : 100...
+connectons : 200...
+connectons : 300...
+connectons : 400...
+connectons : 500...
+connectons : 600...
+...
+connectons : 9300...
+connectons : 9400...
+connectons : 9500...
+connectons : 9600...
+connectons : 9700...
+connectons : 9800...
+connectons : 9900...
+created connections: 10000
+creating threads: 100
+created threads: 100
+running...
+done
+sec: 0 ms: 139
+```
\ No newline at end of file
--- /dev/null
+GCC_FLAGS := -Wall -O2 -g
+
+all: tenk.o
+
+ gcc $(GCC_FLAGS) -I. -o tenk.out main.c tenk.o -lpthread
+
+
+tenk.o:
+
+ gcc $(GCC_FLAGS) -c -I. -o tenk.o tenk.c
+
+clean:
+ rm -r *.o *.a *.so *.out
\ No newline at end of file
--- /dev/null
+#include "tenk.h"
+
+
+char mode = 's';
+char server_mode = 's';
+
+int client_num = MAXCLIENT;
+uint8_t** client_buff = NULL;
+
+int wfds[MAXCLIENT] = {0};
+uint8_t wbuff[MAXCLIENT/CLIENTS_PER_THREAD][MAXBUFFLEN];
+atomic_uint_fast8_t wdones[MAXCLIENT / CLIENTS_PER_THREAD];
+
+
+
+pthread_mutex_t lock;
+
+static void help(){
+
+ printf("arguments: mode [address|server_mode]\n");
+
+ printf("mode: c - client, s - server\n");
+ printf("address: server address in client mode\n");
+ printf("server_mode: s - select, p - poll, e - epoll\n");
+}
+
+int main(int argc, char** argv){
+
+ int result = -1;
+
+ int sockfd;
+ int opt = 1;
+ struct sockaddr_in servaddr;
+
+ if(argc != 3){
+
+ help();
+
+ return -1;
+ }
+
+ if(strcmp(argv[1], "c") == 0){
+
+ mode = 'c';
+
+ } else if (strcmp(argv[1], "s") == 0){
+
+ mode = 's';
+ } else {
+
+ printf("invalid mode: %s\n", argv[1]);
+ help();
+
+ return -1;
+
+ }
+
+ if(mode == 'c'){
+
+ printf("client mode: address: %s\n", argv[2]);
+
+ pthread_t tids[MAXCLIENT / CLIENTS_PER_THREAD];
+ int ids[MAXCLIENT / CLIENTS_PER_THREAD];
+
+ int connfd;
+ struct sockaddr_in servaddr;
+
+ printf("creating connections: %d\n", MAXCLIENT);
+
+ for(int i = 0; i < MAXCLIENT; i++){
+
+ connfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connfd == -1) {
+ printf("client socket creation failed: %d\n", i);
+ result = -1;
+ break;
+ }
+
+ memset(&servaddr, 0, sizeof(servaddr));
+
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = inet_addr(argv[2]);
+ servaddr.sin_port = htons(PORT);
+
+ if (connect(connfd, (struct sockaddr*)&servaddr, sizeof(servaddr))!= 0) {
+ printf("connection with the server failed: %d\n", i);
+ result = -1;
+ break;
+ }
+
+ if(i % 100 == 0){
+ printf("connectons : %d...\n", i);
+ }
+
+ wfds[i] = connfd;
+
+ }
+
+ printf("created connections: %d\n", MAXCLIENT);
+
+ int thread_count = MAXCLIENT / CLIENTS_PER_THREAD;
+
+ printf("creating threads: %d\n", thread_count);
+
+ for(int i = 0; i < thread_count; i++){
+
+ ids[i] = i;
+ wdones[i] = 0;
+ pthread_create(&tids[i], NULL, run_client_thread, (void*)&ids[i]);
+
+ }
+
+ printf("created threads: %d\n", thread_count);
+
+ printf("running...\n");
+
+ struct timeval t1, t2;
+
+ gettimeofday(&t1, NULL);
+
+ gettimeofday(&t2, NULL);
+
+ while(1){
+
+ int count = 0;
+
+ for(int i = 0 ; i < thread_count; i++){
+
+ if(wdones[i] == 1){
+ count += 1;
+ }
+
+ }
+
+ if(count == thread_count){
+
+ printf("done\n");
+ break;
+ }
+ }
+
+ gettimeofday(&t2, NULL);
+
+
+ uint32_t seconds = t2.tv_sec - t1.tv_sec;
+ uint32_t ms = (t2.tv_usec - t1.tv_usec) / 1000;
+
+ printf("sec: %lu ms: %lu\n", seconds, ms);
+
+ }
+
+ if(mode == 's'){
+
+ if(strcmp(argv[2], "s") == 0){
+
+ server_mode = 's';
+ } else if(strcmp(argv[2], "p") == 0){
+
+ server_mode = 'p';
+ } else if(strcmp(argv[2], "e") == 0){
+
+ server_mode = 'e';
+ } else {
+
+ printf("invalid server mode: %s\n", argv[2]);
+ help();
+
+ return -1;
+ }
+
+ client_buff = (uint8_t**)malloc(client_num * sizeof(uint8_t*));
+
+ for(int i = 0; i < client_num; i++){
+
+ client_buff[i] = (uint8_t*)malloc(MAXBUFFLEN * sizeof(uint8_t));
+
+ }
+
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ printf("socket creation failed\n");
+ return -1;
+ } else {
+ printf("socket successfully created\n");
+ }
+
+ if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
+ printf("setsockopt failed\n");
+ return -1;
+ }
+
+ memset(&servaddr, 0, sizeof(servaddr));
+
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(PORT);
+
+ if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
+ printf("socket bind failed\n");
+ return -1;
+ }
+
+ if(make_socket_non_blocking(sockfd) < 0){
+ printf("non-blocking failed\n");
+ return -1;
+ }
+
+ if ((listen(sockfd, client_num + 1)) != 0) {
+ printf("listen failed\n");
+ return -1;
+ }
+ if(server_mode == 's'){
+
+ result = run_select(sockfd, &servaddr);
+
+ } else if (server_mode == 'p') {
+
+ result = run_poll(sockfd, &servaddr);
+
+ } else if (server_mode == 'e') {
+
+ result = run_epoll(sockfd, &servaddr);
+ }
+
+ for(int i = 0 ; i < client_num; i++){
+
+ free(client_buff[i]);
+
+ }
+
+ free(client_buff);
+ }
+
+
+ return result;
+}
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+
+
+echo "creating interface..."
+
+sudo ip netns add net1
+
+sudo ip link add dev veth11 type veth peer name veth12 netns net1
+
+sudo ip link set up veth11
+
+sudo ip netns exec net1 ip link set up veth12
+
+sudo ip addr add 192.168.62.5/24 dev veth11
+
+sudo ip netns exec net1 ip addr add 192.168.62.6/24 dev veth12
+
+echo "created interface!"
--- /dev/null
+#include "tenk.h"
+
+
+
+void* run_client_thread(void* varg){
+
+ int tid = *(int*)varg;
+
+ int fdstart = tid * CLIENTS_PER_THREAD;
+
+ int fdend = tid + CLIENTS_PER_THREAD;
+
+ int count = 0;
+
+ int n = 0;
+
+ while(count < THREAD_ITER){
+
+ if(getrandom(wbuff[tid], MAXBUFFLEN, 0) < 0){
+
+ printf("getrandom failed\n");
+
+ continue;
+ }
+
+ for(int i = fdstart; i < fdend; i++){
+
+ n = write(wfds[i], wbuff[tid], MAXBUFFLEN);
+
+ if(n <= 0){
+
+ printf("failed to write: %d\n", i);
+
+ continue;
+
+ }
+
+ }
+
+ count += 1;
+
+ }
+
+ wdones[tid] = 1;
+
+ pthread_exit(NULL);
+
+}
+
+
+
+int make_socket_non_blocking(int sfd){
+ int flags, s;
+
+ flags = fcntl (sfd, F_GETFL, 0);
+ if (flags == -1){
+ printf("fcntl get");
+ return -1;
+ }
+
+ flags |= O_NONBLOCK;
+ s = fcntl (sfd, F_SETFL, flags);
+ if (s == -1){
+ printf("fcntl set");
+ return -2;
+ }
+ return 0;
+}
+
+
+int run_select(int fd, struct sockaddr_in* servaddr){
+
+ printf("server mode: select\n");
+
+ int connections = 0;
+ int connections_printed = 0;
+
+ int max_fd = 0;
+ int event = 0;
+ fd_set readfds;
+ int servlen;
+ int client_fds[MAXCLIENT] = {0};
+ int valread;
+ int n;
+ int client_fd;
+
+ int keep = 1;
+
+ servlen = sizeof(*servaddr);
+
+ while(keep){
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ max_fd = fd;
+
+ for(int i = 0; i < client_num; i++){
+ client_fd = client_fds[i];
+
+ if(client_fd > 0){
+ FD_SET(client_fd, &readfds);
+ }
+ if(client_fd > max_fd){
+ max_fd = client_fd;
+ }
+
+ }
+
+ event = select(max_fd + 1, &readfds, NULL, NULL, NULL);
+
+ if ((event < 0 ) && (errno != EINTR)){
+ printf("select error\n");
+ break;
+ }
+
+ do {
+ if(FD_ISSET(fd, &readfds)){
+ int added = 0;
+ event -= 1;
+ client_fd = accept(fd, (struct sockaddr*)servaddr, (socklen_t*)&servlen);
+
+ if(client_fd < 0){
+
+ break;
+ }
+
+
+ if(make_socket_non_blocking(client_fd) < 0){
+ printf("accept non-blocking failed\n");
+ break;
+ }
+ for(int i = 0; i < client_num; i++){
+ if(client_fds[i] == 0){
+ client_fds[i] = client_fd;
+ added = 1;
+ break;
+ }
+ }
+ if(added != 1){
+ printf("accept slot full\n");
+ break;
+ }
+
+ connections += 1;
+
+ }
+ } while(0);
+
+ if(connections != MAXCLIENT){
+
+ continue;
+ } else {
+
+ if(connections_printed == 0){
+
+ printf("connection reached: %d\n", connections);
+ connections_printed = 1;
+ }
+ }
+
+ for(int i = 0; i < client_num; i++){
+ if(event == 0){
+ break;
+ }
+ client_fd = client_fds[i];
+ if(client_fd == 0){
+ continue;
+ }
+ if(FD_ISSET(client_fd, &readfds)){
+ valread = 0;
+ n = 0;
+ event -= 1;
+ while(valread < MAXBUFFLEN){
+ n = read(client_fd, client_buff[i] + valread, MAXBUFFLEN - valread);
+ if(n < 0 && errno != EAGAIN){
+
+ printf("fatal\n");
+
+ keep = 0;
+ break;
+ } else if (n < 0 && errno == EAGAIN){
+
+ break;
+ }
+ valread += n;
+ }
+
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+
+int run_poll(int fd, struct sockaddr_in* servaddr){
+
+ printf("server mode: poll\n");
+
+
+ int connections = 0;
+ int connections_printed = 0;
+
+ int event = 0;
+ struct pollfd* pollfds = NULL;
+ int servlen;
+ int valread;
+ int n;
+ int client_fd;
+
+ int idx;
+
+ int keep = 1;
+
+ servlen = sizeof(*servaddr);
+
+ pollfds = (struct pollfd*)malloc((client_num + 1) * sizeof(struct pollfd));
+
+ memset(pollfds, 0, (client_num + 1) * sizeof(struct pollfd));
+
+ pollfds[0].fd = fd;
+ pollfds[0].events = POLLIN;
+
+ for(int i = 1; i < client_num + 1; i++){
+
+ pollfds[i].fd = 0;
+ pollfds[i].events = POLLIN;
+
+ }
+
+ while(keep){
+
+ event = poll(pollfds, client_num + 1, -1);
+
+
+ do {
+
+ if(pollfds[0].revents & POLLIN){
+
+ int added = 0;
+
+ event -= 1;
+
+ client_fd = accept(fd, (struct sockaddr*)servaddr, (socklen_t*)&servlen);
+ if(client_fd < 0){
+
+ break;
+ }
+
+ if(make_socket_non_blocking(client_fd) < 0){
+ printf("accept non-blocking failed\n");
+ break;
+ }
+
+ for(int i = 1; i < client_num + 1; i++){
+ if(pollfds[i].fd == 0){
+ pollfds[i].fd = client_fd;
+ added = 1;
+ break;
+ }
+ }
+ if(added != 1){
+ printf("accept slot full\n");
+ break;
+ }
+
+ connections += 1;
+
+ }
+
+ } while(0);
+
+ if(connections != MAXCLIENT){
+
+ continue;
+ } else {
+
+ if(connections_printed == 0){
+
+ printf("connection reached: %d\n", connections);
+ connections_printed = 1;
+ }
+ }
+
+
+ for(int i = 1; i < client_num + 1; i++){
+
+ idx = i - 1;
+
+ if(event == 0){
+ break;
+ }
+
+ if(pollfds[i].fd == 0){
+ continue;
+ }
+
+ if(pollfds[i].revents & POLLIN){
+
+ valread = 0;
+ n = 0;
+ event -= 1;
+ while(valread < MAXBUFFLEN){
+ n = read(pollfds[i].fd, client_buff[idx] + valread, MAXBUFFLEN - valread);
+ if(n < 0 && errno != EAGAIN){
+
+ printf("fatal\n");
+
+ keep = 0;
+ break;
+ } else if (n < 0 && errno == EAGAIN){
+
+ break;
+ }
+ valread += n;
+ }
+
+ }
+
+ }
+
+ }
+
+poll_out:
+
+ free(pollfds);
+
+ return 0;
+}
+
+static inline int epoll_add_idx(int* client_fds, int fd){
+
+ int done = 0;
+ int idx = fd % MAXCLIENT;
+ int start_idx = idx;
+
+ while(done == 0){
+
+ if(client_fds[idx] == 0){
+
+ client_fds[idx] = fd;
+
+ done = idx;
+
+ break;
+ } else {
+ idx += 1;
+ }
+
+ if(idx == MAXCLIENT){
+ idx = 0;
+ }
+
+ if(idx == start_idx){
+ done = -1;
+ }
+
+ }
+
+ return done;
+}
+
+static inline int epoll_get_idx(int* client_fds, int fd){
+
+ int done = 0;
+ int idx = fd % MAXCLIENT;
+ int start_idx = idx;
+
+ while(done == 0){
+
+ if(client_fds[idx] == fd){
+
+ done = idx;
+
+ break;
+ } else {
+ idx += 1;
+ }
+
+ if(idx == MAXCLIENT){
+ idx = 0;
+ }
+
+ if(idx == start_idx){
+ done = -1;
+ }
+
+ }
+
+ return done;
+}
+
+int run_epoll(int fd, struct sockaddr_in* servaddr){
+
+ printf("server mode: epoll\n");
+
+
+ int connections = 0;
+ int connections_printed = 0;
+
+ int event;
+ struct epoll_event ev;
+ struct epoll_event* evs = NULL;
+ int servlen;
+ int valread;
+ int n;
+ int client_fd;
+
+ int client_fds[MAXCLIENT] = {0};
+
+ int idx;
+
+ int keep = 1;
+
+ int eplfd = 0;
+
+ servlen = sizeof(*servaddr);
+
+ eplfd = epoll_create1(0);
+
+ if(eplfd == -1){
+ printf("failed to create epoll fd\n");
+ return -1;
+ }
+
+ evs = (struct epoll_event*)malloc((client_num + 1) * sizeof(struct epoll_event));
+
+ memset(evs, 0, (client_num + 1) * sizeof(struct epoll_event));
+
+ ev.data.fd = fd;
+ ev.events = EPOLLIN;
+
+ if(epoll_ctl(eplfd, EPOLL_CTL_ADD, fd, &ev) < 0){
+ printf("epoll add failed\n");
+ return -1;
+ }
+
+ while(keep){
+
+ event = epoll_wait(eplfd, evs, client_num + 1, -1);
+
+ for(int i = 0 ; i < event; i++){
+
+ if (
+ evs[i].events & EPOLLHUP ||
+ evs[i].events & EPOLLERR ||
+ (!(evs[i].events & EPOLLIN))
+ ){
+ continue;
+ }
+
+ if(evs[i].data.fd == fd){
+
+ int added = 0;
+
+ client_fd = accept(fd, (struct sockaddr*)servaddr, (socklen_t*)&servlen);
+ if(client_fd < 0){
+
+ continue;
+ }
+
+
+ if(make_socket_non_blocking(client_fd) < 0){
+ printf("accept non-blocking failed\n");
+ continue;
+ }
+
+
+ ev.data.fd = client_fd;
+ ev.events = EPOLLIN ;
+
+ if(epoll_ctl(eplfd, EPOLL_CTL_ADD, client_fd, &ev) < 0){
+ printf("epoll add client failed\n");
+ continue;
+ }
+
+ idx = epoll_add_idx(client_fds, client_fd);
+
+ if(idx < 0){
+ printf("epoll add slot full\n");
+ continue;
+ }
+
+ connections += 1;
+
+ } else {
+
+ if(connections != MAXCLIENT){
+
+ continue;
+ } else {
+
+ if(connections_printed == 0){
+
+ printf("connection reached: %d\n", connections);
+ connections_printed = 1;
+ }
+ }
+
+ idx = epoll_get_idx(client_fds, evs[i].data.fd);
+
+ if(idx < 0){
+ printf("epoll get slot failed\n");
+ continue;
+ }
+
+ valread = 0;
+ n = 0;
+ while(valread < MAXBUFFLEN){
+ n = read(evs[i].data.fd, client_buff[idx] + valread, MAXBUFFLEN - valread);
+ if(n < 0 && errno != EAGAIN){
+
+ printf("fatal\n");
+
+ keep = 0;
+ break;
+ } else if (n < 0 && errno == EAGAIN){
+
+ break;
+ }
+ valread += n;
+ }
+
+ }
+
+ }
+
+ }
+
+epoll_out:
+
+ free(evs);
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#ifndef _TEN_K_H_
+#define _TEN_K_H_
+
+#include <stdio.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <stdatomic.h>
+#include <sys/time.h>
+#include <sys/random.h>
+
+#define MAXCLIENT 10000
+#define CLIENTS_PER_THREAD 100
+#define THREAD_ITER 100
+#define MAXBUFFLEN 65536
+#define PORT 9999
+
+extern char mode;
+extern char server_mode;
+
+extern int client_num;
+extern uint8_t** client_buff;
+
+extern int wfds[MAXCLIENT];
+extern uint8_t wbuff[MAXCLIENT / CLIENTS_PER_THREAD][MAXBUFFLEN];
+extern atomic_uint_fast8_t wdones[MAXCLIENT / CLIENTS_PER_THREAD];
+
+
+void* run_client_thread(void* varg);
+
+int make_socket_non_blocking (int sfd);
+
+
+
+int run_select(int fd, struct sockaddr_in* servaddr);
+
+int run_poll(int fd, struct sockaddr_in* servaddr);
+
+int run_epoll(int fd, struct sockaddr_in* servaddr);
+
+
+
+
+#endif
\ No newline at end of file