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);
...
}