http://www.cnblogs.com/zhanggaofeng/p/5901316.html
//头文件 pub.h #ifndef _vsucess#define _vsucess#ifdef __cplusplus extern "C" {#endif //服务器创建socket int server_socket(int port);//设置非阻塞 int setnonblock(int st);//接收客户端socket int server_accept(int st);//关闭socket int 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//创建socket int 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));//typeaddr.sin_family = AF_INET;//portaddr.sin_port = htons(port);//ipaddr.sin_addr.s_addr = htonl(INADDR_ANY);//bind ip addressif (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1){printf("bind failed ! error message :%s\n", strerror(errno));//close socket close_socket(st);return -1;}//listenif (listen(st, 20) == -1){printf("listen failed ! error message :%s\n", strerror(errno));//close socket close_socket(st);return -1;}return 0; }//服务器创建socket int server_socket(int port) {if (port < 0){printf("function server_socket param not correct !\n");return -1;}//create socketint st = socket_create();if (st < 0){return -1;}//reuseaddrif (socket_reuseaddr(st) < 0){return -1;}//bind and listenif (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 serverstruct 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; }//接收客户端socket int 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; }//关闭socket int 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 keyboardread(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 socketint 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){//接收客户端socketint 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池,当关闭socket并且events[i].data.fd=-1,epoll会自动将该socket从池中清除 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 serverint st=connect_server(ipaddr,port);//send message//发送消息-- socket_send(st);//close socket close(st);return 0; }
.SUFFIXES:.c .o CC=gcc SRCS1=epoll_client.c\pub.c SRCS2=epoll_server.c\pub.c OBJS1=$(SRCS1:.c=.o) OBJS2=$(SRCS2:.c=.o) EXEC1=mclient EXEC2=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)