概念
IO復用:用于表示多個網(wǎng)絡鏈接復用一個IO線程专肪,具有開銷小的優(yōu)點拇厢,但是同樣的編程的復雜度就會比較高椭岩;
IO復用使用的幾個函數(shù)
select
int select (int maxfd,fd_set *rdset,fd_set*wrset,fd_set *exset,struct timeval *timeout)竟趾;
maxfd:表示需要監(jiān)視的最大文件描述符值+1冯事;
rdset:需要檢測的刻度文件描述符集合宿接;
wrset:需要檢測的可寫文件描述符集合赘淮;
exset:需要檢測的異常文件描述符集合;
timeout:超時時間
返回值:-1表示出錯睦霎,0表示超時梢卸,>0表示獲取到的數(shù)據(jù);
同時還需要掌握的幾個函數(shù)包括:
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:是一個常數(shù)值表示的是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、需要修改傳入的參數(shù)數(shù)組碑幅;
2戴陡、不能夠確切指定有數(shù)據(jù)的socket;
3沟涨、只能夠監(jiān)視FD_SETSIZE數(shù)目個連接恤批;
4、線程不安全裹赴;
Poll模式
Poll模式具備的優(yōu)點:
1喜庞、不需要修改傳入的參數(shù)數(shù)組
2、可以監(jiān)視任意個連接棋返,可以通過cat /proc/sys/file-max進行查看
缺點:
1延都、不能夠確切的指定有數(shù)據(jù)的socket
2、線程不安全
poll模型需要使用的函數(shù)是int poll(struct pollfd *fdarray,usigned long nfds,int timeout);
struct pollfd *fdarray {
fd:表示文件描述符號
struct profile{
events:表示監(jiān)視的事件睛竣;
revents:表示實際發(fā)生的事件晰房;
};
};
對于events支持的選項有:
?輸入:POLLRDNOPM
:表示普通數(shù)據(jù);POLLRDBAND
:優(yōu)先級帶數(shù)據(jù)射沟;POLLIN
:普通或者優(yōu)先級帶數(shù)據(jù)嫉你;
?輸出:POLLWRNOPM
:表示普通數(shù)據(jù);POLLWRBAND
:優(yōu)先級帶數(shù)據(jù)躏惋;POLLOUT
:普通或者優(yōu)先級帶數(shù)據(jù);
對于revents支持的選項包括:
?輸入:POLLRDNOPM
:普通數(shù)據(jù)嚷辅;POLLRDBAND
:優(yōu)先級帶數(shù)據(jù)簿姨;POLLIN
:普通或者優(yōu)先級帶數(shù)據(jù);
?輸出:POLLWRNORW
:普通數(shù)據(jù);POLLWRBAND
:優(yōu)先級帶數(shù)據(jù)扁位;POOLLOUT
:普通或者優(yōu)先級帶數(shù)據(jù)准潭;
?錯誤:POLLERR
:發(fā)生錯誤;POLLHUP
:發(fā)生掛起域仇;POLLNVAL
:描述符非法刑然;
No | 常量 | events | revents | 說明 |
---|---|---|---|---|
1 | POLLIN | OK | OK | 普通或者優(yōu)先級帶數(shù)據(jù)可讀; |
2 | POLLRDNORM | OK | OK | 普通數(shù)據(jù)可讀 |
3 | POLLRDBAND | OK | OK | 優(yōu)先級帶數(shù)據(jù)可讀 |
4 | POLLPRI | OK | OK | 高優(yōu)先級數(shù)據(jù)可讀 |
5 | POLLOUT | OK | OK | 普通數(shù)據(jù)可寫 |
6 | POLLWRNORM | OK | OK | 普通數(shù)據(jù)可寫 |
7 | POLLWRBAND | OK | OK | 優(yōu)先級帶數(shù)據(jù)可寫 |
8 | POLLERR | NG | OK | 發(fā)生錯誤 |
9 | POLLHUP | NG | OK | 發(fā)生掛起 |
10 | POLLNVAL | NG | OK | 描述字不是一個打開的文件 |
其余的參數(shù)的含義
?nfds:表示數(shù)組元素的個數(shù)暇务;
?timeout泼掠;用于定義等待的時間;INFTIM
:表示永久等待垦细;0:表示立即返回择镇;>0:表示等待描述;
?返回值0:表示超時括改;-1:表示出錯腻豌;正數(shù):表示就緒的描述符的個數(shù);
普通數(shù)據(jù):表示的含義是正規(guī)的TCP數(shù)據(jù)以及所有的UDP數(shù)據(jù)嘱能;優(yōu)先級帶數(shù)據(jù):表示TCP帶外的數(shù)據(jù)吝梅;
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模型
優(yōu)點:能夠確切地指定有數(shù)據(jù)的socket,并且線程是安全的惹骂;
Epoll模型的創(chuàng)建
使用函數(shù)int eploo_create(int size)
來進行創(chuàng)建苏携,size用于指定監(jiān)聽的數(shù)目,返回值通常是文件描述符析苫,在/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 | 表示對應的文件描述符有緊急的數(shù)據(jù)可讀 |
EPOLLERR | 表示對應文件描述符發(fā)生錯誤 |
EPOLLHUP | 表示對應的文件描述符被掛斷 |
EPOLLET | 表示對應的文件描述符設定為edge模式 |
使用函數(shù)int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event)
;來進行epoll模型的控制;
epfd
:表示epoll
文件描述符衩侥;
op
:用于定義對于文件描述符的操作国旷,EPOLL_CTL_ADD
:表示用于創(chuàng)建;EPOLL_CTL_MOD
:表示用于修改某些類型茫死;EPOLL_CTL_DEL
:表示用于刪除跪但;fd
:表示相互關(guān)聯(lián)的文件描述符;event
:表示指向epoll_event的指針峦萎;
Epoll_event | 說明 |
---|---|
EPOLLOUT | 表示對應的文件描述符可寫 |
EPOLLPRI | 表示對應的文件描述符有緊急的數(shù)據(jù)可讀 |
EPOLLERR | 表示對應文件描述符發(fā)生錯誤 |
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
:用于回傳待處理事件的數(shù)組;
maxevents
:每次能夠處理的事件數(shù)详幽;
timeout
:等待IO事件發(fā)生的超時值筛欢;-1表示永不超時浸锨;0表示立即返回;
返回值
:正數(shù)表示發(fā)生事件數(shù)版姑;-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的數(shù)據(jù);
3表制、調(diào)用epoll_wait可以獲得管道讀者已經(jīng)就緒的文件句柄健爬;
4、管道讀者讀取1Kb的數(shù)據(jù)夫凸;
5浑劳、一次epoll_wait調(diào)用完成;
如果執(zhí)行的是ET模式夭拌,管道中剩余的1Kb數(shù)據(jù)就會被掛起魔熏,等待再次調(diào)用epoll_wait()
,得不到管道讀者的文件句柄鸽扁,除非有新的數(shù)據(jù)寫入管道蒜绽,如果是LT模式,只要管道中有數(shù)據(jù)可讀桶现,每次調(diào)用epoll_wait()
都會觸發(fā)躲雅;
還有一點區(qū)別就是設為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:用于檢測計算機最大可執(zhí)行線程的數(shù)量骡和;
#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++;
}
}
:
: