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)

Linux 网络编程八(epoll应用--大并发处理)相关推荐

  1. 【Linux网络编程】epoll进阶之水平模式和边沿模式

    ------------->[Linux系统编程/网络编程](学习目录汇总) <-------------- 文章目录 1.epoll的事件模型 1.1 ET(边沿模式)的设置 1.2 基 ...

  2. Linux网络编程7——epoll反应堆模型

    学习视频链接 16-epoll反应堆main逻辑_bilibili_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1iJ411S7UA?p=81& ...

  3. Linux网络编程---I/O复用模型之epoll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之epoll 1. epoll模型简介 epoll是Li ...

  4. linux网络编程(三)select、poll和epoll

    linux网络编程(三)select.poll和epoll 一.为什么会有多路I/O转接服务器? 二.select 三.poll 三.epoll 一.为什么会有多路I/O转接服务器? 为什么会有多路I ...

  5. 详情讲述Linux网络编程关注的问题丨epoll原理丨reactor模型丨三次挥手丨四次握手丨多线程丨单线程丨C/C++Linux丨C++后端开发

    90分钟搞懂linux网络编程关注的问题 1. 三次挥手,四次握手 2. epoll实现原理剖析 3. reactor模型封装 单线程.多线程以及多进程 视频讲解如下,点击观看: 详情讲述Linux网 ...

  6. Linux网络编程(六)-高并发服务器03-I/O多路复用03:epoll【红黑树;根节点为监听节点】【无宏FD_SETSIZE限制;不需每次都将要监听的文件描述符从应用层拷贝到内核;不需遍历树】

    一.epoll概述 epoll的本质是一个[红黑树].监听结点为根节点. 大量并发,少量活跃效率高. epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并 ...

  7. 【网络编程】epoll 笔记

    一.最大连接数 1.select select在单进程中最多同时监听1024个fd:要想实现百万并发需要一千个进程,并且性能会很差.内存消耗巨大.所以select只适用于连接数在一千个以下的场景. 2 ...

  8. Linux网络编程——黑马程序员笔记

    01P-复习-Linux网络编程 02P-信号量生产者复习 03P-协议 协议: 一组规则. 04P-7层模型和4层模型及代表协议 分层模型结构: OSI七层模型: 物.数.网.传.会.表.应TCP/ ...

  9. Linux网络编程基础

    2019独角兽企业重金招聘Python工程师标准>>> (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的 ...

最新文章

  1. Halcon 点云拟合平面并获取单位法向量及位姿
  2. AI一分钟 | 阿里联合蚂蚁金服95亿美元收购饿了么;西湖大学正式获批成立
  3. Python 程序设计(第二版)董付国_清华大学出版社_习题答案与分析【针对8.4及其之前的】
  4. JDK 9/10/11:Java字符串上+ =带来的副作用
  5. socket 编程入门教程(一)TCP server 端:2、socket与文件描述符
  6. 看咒语,知情节?他们用《哈利·波特》让AI学习剧透
  7. 富士通大数据架构解决方案闪耀存储峰会
  8. XML-RPC 实现C++和C#交互
  9. 批处理取系统前一天时间并取备分文件日期为前一天的复制到本地
  10. 循序渐进 OSPF的详细剖析(二)
  11. Oracle 定时任务详解(dbms_scheduler)
  12. Microsoft Edge无法打开测试平台的解决方法
  13. w ndows热键,Window 10 优雅的快捷键
  14. 狼的处世十大哲理(想养狼的人必应)
  15. 洗地扫地机一体机好用吗、洗扫一体洗地机选购必看
  16. DLNA介绍(包括 UPnP)
  17. CSCW领域的“老”词和“新”词
  18. 各证件号码(身份证、护照、军官证、驾驶证、港澳台湾通行证、户口簿)正则表达式校验 完整正确
  19. surface pro 开发java_微软 Surface Pro、Studio、Laptop 全线更新
  20. 黄荣奎:如何快速、便捷开发小程序

热门文章

  1. 独立线性度 最佳直线
  2. 1034. 二哥的金链
  3. 深入理解softmax函数
  4. 内核态与用户态【转载】
  5. VS2005 there is no source code available for the current location 解决方案
  6. [转载]SQL Plus 一些使用技巧
  7. poj 2528_2
  8. CLI下的网页浏览器之二——Lynx
  9. 世界 Web 2.0 网站评奖揭晓
  10. java 如何去掉http debug日志_你居然还去服务器上捞日志,搭个日志收集系统难道不香吗?...