Network programming libevent示例代码的一个问题:如何调用?

Network programming libevent示例代码的一个问题:如何调用?,network-programming,libevent,Network Programming,Libevent,我正在学习libev,但是代码很难理解,所以我选择先学习libevent,它的代码相对更清晰。但是我在尝试示例()时遇到了一个问题 如何调用do_read()make do_write()函数中的代码事件(state->write_event,NULL) /* For sockaddr_in */ #include <netinet/in.h> /* For socket functions */ #include <sys/socket.h> /* For fc

我正在学习libev,但是代码很难理解,所以我选择先学习libevent,它的代码相对更清晰。但是我在尝试示例()时遇到了一个问题

如何调用do_read()make do_write()函数中的代码事件(state->write_event,NULL)

    /* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>

#include <event2/event.h>

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

#define MAX_LINE 16384

void do_read(evutil_socket_t fd, short events, void *arg);
void do_write(evutil_socket_t fd, short events, void *arg);

char
rot13_char(char c)
{
    return c;
    /* We don't want to use isalpha here; setting the locale would change
     * which characters are considered alphabetical. */
    if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
        return c + 13;
    else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
        return c - 13;
    else
        return c;
}

struct fd_state {
    char buffer[MAX_LINE];
    size_t buffer_used;

    size_t n_written;
    size_t write_upto;

    struct event *read_event;
    struct event *write_event;
};

struct fd_state *
alloc_fd_state(struct event_base *base, evutil_socket_t fd)
{
    struct fd_state *state = malloc(sizeof(struct fd_state));
    if (!state)
        return NULL;
    state->read_event = event_new(base, fd, EV_READ|EV_PERSIST, do_read, state);
    if (!state->read_event) {
        free(state);
        return NULL;
    }
    state->write_event =
        event_new(base, fd, EV_WRITE|EV_PERSIST, do_write, state);

    if (!state->write_event) {
        event_free(state->read_event);
        free(state);
        return NULL;
    }

    state->buffer_used = state->n_written = state->write_upto = 0;

    assert(state->write_event);
    return state;
}

void
free_fd_state(struct fd_state *state)
{
    event_free(state->read_event);
    event_free(state->write_event);
    free(state);
}

void
do_read(evutil_socket_t fd, short events, void *arg)
{
    struct fd_state *state = arg;
    char buf[1024];
    int i;
    ssize_t result;
    while (1) {
        assert(state->write_event);
        result = recv(fd, buf, sizeof(buf), 0);
        if (result <= 0)
            break;

        for (i=0; i < result; ++i)  {
            if (state->buffer_used < sizeof(state->buffer))
                state->buffer[state->buffer_used++] = rot13_char(buf[i]);
            if (buf[i] == '\n') {
                assert(state->write_event);
                **event_add(state->write_event, NULL);**
                state->write_upto = state->buffer_used;
            }
        }
    }

    if (result == 0) {
        free_fd_state(state);
    } else if (result < 0) {
        if (errno == EAGAIN) // XXXX use evutil macro
            return;
        perror("recv");
        free_fd_state(state);
    }
}

void
**do_write(evutil_socket_t fd, short events, void *arg)**
{
    struct fd_state *state = arg;

    while (state->n_written < state->write_upto) {
        ssize_t result = send(fd, state->buffer + state->n_written,
                              state->write_upto - state->n_written, 0);
        if (result < 0) {
            if (errno == EAGAIN) // XXX use evutil macro
                return;
            free_fd_state(state);
            return;
        }
        assert(result != 0);

        state->n_written += result;
    }

    if (state->n_written == state->buffer_used)
        state->n_written = state->write_upto = state->buffer_used = 1;

    event_del(state->write_event);
}

void
do_accept(evutil_socket_t listener, short event, void *arg)
{
    struct event_base *base = arg;
    struct sockaddr_storage ss;
    socklen_t slen = sizeof(ss);
    int fd = accept(listener, (struct sockaddr*)&ss, &slen);
    if (fd < 0) { // XXXX eagain??
        perror("accept");
    } else if (fd > FD_SETSIZE) {
        close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET */
    } else {
        struct fd_state *state;
        evutil_make_socket_nonblocking(fd);
        state = alloc_fd_state(base, fd);
        assert(state); /*XXX err*/
        assert(state->write_event);
        event_add(state->read_event, NULL);
    }
}

