概念
IO复用:用于表示多个网络链接复用一个IO线程,具有开销小的优点,但是同样的编程的复杂度就会比较高;
IO复用使用的几个函数
select
int select (int maxfd,fd_set *rdset,fd_set*wrset,fd_set *exset,struct timeval *timeout);
maxfd:表示需要监视的最大文件描述符值+1;
rdset:需要检测的刻度文件描述符集合;
wrset:需要检测的可写文件描述符集合;
exset:需要检测的异常文件描述符集合;
timeout:超时时间
返回值:-1表示出错,0表示超时,>0表示获取到的数据;
同时还需要掌握的几个函数包括:
FD_ZERO(fd_set *fdset):用于清空文件描述符集合
fd_set rfds;
FD_ZERO(&RFDS);
FD_SET(int fd,fd_set *fd_set):向文件描述符中增加一个新的文件描述符
FD_SET(listenfd,&rfds);
int maxfdp1 = listenfd + 1;
int connfds[FD_SETSIZE-1];
size_t connfds_cnt = 0;
for(;;){
int i;
FD_SET(listenfd,&rfds);
for(i=0;i<connfds_cnt;i++){
FD_SET(connfds[i],&rfds);
printf("FD_SET(%d)\n",connfds[i]);
}
FD_CLR(int fd, fd_set *fdset):在文件描述符集合中删除应文件描述符
if(0 == len){
printf("close %d\n",connfds[i]);
close(connfds[i]);
FD_CLR(connfds[i],&rfds);
memcpy(connfds+i,connfd+i+1,connfds_cnt-i-1);
connfds_cnt--;
i--;
continue;
}
FD_ISSET(int fd,fd_set *fdset):用于测试指定的文件描述符是否在该集合中;
if(FD_ISSET(connfds[i],&rfds)){
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
ssize_t len;
if((len = read(connfds[i],buf,BUFSIZ-1)) == -1){
perror("read err");
//return 1;
}
if(0 == len){
printf("close %d\n",connfds[i]);
close(connfds[i]);
FD_CLR(connfds[i],&rfds);
memcpy(connfds+i,connfd+i+1,connfds_cnt-i-1);
connfds_cnt--;
i--;
continue;
}
}
FD_SETSIZE:是一个常数值表示的是265;
提供一个完整的tcp_server_select.c程序:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#define max(a,b) ((a)>(b)?(a):(b))
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port>\n",argv[0]);
return 1;
}
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listenfd){
perror("listenfd open err");
return 1;
}
printf("socket create OK\n");
int flag = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(argv[1]);
local_addr.sin_port = htons(atoi(argv[2]));
if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
perror("bind err");
return 1;
}
printf("bind OK\n");
if(-1 == listen(listenfd,10)){
perror("listen err");
return 1;
}
printf("listen OK\n");
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(listenfd,&rfds);
int maxfdp1 = listenfd + 1;
int connfds[FD_SETSIZE-1];
size_t connfds_cnt = 0;
for(;;){
int i;
FD_SET(listenfd,&rfds);
for(i=0;i<connfds_cnt;i++){
FD_SET(connfds[i],&rfds);
printf("FD_SET(%d)\n",connfds[i]);
}
printf("before select:%lu\n",rfds);
if(-1 == select(maxfdp1,&rfds,NULL,NULL,NULL)){
perror("select error");
return 1;
}
printf("after select:%lu\n",rfds);
if(FD_ISSET(listenfd,&rfds)){
printf("listenfd ready\n");
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
socklen_t remote_addr_len = sizeof(remote_addr);
int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
if(-1 == connfd){
perror("accept err");
//return 1;
}
if(connfds_cnt+1 == FD_SETSIZE-1){
fprintf(stderr,"connfd size over %d\n",FD_SETSIZE-1);
close(connfds[i]);
}else{
connfds[connfds_cnt++] = connfd;
maxfdp1 = max(connfd,maxfdp1-1)+1;
show_info(connfd);
}
}
for(i=0;i<connfds_cnt;i++){
if(-1 == connfds[i]){
continue;
}
if(FD_ISSET(connfds[i],&rfds)){
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
ssize_t len;
if((len = read(connfds[i],buf,BUFSIZ-1)) == -1){
perror("read err");
//return 1;
}
if(0 == len){
printf("close %d\n",connfds[i]);
close(connfds[i]);
FD_CLR(connfds[i],&rfds);
memcpy(connfds+i,connfd+i+1,connfds_cnt-i-1);
connfds_cnt--;
i--;//鏁扮粍鍙戠敓鍙樺寲锛岄噸鏂板垽鏂璱鐨刦d
continue;
}
printf("server recv:%s\n",buf);
int fd = open(buf,O_RDONLY);
if(-1 == fd){
perror("open file err");
}
struct stat file_stat;
fstat(fd,&file_stat);
if(-1 == sendfile(connfds[i],fd,NULL,file_stat.st_size)){
perror("sendfile err");
}
printf("server send file %s ok\n",buf);
close(fd);
}
}
}
close(listenfd);
}
对于select模式的缺点:
1、需要修改传入的参数数组;
2、不能够确切指定有数据的socket;
3、只能够监视FD_SETSIZE数目个连接;
4、线程不安全;
Poll模式
Poll模式具备的优点:
1、不需要修改传入的参数数组
2、可以监视任意个连接,可以通过cat /proc/sys/file-max进行查看
缺点:
1、不能够确切的指定有数据的socket
2、线程不安全
poll模型需要使用的函数是int poll(struct pollfd *fdarray,usigned long nfds,int timeout);
struct pollfd *fdarray {
fd:表示文件描述符号
struct profile{
events:表示监视的事件;
revents:表示实际发生的事件;
};
};
对于events支持的选项有:
输入:POLLRDNOPM
:表示普通数据;POLLRDBAND
:优先级带数据;POLLIN
:普通或者优先级带数据;
输出:POLLWRNOPM
:表示普通数据;POLLWRBAND
:优先级带数据;POLLOUT
:普通或者优先级带数据;
对于revents支持的选项包括:
输入:POLLRDNOPM
:普通数据;POLLRDBAND
:优先级带数据;POLLIN
:普通或者优先级带数据;
输出:POLLWRNORW
:普通数据;POLLWRBAND
:优先级带数据;POOLLOUT
:普通或者优先级带数据;
错误:POLLERR
:发生错误;POLLHUP
:发生挂起;POLLNVAL
:描述符非法;
No | 常量 | events | revents | 说明 |
---|---|---|---|---|
1 | POLLIN | OK | OK | 普通或者优先级带数据可读; |
2 | POLLRDNORM | OK | OK | 普通数据可读 |
3 | POLLRDBAND | OK | OK | 优先级带数据可读 |
4 | POLLPRI | OK | OK | 高优先级数据可读 |
5 | POLLOUT | OK | OK | 普通数据可写 |
6 | POLLWRNORM | OK | OK | 普通数据可写 |
7 | POLLWRBAND | OK | OK | 优先级带数据可写 |
8 | POLLERR | NG | OK | 发生错误 |
9 | POLLHUP | NG | OK | 发生挂起 |
10 | POLLNVAL | NG | OK | 描述字不是一个打开的文件 |
其余的参数的含义
nfds:表示数组元素的个数;
timeout;用于定义等待的时间;INFTIM
:表示永久等待;0:表示立即返回;>0:表示等待描述;
返回值0:表示超时;-1:表示出错;正数:表示就绪的描述符的个数;
普通数据:表示的含义是正规的TCP数据以及所有的UDP数据;优先级带数据:表示TCP带外的数据;
tcp_server_poll.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <linux/fs.h>
#define max(a,b) ((a)>(b)?(a):(b))
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port>\n",argv[0]);
return 1;
}
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listenfd){
perror("listenfd open err");
return 1;
}
printf("socket create OK\n");
int flag = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(argv[1]);
local_addr.sin_port = htons(atoi(argv[2]));
if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
perror("bind err");
return 1;
}
printf("bind OK\n");
if(-1 == listen(listenfd,10)){
perror("listen err");
return 1;
}
printf("listen OK\n");
struct pollfd poll_fd[INR_OPEN_MAX];
poll_fd[0].fd = listenfd;
poll_fd[0].events = POLLRDNORM;
size_t poll_fd_cnt = 1;
for(;;){
if(-1 != poll(poll_fd,poll_fd_cnt,-1)){
if(poll_fd[0].revents == POLLRDNORM){
printf("accept listenfd\n");
int connfd = accept(listenfd,NULL,NULL);
if(-1 == connfd){
perror("accept err");
}else{
if(poll_fd_cnt+1 == INR_OPEN_MAX){
fprintf(stderr,"connfd size over %d",INR_OPEN_MAX);
close(connfd);
}else{
poll_fd[poll_fd_cnt].fd = connfd;
poll_fd[poll_fd_cnt].events = POLLRDNORM;
poll_fd_cnt++;
}
}
}
int i;
for(i=1;i<poll_fd_cnt;i++){
if(poll_fd[i].revents & POLLRDNORM){
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
ssize_t len;
printf("read connfd %d\n",poll_fd[i].fd);
if((len = read(poll_fd[i].fd,buf,BUFSIZ-1)) == -1){
perror("read err");
//return 1;
}
if(0 == len){
printf("close %d\n",poll_fd[i].fd);
printf("%d vs %d\n",poll_fd[i].revents,poll_fd[i].revents);
close(poll_fd[i].fd);
printf("%d vs %d\n",poll_fd[i].revents,poll_fd[i].revents);
memcpy(poll_fd+i,poll_fd+i+1,poll_fd_cnt-i-1);
poll_fd_cnt--;
i--;
continue;
//break;
}
printf("server recv:%s\n",buf);
int fd = open(buf,O_RDONLY);
if(-1 == fd){
perror("open file err");
}
struct stat file_stat;
fstat(fd,&file_stat);
if(-1 == sendfile(poll_fd[i].fd,fd,NULL,file_stat.st_size)){
perror("sendfile err");
}
printf("server send file %s ok\n",buf);
close(fd);
}
}
}
}
close(listenfd);
}
tcp_client_poll.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
#define max(a,b) ((a)>(b)?(a):(b))
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port> \n",argv[0]);
return 1;
}
int connfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == connfd){
perror("socket err");
return 1;
}
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
perror("connect err");
return 1;
}
show_info(connfd);
printf("connfd:%d\n",connfd);
struct pollfd poll_fds[2];
poll_fds[0].fd = connfd;
poll_fds[0].events = POLLRDNORM;
poll_fds[1].fd = STDIN_FILENO;
poll_fds[1].events = POLLRDNORM;
char buf[BUFSIZ];
for(;;){
if(-1 != poll(poll_fds,2,-1)){
if(poll_fds[0].fd == connfd && poll_fds[0].revents & POLLRDNORM){
bzero(buf,BUFSIZ);
printf("recv msg\n");
ssize_t n;
if((n = read(connfd,buf,BUFSIZ)) == -1){
perror("read err");
return 1;
}else if(0 == n){
printf("server close\n");
break;
}
printf("client recv:%s\n",buf);
}
if(poll_fds[1].fd == STDIN_FILENO && poll_fds[1].revents & POLLRDNORM){
bzero(buf,BUFSIZ);
printf("send msg\n");
fgets(buf,BUFSIZ,stdin);
write(connfd,buf,strlen(buf)-1);
}
}
}
close(connfd);
}
EPOLL模型
优点:能够确切地指定有数据的socket,并且线程是安全的;
Epoll模型的创建
使用函数int eploo_create(int size)
来进行创建,size用于指定监听的数目,返回值通常是文件描述符,在/proc/进程ID/fd
可以进行查看;
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(argv[1]);
local_addr.sin_port = htons(atoi(argv[2]));
if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
perror("bind err");
return 1;
}
printf("bind OK\n");
if(-1 == listen(listenfd,10)){
perror("listen err");
return 1;
}
printf("listen OK\n");
int epoll_fd = epoll_create(INR_OPEN_MAX);
Epoll模型的控制
Epoll_event | 说明 |
---|---|
EPOLLOUT | 表示对应的文件描述符可写 |
EPOLLPRI | 表示对应的文件描述符有紧急的数据可读 |
EPOLLERR | 表示对应文件描述符发生错误 |
EPOLLHUP | 表示对应的文件描述符被挂断 |
EPOLLET | 表示对应的文件描述符设定为edge模式 |
使用函数int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event)
;来进行epoll模型的控制;
epfd
:表示epoll
文件描述符;
op
:用于定义对于文件描述符的操作,EPOLL_CTL_ADD
:表示用于创建;EPOLL_CTL_MOD
:表示用于修改某些类型;EPOLL_CTL_DEL
:表示用于删除;fd
:表示相互关联的文件描述符;event
:表示指向epoll_event的指针;
Epoll_event | 说明 |
---|---|
EPOLLOUT | 表示对应的文件描述符可写 |
EPOLLPRI | 表示对应的文件描述符有紧急的数据可读 |
EPOLLERR | 表示对应文件描述符发生错误 |
EPOLLHUP | 表示对应的文件描述符被挂断 |
EPOLLET | 表示对应的文件描述符设定为edge模式 |
返回值:0表示成功,-1表示失败;
struct epoll_event evt;
evt.data.fd = listenfd;
evt.events = EPOLLIN;
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listenfd,&evt);
轮询IO事件
int epoll_wait(int epfd,struct epoll_event events,int max events,int timeout)
;
epfd
:表示epoll文件描述符;
epoll_events
:用于回传待处理事件的数组;
maxevents
:每次能够处理的事件数;
timeout
:等待IO事件发生的超时值;-1表示永不超时;0表示立即返回;
返回值
:正数表示发生事件数;-1:表示错误;
struct epoll_event out_evts[out_evts_cnt];
int fd_cnt = epoll_wait(epoll_fd,out_evts,out_evts_cnt,-1);
Epoll模型的两种模式:
ET(Edge Triggered)
模式
LT(Level Triggered)
模式
1、表示管道读者的文件句柄注册到epoll中;
2、管道写着向管道写入2KB的数据;
3、调用epoll_wait可以获得管道读者已经就绪的文件句柄;
4、管道读者读取1Kb的数据;
5、一次epoll_wait调用完成;
如果执行的是ET模式,管道中剩余的1Kb数据就会被挂起,等待再次调用epoll_wait()
,得不到管道读者的文件句柄,除非有新的数据写入管道,如果是LT模式,只要管道中有数据可读,每次调用epoll_wait()
都会触发;
还有一点区别就是设为ET模式的文件句柄必须是非阻塞的;
tcp_server_epoll.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#define max(a,b) ((a)>(b)?(a):(b))
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port> \n",argv[0]);
return 1;
}
int connfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == connfd){
perror("socket err");
return 1;
}
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
perror("connect err");
return 1;
}
show_info(connfd);
printf("connfd:%d\n",connfd);
struct epoll_event in_evts[2];
in_evts[0].data.fd = connfd;
in_evts[0].events = EPOLLIN;
in_evts[1].data.fd = STDIN_FILENO;
in_evts[1].events = EPOLLIN;
int epoll_fd = epoll_create(2);
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,connfd,in_evts);
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,STDIN_FILENO,in_evts+1);
char buf[BUFSIZ];
for(;;){
struct epoll_event out_evts[2];
int fd_cnt = epoll_wait(epoll_fd,out_evts,2,-1);
int i;
for(i=0;i<fd_cnt;i++){
if(out_evts[i].data.fd == connfd && out_evts[i].events & EPOLLIN){
bzero(buf,BUFSIZ);
printf("recv msg\n");
ssize_t n;
if((n = read(connfd,buf,BUFSIZ)) == -1){
perror("read err");
return 1;
}else if(0 == n){
printf("server close\n");
break;
}
printf("client recv:%s\n",buf);
}
if(out_evts[i].data.fd == STDIN_FILENO && out_evts[i].events & EPOLLIN){
bzero(buf,BUFSIZ);
printf("send msg\n");
fgets(buf,BUFSIZ,stdin);
write(connfd,buf,strlen(buf)-1);
}
}
}
close(connfd);
}
tcp_client_epoll.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <linux/fs.h>
#define max(a,b) ((a)>(b)?(a):(b))
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port>\n",argv[0]);
return 1;
}
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listenfd){
perror("listenfd open err");
return 1;
}
printf("socket create OK\n");
int flag = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(argv[1]);
local_addr.sin_port = htons(atoi(argv[2]));
if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
perror("bind err");
return 1;
}
printf("bind OK\n");
if(-1 == listen(listenfd,10)){
perror("listen err");
return 1;
}
printf("listen OK\n");
int epoll_fd = epoll_create(INR_OPEN_MAX);
struct epoll_event evt;
evt.data.fd = listenfd;
evt.events = EPOLLIN;
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listenfd,&evt);
int out_evts_cnt = 1;
for(;;){
struct epoll_event out_evts[out_evts_cnt];
int fd_cnt = epoll_wait(epoll_fd,out_evts,out_evts_cnt,-1);
int i;
for(i=0;i<fd_cnt;i++){
if(out_evts[i].data.fd == listenfd && out_evts[i].events & EPOLLIN){
printf("accept listenfd\n");
int connfd = accept(listenfd,NULL,NULL);
if(-1 == connfd){
perror("accept err");
}else{
if(out_evts_cnt+1 == INR_OPEN_MAX){
fprintf(stderr,"connfd size over %d",INR_OPEN_MAX);
close(connfd);
}else{
struct epoll_event evt;
evt.data.fd = connfd;
evt.events = EPOLLIN;
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,connfd,&evt);
out_evts_cnt++;
}
}
}else if(out_evts[i].events & EPOLLIN){
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
ssize_t len;
printf("read connfd %d\n",out_evts[i].data.fd);
if((len = read(out_evts[i].data.fd,buf,BUFSIZ-1)) == -1){
perror("read err");
//return 1;
}
if(0 == len){
printf("close %d\n",out_evts[i].data.fd);
close(out_evts[i].data.fd);
epoll_ctl(epoll_fd,EPOLL_CTL_DEL,out_evts[i].data.fd,out_evts+i);
continue;
}
printf("server recv:%s\n",buf);
int fd = open(buf,O_RDONLY);
if(-1 == fd){
perror("open file err");
}
struct stat file_stat;
fstat(fd,&file_stat);
if(-1 == sendfile(out_evts[i].data.fd,fd,NULL,file_stat.st_size)){
perror("sendfile err");
}
printf("server send file %s ok\n",buf);
close(fd);
}
}
}
close(epoll_fd);
close(listenfd);
}
thread_max_size.c:用于检测计算机最大可执行线程的数量;
#include <stdio.h>
#include <pthread.h>
void* test(void*arg){
pause();
//for(;;){}
}
int main(int argc,char* argv[]){
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
size_t stack_size = 8192*1024;
pthread_attr_setstacksize(&attr,stack_size);
pthread_attr_getstacksize(&attr,&stack_size);
printf("thread stack size:%dk\n",stack_size/1024);
size_t cnt = 0;
for(;;){
if(0 != pthread_create(&tid,&attr,test,NULL)){
printf("max thread count:%d\n",cnt);
break;
}
cnt++;
}
pthread_attr_destroy(&attr);
}
gethostbyname.c
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc,char** argv){
struct hostent* host = gethostbyname(argv[1]);
if(NULL == host){
herror("gethostbyname err");
return 1;
}
printf("hostname:%s\n",host->h_name);
printf("aliases:");
while(*host->h_aliases != NULL){
printf("%s ",*host->h_aliases);
host->h_aliases++;
}
printf("\n");
printf("addrtype:%s\n",host->h_addrtype == AF_INET?"AF_INET":"AF_INET6");
printf("length:%d\n",host->h_length);
printf("addrlist:");
while(*host->h_addr_list != NULL){
//struct in_addr addr;
//memcpy(&addr,*host->h_addr_list,host->h_length);
//printf("%s ",inet_ntoa(addr));
printf("%s ",inet_ntoa(*(struct in_addr*)*host->h_addr_list));
host->h_addr_list++;
}
}
:
: