epoll中epoll_data_t 中fd和ptr的用法

文章是網上內容總結,爲了自己下次好找,所以寫到自己博客裏邊了。

fd存放文件描述符,所以我們一般直接

struct epoll_event event;
event.events=EPOLLIN;
 event.data.fd = 0;//監聽標準輸入

 epoll_data_t中的ptr怎麼用呢?是給用戶自由使用的。epoll 不關心裏面的內容。用戶可以用 epoll_data 這個 union 在 epoll_event 裏面附帶一些自定義的信息,這個 epoll_data 會隨着 epoll_wait 返回的 epoll_event 一併返回。那附帶的自定義消息,就是ptr指向這個自定義消息。

struct myevent_s {
    int fd;
    int events;
    void *arg;
    void (*call_back)(int fd, int events, void *arg);
    int status;
    char buf[BUFLEN];
    int len;
    long last_active;
};
struct myevent_s g_event; 
struct epoll_event epv = {0, {0}}; 
epv.data.ptr=&g_event;
//然後在epoll_wait()的第二個參數中的data.ptr會原封不動的把上邊的g_event返回給我們,所以我們可以利用這個ptr傳參。

在epoll模型中使用了一個struct epoll_event的結構體:

typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;

struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
可以看到,其中的data成員是一個聯合體,其成員有一個void*的指針,還有一個fd,一般用法是直接把socket賦給fd即可,但是,有了這個void*的指針,我們就可以在註冊socket的時候,傳進我們想要的參數。在wait出來的時候,我們可以用我們自己的函數進行處理。代碼如下:
server.c是一個簡單的回射服務器,用於接收客戶端發過來的數據,然後簡單回發給客戶端。
client.c是一個簡單的客戶端程序,由命令行參數輸入IP和端口8888,由用戶從鍵盤輸入數據,直接發給服務器,然後顯示服務器發回來的內容。
下面程序在Ubuntu12.04系統中測試沒有任何問題。
代碼如下:
 

#include <stdio.h>
#include <stdio.h>
#include "debug.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <sys/epoll.h>

typedef void (*a)(void);
typedef struct abc{
    a p;
    void *ptr;
    int sockfd;
}ABC;
void sock_handler(void)
{
    printf("my own socket handler\n");
}

int main()
{
    ABC ll;
    ll.p = sock_handler;
    ll.ptr = NULL;

    ll.p();
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == listenfd)
        errsys("socket");

    struct sockaddr_in myaddr = {0};
    struct sockaddr_in clientaddr = {0};
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(8888);
    myaddr.sin_addr.s_addr = inet_addr("0.0.0.0");//INADDR_ANY
    int len = sizeof myaddr;

    if(-1 == bind(listenfd, (struct sockaddr*)&myaddr, len))
        errsys("bind");

    if(-1 == listen(listenfd, 10))
        errsys("listen");

    int epoll_fd = epoll_create(1024);
    if(-1 == epoll_fd)
        errsys("epoll");
            struct epoll_event event = {0};
    event.events = EPOLLIN;
    ll.sockfd = listenfd;
    event.data.ptr = (void*)&ll;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenfd, &event);

#define BUFSIZE 100
#define MAXNFD  1024 

    struct epoll_event revents[MAXNFD] = {0};
    int nready;
    char buf[MAXNFD][BUFSIZE] = {0};
    while(1)
    {
        if(-1 == (nready = epoll_wait(epoll_fd, revents, MAXNFD, -1)) )
            errsys("poll");


        int i = 0;
        for(;i<nready; i++)
        {
            if(revents[i].events & EPOLLIN)
            {
//      

                ABC *cc = (ABC *)revents[i].data.ptr;

                if(cc->sockfd == listenfd)
                {
                    int sockfd = accept(listenfd, (struct sockaddr*)&clientaddr, &len);
                    if(-1 == sockfd)
                        errsys("accept");
                    debug("incoming: %s\n", inet_ntoa( clientaddr.sin_addr) );

                    struct epoll_event event = {0};
                    event.events = EPOLLIN;
                    ABC ll;
                    ll.p = sock_handler;
                    ll.sockfd = sockfd;
                    event.data.ptr = (void*)&ll;
                    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &event);
                }
                else
                {
                    int ret = read(cc->sockfd, buf[cc->sockfd], sizeof buf[0]);
                    if(0 == ret)
                    {
            //          close(revents[i].data.fd);
                        epoll_ctl(epoll_fd, EPOLL_CTL_DEL, cc->sockfd, &revents[i]);

                    }

                    revents[i].events = EPOLLOUT;
//                  ABC *ll = (ABC *)revents[i].data.ptr;
                    epoll_ctl(epoll_fd, EPOLL_CTL_MOD, cc->sockfd, &revents[i]);
                }

            }
            else if(revents[i].events & EPOLLOUT)
            {
                ABC *ll = (ABC*)(revents[i].data.ptr);
                ll->p();
                int ret = write(ll->sockfd, buf[ll->sockfd], sizeof buf[0]);
                printf("ret %d: %d\n", ll->sockfd, ret);
                revents[i].events = EPOLLIN;
                epoll_ctl(epoll_fd, EPOLL_CTL_MOD, ll->sockfd, &revents[i]);
            }
        }
    }

    close(listenfd);
}

 client

#include <stdio.h>
#include "debug.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
    if(3 != argc)
    {
        printf("Usage: %s <IP> <PORT>\n", argv[0]);
        return -1;
    }

    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 
    if(-1 == sockfd)
        errsys("socket");

    struct sockaddr_in serveraddr = {0};
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);//IPv4
    int len = sizeof serveraddr;

    if(-1 == connect(sockfd, (struct sockaddr*)&serveraddr, len))
        errsys("connect");

    char buf[100] = {0};
    while(1)
    {
        printf("mydatabase> ");fflush(stdout);
        gets(buf);
        int ret = write(sockfd, buf, sizeof buf);
        ret = read(sockfd, buf, sizeof buf);
        printf("%s\n", buf);
    }
    close(sockfd);
}

debug.h:

#ifndef _DEBUG_
#define _DEBUG_

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#ifdef DEBUG
    #define debug(arg...)  printf(arg)
#else
    #define debug(arg...)
#endif

#define errsys(str...) do{\
            fprintf(stderr, str);\
            fprintf(stderr, ": %s\n", strerror(errno));\
            exit(-1); \
            }while(0)

#endif

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章