void
run(void)
{
    evutil_socket_t listener;
    struct sockaddr_in sin;
    struct event_base *base;
    struct event *listener_event;

    base = event_base_new();
    if (!base)
        return; /*XXXerr*/

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(40713);

    listener = socket(AF_INET, SOCK_STREAM, 0);
    evutil_make_socket_nonblocking(listener);

#ifndef WIN32
    {
        int one = 1;
        setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    }
#endif

    if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
        perror("bind");
        return;
    }

    if (listen(listener, 16)<0) {
        perror("listen");
        return;
    }

    listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);
    /*XXX check it */
    event_add(listener_event, NULL);

    event_base_dispatch(base);
}

int
main(int c, char **v)
{
    setvbuf(stdout, NULL, _IONBF, 0);

    run();
    return 0;
}
中的sockaddr\u的
/**/
#包括
/*用于套接字函数*/
#包括
/*对于fcntl*/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义最大值线16384
void do_read(evutil_socket_t fd,短事件,void*arg);
void do_write(evutil_socket_t fd,短事件,void*arg);
烧焦
rot13_字符(字符c)
{
返回c;
/*我们不想在这里使用isalpha;设置区域设置会改变
*哪些字符按字母顺序排列*/
如果((c>='a'&&c='a'&&c='n'&&c='n'&&c read\u event=event\u new)(基本、fd、EV\u read、EV\u PERSIST、do\u read、state);
如果(!状态->读取事件){
自由(州);
返回NULL;
}
状态->写入事件=
事件(基本、fd、EV_写入、EV_持续、do_写入、状态);
如果(!状态->写入事件){
无事件(状态->读取事件);
自由(州);
返回NULL;
}
state->buffer\u used=state->n\u write=state->write\u upto=0;
断言(状态->写入事件);
返回状态;
}
无效的
自由fd_状态(结构fd_状态*状态)
{
无事件(状态->读取事件);
无事件(状态->写入事件);
自由(州);
}
无效的
do_read(evutil_socket_t fd,短事件,void*arg)
{
结构fd_state*state=arg;
char-buf[1024];
int i;
对结果进行量化;
而(1){
断言(状态->写入事件);
结果=recv(fd,buf,sizeof(buf),0);
if(使用的结果缓冲区buffer))
state->buffer[state->buffer_used++]=rot13_char(buf[i]);
如果(buf[i]='\n'){
断言(状态->写入事件);
**事件添加(状态->写入事件,空)**
状态->写入=状态->使用的缓冲区;
}
}
}
如果(结果==0){
自由州(州);
}否则如果(结果<0){
如果(errno==EAGAIN)//XXXX使用evutil宏
返回;
perror(“recv”);
自由州(州);
}
}
无效的
**do_write(evutil_socket_t fd,短事件,void*arg)**
{
结构fd_state*state=arg;
同时(状态->n_写入<状态->写入到){
ssize_t result=send(fd,state->buffer+state->n_writed,
状态->写入到-状态->未写入,0);
如果(结果<0){
如果(errno==EAGAIN)//XXX使用evutil宏
返回;
自由州(州);
返回;
}
断言(结果!=0);
状态->n_写入+=结果;
}
if(state->n\u writed==state->buffer\u used)
state->n_writed=state->write_upto=state->buffer_used=1;
事件删除(状态->写入事件);
}
无效的
do_accept(evutil_socket_t侦听器、短事件、void*arg)
{
结构事件_base*base=arg;
结构sockaddr_存储ss;
socklen_t slen=sizeof(ss);
int fd=accept(侦听器,(结构sockaddr*)&ss和slen);
如果(fd<0){//XXXX-eagain??
佩罗(“接受”);
}否则如果(fd>fd_设置大小){
close(fd);//XXX用EVUTIL_CLOSESOCKET替换所有close*/
}否则{
结构fd_状态*状态;
evutil_使_插座_非阻塞(fd);
状态=alloc_fd_状态(基本,fd);
断言(状态);/*XXX错误*/
断言(状态->写入事件);
事件添加(状态->读取事件,空);
}
}
无效的
运行(无效)
{
evutil_套接字_t侦听器;
sin中的结构sockaddr_;
结构事件库*base;
结构事件*侦听器事件;
base=事件\基础\新();
如果(!base)
返回;/*xxxer*/
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=0;
sin.sin_port=htons(40713);
侦听器=socket(AF_INET,SOCK_STREAM,0);
evutil_使_套接字_非阻塞(侦听器);
#ifndef WIN32
{
int-one=1;
setsockopt(监听器,SOL_套接字,SO_REUSEADDR,&one,sizeof(one));
}
#恩迪夫
if(bind(listener,(struct sockaddr*)&sin,sizeof(sin))<0){
佩罗(“绑定”);
返回;
}

如果(听)(听众,16)我不确定我是否回答了你问的同一个问题——我理解为:

do\u read()
中调用
event\u add(state->write\u event,NULL)
如何导致调用
do\u write()

弄清楚这一点的关键是理解
do\u read()
函数实际在做什么。do\u read()是一个回调函数,与一个套接字关联,该套接字具有要读取的数据:这是通过
allocate\u fd\u state()设置的:

不过,在这一点上,这两个事件都没有被
event\u add()
”添加到事件库中。操作说明都写出来了,但没有人查看。那么如何读取任何内容呢?
state->read\u event
event\u add()在建立传入连接后,
“已安装到基座。请查看
do\u accept()

因此,在从文件描述符读入一些数据后,程序开始等待,直到 文件描述符已准备好写入,然后调用
do\u write()
程序 流程如下所示:

[ set up an event_base and start waiting for events ]
[ if someone tries to connect ]
    [ accept the connection ]

[ ... wait until there is data to read on the connection ... ]

[ read in data from the connection until there is no more left ]

[ ....wait until the connection is ready to be written to ... ]

[ write out our rot13() encoded response ]
我希望a)这是对你问题的正确解释,b)这是一个有用的答案

