socket epoll网络编程实例
生活随笔
收集整理的這篇文章主要介紹了
socket epoll网络编程实例
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
總結(jié)了各個(gè)博主的經(jīng)驗(yàn),寫(xiě)出了簡(jiǎn)單的demo,實(shí)例為ET模式,轉(zhuǎn)載請(qǐng)寫(xiě)明出處,如有寶貴意見(jiàn)請(qǐng)留言。
?
第一版:
服務(wù)端:
#include <stdio.h> #include <sys/epoll.h> #include <stdlib.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/resource.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <netdb.h>#define MAXBUF 1024 #define MAXEPOLLSIZE 10000int main(int argc, char *argv[]) {//設(shè)置端口if(argc != 2){ printf("請(qǐng)?jiān)O(shè)置端口號(hào)!\n");}int port = atoi(argv[1]); int listener, conn_sock, kdpfd, nfds, n, ret, curfds;socklen_t len;struct sockaddr_in server_addr, client_addr;struct epoll_event ev;struct epoll_event pevent[MAXEPOLLSIZE];struct rlimit rt;rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;//設(shè)置系統(tǒng)資源,打開(kāi)最大文件數(shù)if (setrlimit(RLIMIT_NOFILE, &rt) == -1){perror("setrlimit");exit(EXIT_FAILURE);}else{printf("設(shè)置系統(tǒng)資源參數(shù)成功!\n");}//創(chuàng)建socketif( (listener = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket");exit(EXIT_FAILURE);}else{printf("socket 創(chuàng)建成功!\n");}//設(shè)置非堵塞if (fcntl(listener, F_SETFL, fcntl(listener, F_GETFL, 0) | O_NONBLOCK) == -1){perror("fcntl");exit(EXIT_FAILURE);}bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);server_addr.sin_addr.s_addr = INADDR_ANY; //0.0.0.0所有地址//綁定if ( bind( listener, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) == -1 ){perror("bind");exit(EXIT_FAILURE);}else{printf("IP 地址和端口綁定成功\n");}if (listen(listener, 10) == -1){perror("listen");exit(EXIT_FAILURE);}else{printf("開(kāi)啟服務(wù)成功!\n");}//創(chuàng)建epoll為ET模式kdpfd = epoll_create(MAXEPOLLSIZE);len = sizeof(struct sockaddr_in);ev.events = EPOLLIN | EPOLLET;ev.data.fd = listener;//socket加入epollif( epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0 ){fprintf( stderr, "epoll set insertion error: fd=%d\n", listener );exit(EXIT_FAILURE);}else{printf("監(jiān)聽(tīng) socket 加入 epoll 成功!\n");}//設(shè)置延遲和事件個(gè)數(shù),事件由累加完成curfds = 1;//int timeout = 10*1000;while(1){//等待有事件發(fā)生//nfds = epoll_wait(kdpfd, pevent, curfds, timeout);nfds = epoll_wait(kdpfd, pevent, curfds, -1);if( nfds == -1 ){perror("epoll_wait");break;}else if (nfds == 0){printf("waiting for connecting...\n");continue;}for (n = 0; n < nfds; ++n){if ((pevent[n].events & EPOLLERR) || (pevent[n].events & EPOLLHUP) || (!(pevent[n].events & EPOLLIN))){//此FD上發(fā)生錯(cuò)誤,或者套接字未準(zhǔn)備好讀取(那么為什么通知我們?)fprintf (stderr, "epoll error\n");close(pevent[n].data.fd);continue;}else if (pevent[n].data.fd == listener){//我們?cè)诒O(jiān)聽(tīng)套接字上有一個(gè)通知,這意味著一個(gè)或多個(gè)傳入連接while (1){conn_sock = accept(listener, (struct sockaddr*)&client_addr, &len);if( conn_sock == -1 ){if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){//我們已經(jīng)處理了所有傳入的連接break;}else{perror ("accept error");break;}}//else // printf("有連接來(lái)自于: %s:%d, 分配的 socket 為:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), conn_sock);char hbuf[1024], sbuf[1024];if ( 0 == getnameinfo((struct sockaddr*)&client_addr, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV))printf("Accepted connection on descriptor %d (host=%s, port=%s)\n", conn_sock, hbuf, sbuf);if (fcntl(conn_sock, F_SETFL, fcntl(conn_sock, F_GETFL, 0) | O_NONBLOCK) == -1){perror("fcntl");break;}ev.events = EPOLLIN | EPOLLET;ev.data.fd = conn_sock;if( -1 == epoll_ctl( kdpfd, EPOLL_CTL_ADD, conn_sock, &ev)){fprintf(stderr, "把 socket '%d' 加入 epoll 失敗!%s\n", conn_sock, strerror(errno));exit(EXIT_FAILURE);}curfds ++; }continue;}else{if (do_use_fd(pevent[n].data.fd) < 0){printf ("關(guān)閉 %d\n", pevent[n].data.fd); epoll_ctl(kdpfd, EPOLL_CTL_DEL, pevent[n].data.fd,&ev);close(pevent[n].data.fd);curfds--;}}}}close(listener);close(kdpfd);return 0; }int do_use_fd(int connfd) {int done = 0;while(1){char buf[MAXBUF + 1];bzero(buf, MAXBUF + 1);int nread;//讀取客戶端socket流nread = recv(connfd, buf, MAXBUF, 0);if (nread == -1){if (errno != EAGAIN){perror ("recv");done = -1;}break;}else if (nread == 0){done = -1;break;}printf("%d接收消息成功:'%s',共%d個(gè)字節(jié)的數(shù)據(jù)\n", connfd, buf, nread);//響應(yīng)客戶端 if ( -1 == send(connfd, buf, strlen(buf), 0))perror ("write");}return done; }?
第二版:
.h
#ifndef _INITNETWORK_H_ #define _INITNETWORK_H_#include <stdio.h> #include <sys/epoll.h> #include <stdlib.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/resource.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <pthread.h>#define MAXBUF 1024 #define MAXEPOLLSIZE 10000typedef struct SOCKET_EPOLL_PAR{int listener; //socket句柄int port; //socket端口int kdpfd; //epoll句柄int curfds; //socket連接個(gè)數(shù)socklen_t len; //len = sizeof(struct sockaddr_in);struct epoll_event ev; //epoll 模式int fd; //當(dāng)前事件struct epoll_event pevent[MAXEPOLLSIZE]; //事件數(shù)集合 }SEPAR;static void *thread_conn(void *arg); static void *thread_do_use_fd(void *arg); int init_system_res(); int init_socket(int *listener, int *port); int init_epoll(SEPAR *se_par); void run_network(int port); int close_network(int listener, int kdpfd);#endif.c
#include "initnetwork.h"void *thread_conn(void *arg) {SEPAR *pse_par = (SEPAR*)arg;struct sockaddr_in client_addr;while (1){ int conn_sock = accept(pse_par->listener, (struct sockaddr*)&client_addr, &(pse_par->len));if( conn_sock == -1 ){if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){//我們已經(jīng)處理了所有傳入的連接break;}else{perror ("accept error");break;}}char hbuf[1024], sbuf[1024];if ( 0 == getnameinfo((struct sockaddr*)&client_addr, pse_par->len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV))printf("Accepted connection on descriptor %d (host=%s, port=%s)\n", conn_sock, hbuf, sbuf);if (fcntl(conn_sock, F_SETFL, fcntl(conn_sock, F_GETFL, 0) | O_NONBLOCK) == -1){perror("fcntl");break;}pse_par->ev.events = EPOLLIN | EPOLLET;pse_par->ev.data.fd = conn_sock;if( -1 == epoll_ctl( pse_par->kdpfd, EPOLL_CTL_ADD, conn_sock, &(pse_par->ev))){fprintf(stderr, "把 socket '%d' 加入 epoll 失敗!%s\n", conn_sock, strerror(errno));exit(EXIT_FAILURE);}pse_par->curfds++;printf ("conn curfds: %d\n", pse_par->curfds);} }void *thread_do_use_fd(void *arg) {SEPAR *pse_par = (SEPAR*)arg;int done = 0;int conn_fd = pse_par->pevent[pse_par->fd].data.fd;while(1){char buf[MAXBUF + 1];bzero(buf, MAXBUF + 1);int nread;//讀取客戶端socket流nread = recv(conn_fd, buf, MAXBUF, 0);if (nread == -1){if (errno != EAGAIN){perror ("recv");done = -1;}break;}else if (nread == 0){done = -1;break;}printf("%d接收消息成功:'%s',共%d個(gè)字節(jié)的數(shù)據(jù)\n", conn_fd, buf, nread);//響應(yīng)客戶端 if ( -1 == send(conn_fd, buf, strlen(buf), 0))perror ("write");}if (done < 0){printf ("關(guān)閉 %d\n", conn_fd);epoll_ctl(pse_par->kdpfd, EPOLL_CTL_DEL, conn_fd,&(pse_par->ev));close(conn_fd);pse_par->curfds--;printf ("close curfds: %d\n", pse_par->curfds);} }int init_system_res() {struct rlimit rt;rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;if (setrlimit(RLIMIT_NOFILE, &rt) == -1){perror("setrlimit");return -1;}elseprintf("設(shè)置系統(tǒng)資源參數(shù)成功!\n");return 0; }int init_socket(int *listener, int *port) {//創(chuàng)建socketif( (*listener = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket");return -1;}elseprintf("socket 創(chuàng)建成功!\n");//設(shè)置非堵塞if (fcntl(*listener, F_SETFL, fcntl(*listener, F_GETFL, 0) | O_NONBLOCK) == -1){perror("fcntl");return -1;}struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(*port);server_addr.sin_addr.s_addr = INADDR_ANY; //0.0.0.0所有地址//綁定if (bind( *listener, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) == -1 ){perror("bind");return -1;}elseprintf("IP 地址和端口綁定成功\n");//監(jiān)聽(tīng)if (listen( *listener, MAXEPOLLSIZE) == -1){perror("listen");return -1;}elseprintf("開(kāi)啟服務(wù)成功!\n");return 0; }int init_epoll(SEPAR *se_par) {//創(chuàng)建epoll為ET模式se_par->kdpfd = epoll_create(MAXEPOLLSIZE);se_par->len = sizeof(struct sockaddr_in);se_par->ev.events = EPOLLIN | EPOLLET;se_par->ev.data.fd = se_par->listener;//socket加入epollif( epoll_ctl(se_par->kdpfd, EPOLL_CTL_ADD, se_par->listener, &(se_par->ev)) < 0 ){fprintf( stderr, "epoll set insertion error: fd=%d\n", se_par->listener );return -1;}elseprintf("監(jiān)聽(tīng) socket 加入 epoll 成功!\n");return 0; }void run_network(int port) {SEPAR se_par;int nfds, n;se_par.port = port;//設(shè)置系統(tǒng)資源,打開(kāi)最大文件數(shù)if(init_system_res() == -1)abort();//初始化網(wǎng)絡(luò)if (init_socket(&se_par.listener, &se_par.port) == -1)abort();//創(chuàng)建epoll并添加socketif (init_epoll(&se_par) == -1)abort();//設(shè)置延遲和事件個(gè)數(shù),事件由累加完成se_par.curfds = 1;//int timeout = 10*1000;while(1){//等待有事件發(fā)生//nfds = epoll_wait(kdpfd, pevent, curfds, timeout);nfds = epoll_wait(se_par.kdpfd, se_par.pevent, se_par.curfds, -1);if( nfds == -1 ){perror("epoll_wait");break;}else if (nfds == 0){printf("waiting for connecting...\n");continue;}for (n = 0; n < nfds; ++n){if ((se_par.pevent[n].events & EPOLLERR) || (se_par.pevent[n].events & EPOLLHUP) || (!(se_par.pevent[n].events & EPOLLIN))){//此FD上發(fā)生錯(cuò)誤,或者套接字未準(zhǔn)備好讀取(那么為什么通知我們?)fprintf (stderr, "epoll error\n");close(se_par.pevent[n].data.fd);continue;}else if (se_par.pevent[n].data.fd == se_par.listener){//我們?cè)诒O(jiān)聽(tīng)套接字上有一個(gè)通知,這意味著一個(gè)或多個(gè)傳入連接 pthread_t tid;int ret = pthread_create(&tid, NULL, thread_conn, (void*)&se_par);if (ret != 0)printf ("創(chuàng)建epoll連接線程出錯(cuò)!");continue;}else{//處理事件pthread_t tid;se_par.fd = n;int ret = pthread_create(&tid, NULL, thread_do_use_fd, (void*)&se_par);if (ret != 0)printf ("創(chuàng)建epoll事件線程出錯(cuò)!");}}}if (close_network(se_par.listener, se_par.kdpfd) == -1)abort(); }int close_network(int listener, int kdpfd) {if (close(listener) == -1){perror ("close listener");return -1;}if (close(kdpfd) == -1){perror ("close kdpfd");return -1;}return 0; }?
?
?
測(cè)試客戶端:
/** * socket簡(jiǎn)單編程 客戶端* */#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h>#define BUFFSIZE 1024int main(int argc, char *argv[]) {int client_sockfd = 0;int len = 0;struct sockaddr_in server_addr;char buf[BUFFSIZE] = {0};bzero(&server_addr, sizeof(struct sockaddr_in));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");server_addr.sin_port = htons(8080);if((client_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error!\n");return -1;}if(connect(client_sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0){perror("client error!\n");return -1;}printf("connect success!\n");// len = recv(client_sockfd, buf, BUFFSIZE, 0); // buf[len] = '\0'; // printf("client_buf = %s\n",buf);while(1){printf("Enter string to send:");bzero(buf, sizeof(buf));scanf("%s",buf);if(!strcmp(buf,"quit")){break;}len = send(client_sockfd, buf, strlen(buf), 0);bzero(buf, sizeof(buf));len = recv(client_sockfd, buf, BUFFSIZE, 0);buf[len] = '\0';printf("received: %s\n",buf);}close(client_sockfd);return 0; }?
總結(jié)
以上是生活随笔為你收集整理的socket epoll网络编程实例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: XCode调试器LLDB
- 下一篇: shell 遍历目录下的所有文件