首页 > 代码库 > Linux 网络编程八(epoll应用--大并发处理)
Linux 网络编程八(epoll应用--大并发处理)
//头文件 pub.h#ifndef _vsucess#define _vsucess#ifdef __cplusplusextern "C"{#endif//服务器创建socketint server_socket(int port);//设置非阻塞int setnonblock(int st);//接收客户端socketint server_accept(int st);//关闭socketint close_socket(int st);//接收消息int socket_recv(int st);//连接服务器int connect_server(char *ipaddr,int port);//发送消息int socket_send(int st);//将sockaddr_in转化成IP地址int sockaddr_toa(const struct sockaddr_in * addr, char * ipaddr);#ifdef __cplusplus}#endif#endif
//辅助方法--pub.c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>//htons()函数头文件#include <netinet/in.h>//inet_addr()头文件#include <fcntl.h>#include "pub.h"#define MAXBUF 1024//创建socketint socket_create(){ int st = socket(AF_INET, SOCK_STREAM, 0); if (st == -1) { printf("create socket failed ! error message :%s\n", strerror(errno)); return -1; } return st;}//设置服务端socket地址重用int socket_reuseaddr(int st){ int on = 1; if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { printf("setsockopt reuseaddr failed ! error message :%s\n", strerror(errno)); //close socket close_socket(st); return -1; } return 0;}//服务器绑定--监听端口号int socket_bind(int st, int port){ struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); //type addr.sin_family = AF_INET; //port addr.sin_port = htons(port); //ip addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind ip address if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1) { printf("bind failed ! error message :%s\n", strerror(errno)); //close socket close_socket(st); return -1; } //listen if (listen(st, 20) == -1) { printf("listen failed ! error message :%s\n", strerror(errno)); //close socket close_socket(st); return -1; } return 0;}//服务器创建socketint server_socket(int port){ if (port < 0) { printf("function server_socket param not correct !\n"); return -1; } //create socket int st = socket_create(); if (st < 0) { return -1; } //reuseaddr if (socket_reuseaddr(st) < 0) { return -1; } //bind and listen if (socket_bind(st, port) < 0) { return -1; } return st;}//连接服务器int connect_server(char *ipaddr,int port){ if(port<0||ipaddr==NULL) { printf("function connect_server param not correct !\n"); return -1; } int st=socket_create(); if(st<0) { return -1; } //conect server struct sockaddr_in addr; memset(&addr,0,sizeof(addr)); addr.sin_family=AF_INET; addr.sin_port=htons(port); addr.sin_addr.s_addr=inet_addr(ipaddr); if(connect(st,(struct sockaddr *)&addr,sizeof(addr))==-1) { printf("connect failed ! error message :%s\n",strerror(errno)); return -1; } return st;}//设置非阻塞int setnonblock(int st){ if (st < 0) { printf("function setnonblock param not correct !\n"); //close socket close_socket(st); return -1; } int opts = fcntl(st, F_GETFL); if (opts < 0) { printf("func fcntl failed ! error message :%s\n", strerror(errno)); return -1; } opts = opts | O_NONBLOCK; if (fcntl(st, F_SETFL, opts) < 0) { printf("func fcntl failed ! error message :%s\n", strerror(errno)); return -1; } return opts;}//接收客户端socketint server_accept(int st){ if (st < 0) { printf("function accept_clientsocket param not correct !\n"); return -1; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); socklen_t len = sizeof(addr); int client_st = accept(st, (struct sockaddr *) &addr, &len); if (client_st < 0) { printf("accept client failed ! error message :%s\n", strerror(errno)); return -1; } else { char ipaddr[20] = { 0 }; sockaddr_toa(&addr, ipaddr); printf("accept by %s\n", ipaddr); } return client_st;}//关闭socketint close_socket(int st){ if (st < 0) { printf("function close_socket param not correct !\n"); return -1; } close(st); return 0;}//将sockaddr_in转化成IP地址int sockaddr_toa(const struct sockaddr_in * addr, char * ipaddr){ if (addr == NULL || ipaddr == NULL) { return -1; } unsigned char *p = (unsigned char *) &(addr->sin_addr.s_addr); sprintf(ipaddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]); return 0;}//接收消息int socket_recv(int st){ if (st < 0) { printf("function socket_recv param not correct !\n"); return -1; } char buf[MAXBUF] = { 0 }; int rc=0; rc=recv(st,buf,sizeof(buf),0); if(rc==0) { printf("client is close ! \n"); return -1; }else if(rc<0) { /* * recv错误信息:Connection reset by peer * 错误原因:服务端给客户端发送数据,但是客户端没有接收,直接关闭,那么就会报错 * 如果客户端接受了数据,再关闭,也不会报错,rc==0. */ printf("recv failed ! error message :%s \n",strerror(errno)); return -1; } printf("%s",buf); //send message /* memset(buf,0,sizeof(buf)); strcpy(buf,"i am server , i have recved !\n"); if(send(st,buf,strlen(buf),0)<0) { printf("send failed ! error message :%s \n",strerror(errno)); return -1; } */ return 0;}//发送消息int socket_send(int st){ char buf[MAXBUF]={0}; while(1) { //read from keyboard read(STDIN_FILENO,buf,sizeof(buf)); if(buf[0]==‘0‘) { break; } if(send(st,buf,strlen(buf),0)<0) { printf("send failed ! error message :%s \n",strerror(errno)); return -1; } memset(buf,0,sizeof(buf)); } return 0;}
//网络编程服务端#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>//htons()函数头文件#include <netinet/in.h>//inet_addr()头文件#include <fcntl.h>#include <sys/epoll.h>#include "pub.h"#define MAXSOCKET 20int main(int arg, char *args[]){ if (arg < 2) { printf("please print one param!\n"); return -1; } //create server socket int listen_st = server_socket(atoi(args[1])); if (listen_st < 0) { return -1; } /* * 声明epoll_event结构体变量ev,变量ev用于注册事件, * 数组events用于回传需要处理的事件 */ struct epoll_event ev, events[100]; //生成用于处理accept的epoll专用文件描述符 int epfd = epoll_create(MAXSOCKET); //把socket设置成非阻塞方式 setnonblock(listen_st); //设置需要放到epoll池里的文件描述符 ev.data.fd = listen_st; //设置这个文件描述符需要epoll监控的事件 /* * EPOLLIN代表文件描述符读事件 *accept,recv都是读事件 */ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; /* * 注册epoll事件 * 函数epoll_ctl中&ev参数表示需要epoll监视的listen_st这个socket中的一些事件 */ epoll_ctl(epfd, EPOLL_CTL_ADD, listen_st, &ev); while (1) { /* * 等待epoll池中的socket发生事件,这里一般设置为阻塞的 * events这个参数的类型是epoll_event类型的数组 * 如果epoll池中的一个或者多个socket发生事件, * epoll_wait就会返回,参数events中存放了发生事件的socket和这个socket所发生的事件 * 这里强调一点,epoll池存放的是一个个socket,不是一个个socket事件 * 一个socket可能有多个事件,epoll_wait返回的是有消息的socket的数目 * 如果epoll_wait返回事件数组后,下面的程序代码却没有处理当前socket发生的事件 * 那么epoll_wait将不会再次阻塞,而是直接返回,参数events里面的就是刚才那个socket没有被处理的事件 */ int nfds = epoll_wait(epfd, events, MAXSOCKET, -1); if (nfds == -1) { printf("epoll_wait failed ! error message :%s \n", strerror(errno)); break; } int i = 0; for (; i < nfds; i++) { if (events[i].data.fd < 0) continue; if (events[i].data.fd == listen_st) { //接收客户端socket int client_st = server_accept(listen_st); /* * 监测到一个用户的socket连接到服务器listen_st绑定的端口 * */ if (client_st < 0) { continue; } //设置客户端socket非阻塞 setnonblock(client_st); //将客户端socket加入到epoll池中 struct epoll_event client_ev; client_ev.data.fd = client_st; client_ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; epoll_ctl(epfd, EPOLL_CTL_ADD, client_st, &client_ev); /* * 注释:当epoll池中listen_st这个服务器socket有消息的时候 * 只可能是来自客户端的连接消息 * recv,send使用的都是客户端的socket,不会向listen_st发送消息的 */ continue; } //客户端有事件到达 if (events[i].events & EPOLLIN) { //表示服务器这边的client_st接收到消息 if (socket_recv(events[i].data.fd) < 0) { close_socket(events[i].data.fd); //接收数据出错或者客户端已经关闭 events[i].data.fd = -1; /*这里continue是因为客户端socket已经被关闭了, * 但是这个socket可能还有其他的事件,会继续执行其他的事件, * 但是这个socket已经被设置成-1 * 所以后面的close_socket()函数都会报错 */ continue; } /* * 此处不能continue,因为每个socket都可能有多个事件同时发送到服务器端 * 这也是下面语句用if而不是if-else的原因, */ } //客户端有事件到达 if (events[i].events & EPOLLERR) { printf("EPOLLERR\n"); //返回出错事件,关闭socket,清理epoll池 close_socket(events[i].data.fd); events[i].data.fd = -1; continue; } //客户端有事件到达 if (events[i].events & EPOLLHUP) { printf("EPOLLHUP\n"); //返回挂起事件,关闭socket,清理epoll池 close_socket(events[i].data.fd); events[i].data.fd = -1; continue; } } } //close epoll close(epfd); //close server socket close_socket(listen_st); return 0;}
//网络编程客户端#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>//htons()函数头文件#include <netinet/in.h>//inet_addr()头文件#include <fcntl.h>#include <sys/epoll.h>#include "pub.h"int main(int arg,char *args[]){ if(arg<2) { printf("please print two param !\n"); } //端口号 int port=atoi(args[2]); //服务端IP地址 char ipaddr[30]={0}; strcpy(ipaddr,args[1]); //connect server int st=connect_server(ipaddr,port); //send message //发送消息-- socket_send(st); //close socket close(st); return 0;}
.SUFFIXES:.c .oCC=gccSRCS1=epoll_client.c pub.cSRCS2=epoll_server.c pub.cOBJS1=$(SRCS1:.c=.o)OBJS2=$(SRCS2:.c=.o)EXEC1=mclientEXEC2=mserverstart:$(OBJS1) $(OBJS2) $(CC) -o $(EXEC1) $(OBJS1) $(CC) -o $(EXEC2) $(OBJS2) @echo "-------ok-----------".c.o: $(CC) -Wall -g -o $@ -c $<clean: rm -f $(OBJS1) rm -f $(EXEC1) rm -f $(OBJS2) rm -f $(EXEC2)
Linux 网络编程八(epoll应用--大并发处理)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。