linux网络编程练习及各种IO模型性能测试

GIT地址

https://github.com/liang8305/network_performance_test

Block IO

首先使用最基本的阻塞IO来写; 运行 block_io_server 和 block_io_client

...
conn:1016
conn:1017
conn:1018
conn:1019
conn:1020
Server Accept Failed!

每次都是到1020个连接就没办法再增加了! 1020? 1024? 马上想到是打开文件数限制,于是增加到65500;

sudo vim /etc/security/limits.conf
文件尾追加 
* hard nofile 65500
* soft nofile 65500

根据limits.conf 的注释, 追加的4个参数的含义分别为:

Each line describes a limit for a user in the form:

<domain>  <type>  <item>  <value>

<domain>:   可以是用户,也可以是组,要用@group这样的语法,也可以是通配符如*%
        - an user name
        - a group name, with @group syntax
        - the wildcard *, for default entry
        - the wildcard %, can be also used with %group syntax,
                 for maxlogin limit
        - NOTE: group and wildcard limits are not applied to root.
          To apply a limit to the root user, <domain> must be
          the literal username root.

<type> :       - "hard" for enforcing hard limits

<item>:     第三列, 设置的项目, nofile 为 最大打开文件数
        - core - limits the core file size (KB)
        - nofile - max number of open files 
...

重启系统后验证, 显示65500 则设置成功;

%ulimit -n  
65500

之后运行, 基本做到10000个连接; server就挂掉了
不过现在是单机连单机的情况;

发现的问题: 创建线程的坑

网上很多多线程socket示例都是使用如下逻辑:

//创建socket
循环{
    int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
    connect(socket_fd, ....);
    //创建线程,并把socket句柄传给线程
    pthread_create(&tid, NULL, loop, (void *) &socket_fd)
}

//然后在线程的function中
void * loop(void *arg) {
	int socket = *((int *) arg);
	...
}

但是实际上这样是错误的; 会有并发问题;
因为 int socket_fd 看起来每次循环都”声明”了一个变量; 但是在c语言中,每个变量只声明一次, 分配一次地址;
添加一行代码验证,

int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
printf("socket_fd:%d, add:%d\n",socket_fd,&socket_fd);

可看到不同句柄的地址都是一致的

...
socket_fd 5, add:2665480
socket_fd 6, add:2665480
socket_fd 7, add:2665480
...

那么对于同一个内存的数据的读取和取出是在不同线程中, 则会有并发问题; 就比如生成socket1之后创建线程A, 线程A并没有马上获得cpu, 然后主线程又 生成了一个socket2,再创建线程B, 此时, 线程A和B取出来的socket值都将是2

可以验证, 在线程中加个睡眠:

void * loop(void *arg) {
    sleep(1);
    int socket = *((int *) arg);
    printf("thread get socket%d\n",socket);
    ...
}