void
do_accept(evutil_socket_t listener, short event, void *arg)
{
    [ ... accept a new connection and give it a file descriptor fd ... ]

    /*
     * If the file descriptor is invalid, close it.
     */
    if (fd < 0) { // XXXX eagain??
        perror("accept");
    } else if (fd > FD_SETSIZE) {
        close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET */
    /*
     * Otherwise, if the connection was successfully accepted...
     */
    } else {
        [ ... allocate a new fd_state structure, and make the file descriptor non-blocking ...]
        /*
         * Here's where the magic happens. The read_event created back in alloc_fd_state()
         * is finally added to the base associated with it.
         */
        event_add(state->read_event, NULL);
    }
}
void
do_read(evutil_socket_t fd, short events, void *arg)
{
    /* Create a temporary buffer to receive some data */
    char buf[1024];

    while (1) {
        [ ... Receive the data, copying it into buf ... ]
        [ ... if there is no more data to receive, or there was an error, exit this loop... ]

        [ ... else, result = number of bytes received ... ]
        for (i=0; i < result; ++i)  {
            [ ... if there's room in the buffer, copy in the rot13() encoded
                  version of the received data ... ]
            /*
             * Boom, headshot. If we've reached the end of the incoming data
             * (assumed to be a newline), then ...
             */
            if (buf[i] == '\n') {
                [...]
                /*
                 * Have libevent start monitoring the write_event, which calls do_write
                 * as soon as the file descriptor is ready to be written to.
                 */
                event_add(state->write_event, NULL);
                [...]
            }
        }
    }
    [...]    
}
[ set up an event_base and start waiting for events ]
[ if someone tries to connect ]
    [ accept the connection ]

[ ... wait until there is data to read on the connection ... ]

[ read in data from the connection until there is no more left ]

[ ....wait until the connection is ready to be written to ... ]

[ write out our rot13() encoded response ]