




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第epoll多路復(fù)用的一個實例程序(C實現(xiàn))本文實例為大家分享了epoll多路復(fù)用一個實例程序的具體代碼,供大家參考,具體內(nèi)容如下
1、實例程序描述
編寫一個echoserver程序,功能是客戶端向服務(wù)端發(fā)送消息,服務(wù)端接收到消息后輸出,并原樣返回給客戶端,客戶端接收到服務(wù)端的應(yīng)答消息并打印輸出。
2、公共接口函數(shù)部分
2.1、common.h源文件
/**
**描述:公共頭文件
#includestdio.h
#includestring.h
#includestdlib.h
#includeerrno.h
#includefcntl.h
#includeunistd.h
#includenetdb.h
#includearpa/inet.h
#includenetinet/in.h
#includesys/types.h
#includesys/socket.h
#includesys/epoll.h
typedefstructepoll_eventEPOLL_EVENT_T;
#defineBUF_SIZE2048
#defineLISTENQ
10
#defineFD_SEZE
1000
#defineMAX_EVENTS100
#defineERROR_SOCKET_SELECT
-1
#defineERROR_SOCKET_TIMEOUT
-2
#defineERROR_SOCKET_READ
-3
#defineERROR_SOCKET_WRITE
-4
#defineERROR_SOCKET_CLOSE
-5
#defineERROR_SOCKET_CREATE
-6
#defineERROR_SOCKET_BIND
-7
#defineERROR_SOCKET_LISTEN
-8
#defineERROR_SOCKET_CONNECT
-9
#defineERROR_EPOLL_CREATE
-10
#defineERROR_EPOLL_CTL_ADD
-11
#defineERROR_EPOLL_CTL_DEL
-12
#defineERROR_EPOLL_CTL_MOD
-13
#defineERROR_ARGUMENT
-999
intadd_epoll_event(intepollfd,intfd,intevents);
intdel_epoll_event(intepoll,intfd,intevents);
intmod_epoll_event(intepoll,intfd,intevents);
intmake_socket_nonblock(intsock_fd);
intlisten_socket(char*ip,intport,intnonblock);
intconnect_socket(char*ip,intport,intnonblock);
2.2、common.c源文件
/**
**描述:公共函數(shù)
#include"common.h"
intadd_epoll_event(intepollfd,intfd,intevents)
EPOLL_EVENT_Tev;
ev.events=events;
ev.data.fd=fd;
if(epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,ev)==-1){
perror("epoll_ctl_add");
returnERROR_EPOLL_CTL_ADD;
}
intdel_epoll_event(intepollfd,intfd,intevents)
EPOLL_EVENT_Tev;
ev.events=events;
ev.data.fd=fd;
if(epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,ev)==-1){
perror("epoll_ctl_del");
returnERROR_EPOLL_CTL_ADD;
}
intmod_epoll_event(intepollfd,intfd,intevents)
EPOLL_EVENT_Tev;
ev.events=events;
ev.data.fd=fd;
if(epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,ev)==-1){
perror("epoll_ctl_mod");
returnERROR_EPOLL_CTL_MOD;
}
//設(shè)置socket為非阻塞模式函數(shù)
intmake_socket_nonblock(intsock_fd)
intflags;
if((flags=fcntl(sock_fd,F_GETFL,NULL))0){
printf("getsocketfdflagserror:%d%s",errno,strerror(errno));
return-1;
}
if(fcntl(sock_fd,F_SETFL,flags|O_NONBLOCK)==-1){
printf("setsocketnon-blockerror:%d%s",errno,strerror(errno));
return-1;
}
return0;
intlisten_socket(char*ip,intport,intnonblock)
intopt=1,sockfd;
structsockaddr_insvr_addr;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))0){
close(sockfd);
returnERROR_SOCKET_CREATE;
}
if(nonblock)//設(shè)置socket為非阻塞模式
make_socket_nonblock(sockfd);
//SO_REUSEADDR是讓端口釋放后立即就可以被再次使用
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,opt,sizeof(opt));
memset(svr_addr,0,sizeof(structsockaddr_in));
svr_addr.sin_family=AF_INET;
if(ip==NULL)
svr_addr.sin_addr.s_addr=htonl(INADDR_ANY);
else
svr_addr.sin_addr.s_addr=inet_addr(ip);
svr_addr.sin_port=htons(port);
if(bind(sockfd,(structsockaddr*)svr_addr,sizeof(structsockaddr))==-1){
close(sockfd);
returnERROR_SOCKET_BIND;
}
if(listen(sockfd,LISTENQ)==-1){
close(sockfd);
returnERROR_SOCKET_LISTEN;
}
returnsockfd;
intconnect_socket(char*ip,intport,intnonblock)
intsockfd;
structsockaddr_insvr_addr;
if(ip==NULL||strlen(ip)==0||port=0)
returnERROR_ARGUMENT;
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd0){
perror("socket");
returnERROR_SOCKET_CREATE;
}
memset(svr_addr,0,sizeof(svr_addr));
svr_addr.sin_family=AF_INET;
svr_addr.sin_addr.s_addr=inet_addr(ip);
svr_addr.sin_port=htons(port);
if(connect(sockfd,(structsockaddr*)svr_addr,sizeof(svr_addr))==-1){
perror("connect");
close(sockfd);
returnERROR_SOCKET_CONNECT;
}
if(nonblock)
make_socket_nonblock(sockfd);
returnsockfd;
}
3、服務(wù)端源文件epoll_server.c
/**
**程序描述:編寫一個echoserver程序,功能是客戶端向服務(wù)器發(fā)送信息,服務(wù)器端接收數(shù)據(jù)后輸出并原樣返回給客戶端,客戶端接收到消息并輸出到終端。
#include"common.h"
voiddo_epoll(intlisten_fd);
voidhandle_epoll_events(intepollfd,EPOLL_EVENT_T*events,intnfds,intlisten_fd,char*buf);
voidon_accept(intepollfd,intlisten_fd);
voidon_read(intepollfd,intfd,char*buf);
voidon_write(intepollfd,intfd,char*buf);
intmain(intargc,int*argv[])
charsvr_ip[32]={0};
intsvr_port;
intlisten_fd,nonblock=0;
if(argc3){
printf("ERROR:toofewcommand-linearguments\n");
printf("Usage:%ssvr_ipsvr_port\n",argv[0]);
return-1;
}
strncpy(svr_ip,argv[1],strlen(argv[1]));
svr_port=atoi(argv[2]);
listen_fd=listen_socket(svr_ip,svr_port,nonblock);
if(listen_fd0){
printf("listensocketerror:%d%s\n",errno,strerror(errno));
return-2;
}
printf("epoll_svrlistenon[%s:%d]succ\n",svr_ip,svr_port);
do_epoll(listen_fd);
printf("exitepoll_svrsucc\n");
return0;
voiddo_epoll(intlisten_fd)
EPOLL_EVENT_Tevents[MAX_EVENTS];
intepollfd,conn_fd,nfds;
charbuf[BUF_SIZE]={0};
//創(chuàng)建一個epoll文件描述符
epollfd=epoll_create(FD_SEZE);
if(epollfd==-1){
perror("epoll_create");
close(listen_fd);
return;
}
//添加監(jiān)聽描述符的讀事件
add_epoll_event(epollfd,listen_fd,EPOLLIN);
for(;;){
nfds=epoll_wait(epollfd,events,MAX_EVENTS,-1);
if(nfds==-1){
perror("epoll_wait");
close(listen_fd);
break;
}
handle_epoll_events(epollfd,events,nfds,listen_fd,buf);
}
close(epollfd);
voidhandle_epoll_events(intepollfd,EPOLL_EVENT_T*events,intnfds,intsockfd,char*buf)
inti=0;
intfd;
//printf("nfds=%d\n",nfds);
for(i=0;infds;i++){
fd=events[i].data.fd;
//根據(jù)文件描述符類型和事件類型進(jìn)行相應(yīng)處理
if(fd==sockfd(events[i].eventsEPOLLIN))
on_accept(epollfd,sockfd);
elseif(events[i].eventsEPOLLIN)
on_read(epollfd,fd,buf);
elseif(events[i].eventsEPOLLOUT)
on_write(epollfd,fd,buf);
}
voidon_accept(intepollfd,intlisten_fd)
intconn_fd;
structsockaddr_incli_addr;
socklen_tcli_addr_len=sizeof(structsockaddr);
conn_fd=accept(listen_fd,(structsockaddr*)cli_addr,cli_addr_len);
if(conn_fd==-1){
perror("accept");
}
else{
printf("acceptanewclient:[%s:%d],conn_fd=%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),conn_fd);
//make_socket_nonblock(conn_fd);
add_epoll_event(epollfd,conn_fd,EPOLLIN);//添加一個客戶端連接描述符的讀事件
}
voidon_read(intepollfd,intfd,char*buf)
intnread;
nread=read(fd,buf,BUF_SIZE);
if(nread==-1){
perror("read");
close(fd);
del_epoll_event(epollfd,fd,EPOLLIN);
}
elseif(nread==0){
printf("ERROR:clientclose\n");
close(fd);
del_epoll_event(epollfd,fd,EPOLLIN);
}
else{
printf("recvreqmsgfromclientsucc,fd=%d,msg:%s",fd,buf);
//修改描述符對應(yīng)的事件,由讀改為寫
mod_epoll_event(epollfd,fd,EPOLLOUT);
}
voidon_write(intepollfd,intfd,char*buf)
intnwrite;
nwrite=write(fd,buf,strlen(buf));
if(nwrite==-1){
perror("write");
close(fd);
del_epoll_event(epollfd,fd,EPOLLOUT);
}
else{
printf("sendrespmsgtoclientsucc,fd=%d,msg:%s\n",fd,buf);
mod_epoll_event(epollfd,fd,EPOLLIN);//將描述符對應(yīng)的事件,由寫改為讀
}
memset(buf,0,sizeof(buf));
}
4、客戶端源文件epoll_client.c
/**
**程序描述:回射程序echo客戶端。客戶端也要使用epoll實現(xiàn)對路復(fù)用,控制STDIN_FILENO、STDOUT_FILENO和sockfd這三個描述符對應(yīng)的事件。
STDIN_FILENO:標(biāo)準(zhǔn)輸入描述符,只有一個讀事件
STDOUT_FILENO:標(biāo)準(zhǔn)輸出描述符,只有一個寫事件
sockfd:有兩個事件,一個是讀事件,即讀取從服務(wù)端發(fā)送來的數(shù)據(jù);另一個是寫事件,即發(fā)送數(shù)據(jù)給服務(wù)端。需要注意的是,在同一時刻,它只能有一個事件
#include"common.h"
voiddo_epoll(intsockfd);
voidhandle_epoll_events(intepollfd,EPOLL_EVENT_T*events,intnfds,intsockfd,char*buf);
voidon_read(intepollfd,intfd,intsockfd,char*buf);
voidon_write(intepollfd,intfd,intsockfd,char*buf);
intmain(intargc,char*argv[])
charsvr_ip[32]={0};
intsvr_port;
intconn_fd,nonblock=0;
if(argc3){
printf("ERROR:toofewcommand-linearguments\n");
printf("Usage:%ssvr_ipsvr_port\n",argv[0]);
return-1;
}
strncpy(svr_ip,argv[1],strlen(argv[1]));
svr_port=atoi(argv[2]);
conn_fd=connect_socket(svr_ip,svr_port,nonblock);
if(conn_fd0){
printf("connecttoserverfailed!\n",conn_fd);
return-2;
}
printf("connecttoserversucc,sockfd=%d\n",conn_fd);
do_epoll(conn_fd);
printf("exitepoll_clisucc\n");
return0;
voiddo_epoll(intsockfd)
intepollfd;
EPOLL_EVENT_Tevents[MAX_EVENTS];
intnfds;
charbuf[BUF_SIZE]={0};
epollfd=epoll_create(FD_SEZE);
add_epoll_event(epollfd,STDIN_FILENO,EPOLLIN);//注冊標(biāo)準(zhǔn)輸入讀事件
for(;;){
nfds=epoll_wait(epollfd,events,MAX_EVENTS,-1);
if(nfds==-1){
perror("epoll_wait");
close(sockfd);
break;
}
handle_epoll_events(epollfd,events,nfds,sockfd,buf);
}
close(epollfd);
voidhandle_epoll_events(intepollfd,EPOLL_EVENT_T*events,intnfds,intsockfd,char*buf)
inti,fd;
//printf("nfds=%d\n",nfds);
for(i=0;infds;i++){
fd=events[i].data.fd;
//根據(jù)文件描述符類型和事件類型進(jìn)行相應(yīng)處理
if(events[i].eventsEPOLLIN)
on_read(epollfd,fd,sockfd,buf);
elseif(events[i].eventsEPOLLOUT)
on_write(epollfd,fd,sockfd,buf);
}
voidon_read(intepollfd,intfd,intsockfd,char*buf)
intnread;
nread=read(fd,buf,BUF_SIZE);
if(nread0){
perror("readerror");
close(fd);
}
elseif(nread==0){
printf("epoll_svrclose.\n");
close(fd);
exit(-1);
}
else{
if(fd==STDIN_FILENO){//標(biāo)準(zhǔn)輸入描述符的讀事件
printf("stdinbuf=%s",buf);
add_epoll_event(epollfd,sockfd,EPOLLOUT);//注冊sockfd的寫事件
}
else{//sockfd描述符的讀事件
del_epoll_event(epollfd,sockfd,EPOLLIN);//刪除當(dāng)前sockfd描述符的讀事件
add_epoll_event(epollfd,STDOUT_FILENO,EPOLLOUT);//注冊標(biāo)準(zhǔn)輸出寫事件
}
}
voidon_write(intepollfd,intfd,intsockfd,char*buf)
intnwrite;
nwrite=write(fd,buf,strlen(buf));
if(nwrite0){
perror("writeerror");
close(fd);
}
else{
if(fd==STDOUT_FILENO)//標(biāo)準(zhǔn)輸出描述符的寫事件
{
printf("recvresp_msgfromsvr,msg=%s\n",buf);
del_epoll_event(epollfd,fd,EPOLLOUT);//刪除輸出描述符的寫事件
}
else//sockfd描述符的寫事件
{
printf("sendreq_msgtosvrsucc,msg=%s",buf);
mod_epoll_event(epollfd,fd,EPOLLIN);//修改sockfd描述符為讀事件
}
}
memset(buf,0,BUF_SIZE);
}
5、Makefile文件
#第1種方式
all:epoll_serverepoll_client
epoll_server:epoll_server.ocommon.o
$(LINK)
epoll_client:epoll_client.ocommon.o
$(LINK)
%.o:%.c
$(COMPILE)
#compilelink
CFLAGS+=-g
COMPILE=gcc-c-g-std=gnu99-o$@$
LINK=gcc-g-o$@$^
clean:
rm-rf*.oepoll_serverepoll_client
6、總結(jié)分析
6.1客戶端程序分析
1、對于客戶端程序而言,我們監(jiān)聽3個文件描述符,分別是連接服務(wù)端的sockfd,標(biāo)準(zhǔn)輸入描述符STDIN_FILENO以及標(biāo)準(zhǔn)輸出描述符STDOUT_FILENO。在do_poll函數(shù)中,我們首先注冊了標(biāo)準(zhǔn)輸入描述符的讀事件(EPOLLIN),然后在for循環(huán)中,循環(huán)調(diào)用epoll_wait系統(tǒng)調(diào)用,handle_epoll_events是整個epoll事件表的handler函數(shù)。當(dāng)我們向終端輸入數(shù)據(jù)完畢的時候,就會觸發(fā)標(biāo)準(zhǔn)輸入描述符的讀事件,從而調(diào)用讀事件處理函數(shù)on_read,在on_read函數(shù)中,注冊了so
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 地震臺網(wǎng)補貼管理辦法
- 評估公司準(zhǔn)入管理辦法
- 基金公司采購管理辦法
- 廣西戶口登記管理辦法
- 肩周炎患者的護(hù)理課件
- 現(xiàn)場設(shè)備維修培訓(xùn)課件
- 肝硬化說課課件
- 東莞華僑中學(xué)數(shù)學(xué)試卷
- 贛一中高一數(shù)學(xué)試卷
- 高新期末考試數(shù)學(xué)試卷
- (高清版)DZT 0064.15-2021 地下水質(zhì)分析方法 第15部分:總硬度的測定 乙二胺四乙酸二鈉滴定法
- 兵檢(征兵)心理測試題目3套匯編
- 人字梯安全專項方案
- 雅魯藏布江米林-加查段沿線暴雨泥石流危險度評價的中期報告
- 2023年麻城市社區(qū)工作者招聘考試真題
- 2023年版《浙江省存量房買賣合同示范文本》
- 高性能計算在智能電網(wǎng)中的應(yīng)用
- 國家輔助類藥品一覽表
- 【青島海爾公司績效管理現(xiàn)狀、問題及優(yōu)化對策(7600字論文)】
- 《把子》課程標(biāo)準(zhǔn)
- 成都市郫都區(qū)七年級上學(xué)期語文期末考試試卷
評論
0/150
提交評論