侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

基于epoll实现的一个简单的web服务器

2022-06-19 星期日 / 0 评论 / 0 点赞 / 86 阅读 / 7406 字

本文使用epoll建立一个简单的web服务器。通过epoll实现对过个端口的管理,非阻塞的数据发送。 使用到数据结构 typedef union epoll_data {

 本文使用epoll建立一个简单的web服务器。通过epoll实现对过个端口的管理,非阻塞的数据发送。

使用到数据结构  


typedef union epoll_data {                void *ptr;                int fd;         /*与之关联的处理的socket文件句柄*/                __uint32_t u32;                __uint64_t u64;        } epoll_data_t;               /*设置fd对应的epoll的管理事件*/        struct epoll_event {                __uint32_t events;      /*设置epoll可以处理的事件。见 详解1 ,可以用‘|' 将多个事件链接起来*/                epoll_data_t data;      /*与之关联的句柄数据,见上一个结构体*/        };

. 详解1
EPOLLIN:文件描述符可以读      EPOLLOUT:文件描述符可以写      EPOLLPRI:文件描述符有紧急的数据可写      EPOLLERR:文件描述符发生错误      EPOLLHUP:文件描述符被挂起      EPOLLET: 文件描述符有事件发生

所用到的函数:

1、int epoll_create(int size)

该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围(在我们做网络开发中应该是可以管理的端口的个数。就是可以接受链接的socket的个数)。


2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。

参数:epfd:由 epoll_create 生成的epoll专用的文件描述符;

op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修改、EPOLL_CTL_DEL 删除

fd:关联的socket文件描述符;

        event:指向epoll_event的指针,根据op的值对fd管理的事件进行操作,更改的事件在event中存放;

        如果调用成功返回0,不成功返回-1


3、int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)

该函数用于轮询I/O事件的发生;

参数:

epfd:由epoll_create 生成的epoll专用的文件描述符;

epoll_event:用于回传代处理事件的数组,即使将所有满足条件的socket文件描述对应的epoll_event中条件的epoll_event放到events数组中 ;

maxevents:每次能处理的事件数的最大值;

timeout:等待I/O事件发生的超时值;

返回发生事件数。


下面是一个例子:(本程序是在ubuntu12.04中运行成功,如果在别的系统上无法运行请谅解)

. .
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <sys/types.h>#include <unistd.h>#include <errno.h>#include <sys/epoll.h> /*设这文件句柄sfd为非阻塞**/static int make_socket_non_blocking (int sfd){    int flags, s;    flags = fcntl (sfd, F_GETFL, 0);    if (flags == -1)    {        perror ("fcntl");        return -1;    }     flags |= O_NONBLOCK;    s = fcntl (sfd, F_SETFL, flags);    if (s == -1)    {        perror ("fcntl");        return -1;    }     return 0;} /*创建epoll管理最大文件句柄的个数*parameter* @maxfds:最大的句柄个数。也就是网站数目。端口的数目*/int epoll_init(int maxfds){    return epoll_create(maxfds);} /*设这epoll管理每个文件句柄的参数和方法*parameter* @fd:要管理socket文件句柄* @maxfds:管理socket文件句柄的个数*/static struct epoll_event * epoll_event_init(int * fd, int maxfds){    struct epoll_event *events;    int i = 0;    if(0 >= maxfds || NULL ==fd) return NULL;    events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * maxfds);    for(; i < maxfds; i++)    {        events[i].data.fd = fd[i];        events[i].events = EPOLLIN | EPOLLET;    }    return events;}  int epoll_handler(int epfd, int * fd, int maxfds){    struct epoll_event *events = epoll_event_init(fd, maxfds);    struct epoll_event *ev = events;    int i = 0;    for(; i < maxfds; i++)    {        epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i], ev);        ev++;    }    }  /*  @description:开始服务端监听@parameterip:web服务器的地址port:web服务器的端口@result:成功返回创建socket套接字标识,错误返回-1 */int socket_listen( char *ip, unsigned short int port){    int res_socket; //返回值    int res, on;    struct sockaddr_in address;    struct in_addr in_ip;    res = res_socket = socket(AF_INET, SOCK_STREAM, 0);    setsockopt(res_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));    memset(&address, 0, sizeof(address));    address.sin_family = AF_INET ;    address.sin_port =htons(port);    address.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1");    res = bind( res_socket, (struct sockaddr *) &address, sizeof( address ) );    if(res) { printf( "port is used , not to repeat bind/n" ); exit(101); };    res = listen(res_socket,5);    if(res) { printf( "listen port is error ;/n" ); exit( 102 );  };    return res_socket ;}  void send_http1(int conn_socket){      char *send_buf = "HTTP/1.1 200 OK/r/nServer: Reage webserver/r/nContent-Type: text/html/r/nConnection: close/r/n/r/n<!DOCTYPE html><html><head><title>epoll learn</title></head><body><h1>Reage Test111111</h1>Hello World! </body></html>/r/n/r/n";    write(conn_socket, send_buf, strlen(send_buf));}void send_http2(int conn_socket){      char *send_buf = "HTTP/1.1 200 OK/r/nServer: Reage webserver/r/nContent-Type: text/html/r/nConnection: close/r/n/r/n<!DOCTYPE html><html><head><title>epoll learn</title></head><body><h1>Reage Test22222</h1>Hello World! </body></html>/r/n/r/n";    write(conn_socket, send_buf, strlen(send_buf));}   int main(int argc, char * argv[] ){       int  res_socket[2];    struct epoll_event event[100];    struct sockaddr_in client_addr;    int len;    res_socket[0] = socket_listen( "127.0.0.1", 1025) ;    res_socket[1] = socket_listen( "127.0.0.1", 1024) ;    make_socket_non_blocking(res_socket[0]);    make_socket_non_blocking(res_socket[1]);    int epfd = epoll_init(2);    epoll_handler(epfd, res_socket, 2);    while(1)    {        int count = epoll_wait(epfd, event, 2, -1);        while(count--)        {            sleep(10);            int connfd = accept(event[count].data.fd, (struct sockaddr *)&client_addr, &len);          //针对不同的端口,即是不同的网站进行不同的处理           if( event[count].data.fd == res_socket[0])                            send_http1(connfd);            else                send_http2(connfd);            close(connfd);        }      }   }
. . blogs :http://blog.csdn.net/rentiansheng/article/details/8684194 .   . . . .

广告 广告

评论区