epoll多路復(fù)用的一個實例程序(C實現(xiàn))_第1頁
epoll多路復(fù)用的一個實例程序(C實現(xiàn))_第2頁
epoll多路復(fù)用的一個實例程序(C實現(xiàn))_第3頁
epoll多路復(fù)用的一個實例程序(C實現(xiàn))_第4頁
epoll多路復(fù)用的一個實例程序(C實現(xiàn))_第5頁
已閱讀5頁,還剩12頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論