美文网首页
接受一个tcp连接

接受一个tcp连接

作者: 食梦狸猫 | 来源:发表于2019-03-21 22:32 被阅读0次

创建/释放一个evconnlistener

struct evconnlistener *evconnlistener_new(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    evutil_socket_t fd);
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    const struct sockaddr *sa, int socklen);
void evconnlistener_free(struct evconnlistener *lev);

当有连接到达时,会调用提供的回调函数。
ptr是传递给回调函数的参数。flags参数控制着listener的行为。backlog参数设置为允许的最大等待连接数量,如果backlog设置为负数,那么libevent会自己选择一个好的值,如果backlog是负数,那么libevent会认为我们已经调用了listen()

flags参数

  • LEV_OPT_LEAVE_SOCKETS_BLOCKING
    将接受到的连接设为阻塞

  • LEV_OPT_CLOSE_ON_FREE
    设置后,listener会在被释放后一并释放下层的socket

  • LEV_OPT_CLOSE_ON_EXEC

  • LEV_OPT_REUSEABLE
    在一些操作系统上的默认情况是,如果一个套接字关闭,那么在一段时间内,其他的套接字将不能绑定相同的端口。设置这个参数,开启端口复用。

  • LEV_OPT_THREADSAFE

  • LEV_OPT_DISABLED
    将listener初始化为不可使用的,可继续调用evconnlistener_enable()继续使用。

  • LEV_OPT_DEFERRED_ACCEPT
    尽量不使用。

listener的连接回调函数

typedef void (*evconnlistener_cb)(struct evconnlistener *listener,
    evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr);

当一个新的连接到达,这个回调函数开始执行,sock参数是一个新的用来连接的socket,ptr参数是一个用户提供的传给evconnlistener_new()的指针。

调整一个evconnlistener的回调函数

void evconnlistener_set_cb(struct evconnlistener *lev,
    evconnlistener_cb cb, void *arg);

获取一个evconnlistener的信息

evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
struct event_base *evconnlistener_get_base(struct evconnlistener *lev);

检查错误信息

我们可以设置一个错误回调函数,当accpet出错时调用。

typedef void (*evconnlistener_errorcb)(struct evconnlistener *lis, void *ptr);
void evconnlistener_set_error_cb(struct evconnlistener *lev,
    evconnlistener_errorcb errorcb);

例子:一个echo服务器

#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>

#include <arpa/inet.h>

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

static void
echo_read_cb(struct bufferevent *bev, void *ctx)
{
        /* This callback is invoked when there is data to read on bev. */
        struct evbuffer *input = bufferevent_get_input(bev);
        struct evbuffer *output = bufferevent_get_output(bev);

        /* Copy all the data from the input buffer to the output buffer. */
        evbuffer_add_buffer(output, input);
}

static void
echo_event_cb(struct bufferevent *bev, short events, void *ctx)
{
        if (events & BEV_EVENT_ERROR)
                perror("Error from bufferevent");
        if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
                bufferevent_free(bev);
        }
}

static void
accept_conn_cb(struct evconnlistener *listener,
    evutil_socket_t fd, struct sockaddr *address, int socklen,
    void *ctx)
{
        /* We got a new connection! Set up a bufferevent for it. */
        struct event_base *base = evconnlistener_get_base(listener);
        struct bufferevent *bev = bufferevent_socket_new(
                base, fd, BEV_OPT_CLOSE_ON_FREE);

        bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);

        bufferevent_enable(bev, EV_READ|EV_WRITE);
}

static void
accept_error_cb(struct evconnlistener *listener, void *ctx)
{
        struct event_base *base = evconnlistener_get_base(listener);
        int err = EVUTIL_SOCKET_ERROR();
        fprintf(stderr, "Got an error %d (%s) on the listener. "
                "Shutting down.\n", err, evutil_socket_error_to_string(err));

        event_base_loopexit(base, NULL);
}

int
main(int argc, char **argv)
{
        struct event_base *base;
        struct evconnlistener *listener;
        struct sockaddr_in sin;

        int port = 9876;

        if (argc > 1) {
                port = atoi(argv[1]);
        }
        if (port<=0 || port>65535) {
                puts("Invalid port");
                return 1;
        }

        base = event_base_new();
        if (!base) {
                puts("Couldn't open event base");
                return 1;
        }

        /* Clear the sockaddr before using it, in case there are extra
         * platform-specific fields that can mess us up. */
        memset(&sin, 0, sizeof(sin));
        /* This is an INET address */
        sin.sin_family = AF_INET;
        /* Listen on 0.0.0.0 */
        sin.sin_addr.s_addr = htonl(0);
        /* Listen on the given port. */
        sin.sin_port = htons(port);

        listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
            LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
            (struct sockaddr*)&sin, sizeof(sin));
        if (!listener) {
                perror("Couldn't create listener");
                return 1;
        }
        evconnlistener_set_error_cb(listener, accept_error_cb);

        event_base_dispatch(base);
        return 0;
}

相关文章

  • Erlang 各种 Socket 服务器 Demo

    TCP Echo server(只接收一次连接): TCP Echo server(接受多次连接,处理完一个连接后...

  • HAProxy介绍

    什么是haproxy? HAProxy是:一个TCP代理:它可以接受来自监听套接字的TCP连接,连接到一个服务器并...

  • 接受一个tcp连接

    创建/释放一个evconnlistener 当有连接到达时,会调用提供的回调函数。ptr是传递给回调函数的参数。f...

  • 计算机网络复习

    传输层 TCP TCP连接管理 TCP 是面向连接的协议。每一个 TCP 连接有三个阶段:连接建立、数据传送、连接...

  • 网络编程-socket

    TCP TCP服务端 创建套接字socket 绑定端口bind 侦听客户请求listen 接受客户连接accept...

  • ethereum p2p Kademlia的实现之五

    这篇文章主要分析两种tcp连接的建立 主动dial目标节点 接受其他节点的连接 先给出重要结论:无论是被动接受连接...

  • 网络 | 三次握手和四次握手

    一、 TCP连接——三次握手 1.TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务...

  • 587,TCP链接和HTTPs链接过程(面试点:TCP:第一次握

    TCP连接 TCP基础知识 TCP标志位 SYN 建立连接 ACK 表示响应 FIN 关闭连接 TCP连接...

  • tcp

    tcp三次握手:首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源。...

  • TCP(I) 连接管理

    TCP 连接管理 查看原文 TCP 连接的建立和终止 一个 TCP 连接由一个四元组构成:源 IP、源端口、目的 ...

网友评论

      本文标题:接受一个tcp连接

      本文链接:https://www.haomeiwen.com/subject/dwihvqtx.html