zoukankan      html  css  js  c++  java
  • 事件循环libevent实现echoclient

    最近使用开发的进程中出现了一个小问题,顺便记录一下原因和方法--事件循环

        基于libevent实现了一个简单的echoclient。之前在网上看到的都是echoserver。这里演示一下使用libevent进行客户端编程的基本步调。

        先看代码:

    #include "stdafx.h"
    #include "event2/event.h"
    #include "event2/util.h"
    
    #define ECHO_PORT   8888
    #define ECHO_SERVER "127.0.0.1"
    
    struct echo_context{
        struct event_base *base;
        struct event *event_write;
        struct event *event_read;
        const char * echo_contents;
        int echo_contents_len;
        int recved;
    };
    
    void write_cb(evutil_socket_t sock, short flags, void * args)
    {
        struct echo_context *ec = (struct echo_context *)args; 
    
        int ret = send(sock, ec->echo_contents, ec->echo_contents_len, 0);
        printf("connected, write to echo server: %d\n", ret);
        event_add(ec->event_read, 0);
    }
    
    void read_cb(evutil_socket_t sock, short flags, void * args)
    {
        struct echo_context *ec = (struct echo_context *)args; 
        char buf[128];
        int ret = recv(sock, buf, 128, 0);
        
        printf("read_cb, read %d bytes\n", ret);
        if(ret > 0)
        {
            ec->recved += ret;
            buf[ret] = 0;
            printf("recv:%s\n", buf);
        }
        else if(ret == 0)
        {
            printf("read_cb connection closed\n");
            event_base_loopexit(ec->base, NULL);
            return;
        }
        if(ec->recved < ec->echo_contents_len)
        {
            event_add(ec->event_read, 0);
        }
    }
    
    static evutil_socket_t make_tcp_socket()
    {
        int on = 1;
        evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
        evutil_make_socket_nonblocking(sock);
    #ifdef WIN32
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *)&on, sizeof(on));
    #else
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
    #endif
    
        return sock;
    }
    
    static void echo_client(struct event_base *base)
    {
        evutil_socket_t sock = make_tcp_socket();
        struct sockaddr_in serverAddr;
        struct event * ev_write = 0;
        struct event * ev_read = 0;
        struct timeval tv={10, 0};
        struct echo_context *ec = (struct echo_context*)calloc(1, sizeof(struct echo_context));
        
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(ECHO_PORT);
    #ifdef WIN32
        serverAddr.sin_addr.S_un.S_addr = inet_addr(ECHO_SERVER);
    #else
        serverAddr.sin_addr.s_addr = inet_addr(ECHO_SERVER);
    #endif
        memset(serverAddr.sin_zero, 0x00, 8);
    
        connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    
        ev_write = event_new(base, sock, EV_WRITE, write_cb, (void*)ec);
        ev_read = event_new(base, sock, EV_READ , read_cb, (void*)ec);
    
        ec->event_write = ev_write;
        ec->event_read = ev_read;
        ec->base = base;
        ec->echo_contents = strdup("echo client tneilc ohce\n");
        ec->echo_contents_len = strlen(ec->echo_contents);
        ec->recved = 0;
    
        event_add(ev_write, &tv);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        struct event_base * base = 0;
    #ifdef WIN32
        WORD wVersionRequested;
        WSADATA wsaData;
    
        wVersionRequested = MAKEWORD(2, 2);
    
        (void) WSAStartup(wVersionRequested, &wsaData);
    #endif
    
        base = event_base_new();
        echo_client(base);
        event_base_dispatch(base);
        event_base_free(base);
    
    	return 0;
    }
        每日一道理
    即使青春是一枝娇艳的花,但我明白,一枝独放永远不是春天,春天该是万紫千红的世界。 即使青春是一株大地伟岸的树,但我明白,一株独秀永远不是挺拔,成行成排的林木,才是遮风挡沙的绿色长城。即使青春是一叶大海孤高的帆,但我明白,一叶孤帆很难远航,千帆竞发才是大海的壮观。

        代码是在windows上实现的。

        使用libevent进行客户端编程的基本步调,在《libevent实现http client》中已经提过,基本如下:

        

    1. 初始化event_base(后续要运行事件循环)
    2. 创立socket,设置为异步,连接server
    3. 创立写读写事件,先将写事件参加事件循环
    4. 在写事件回调中向server端发送请求并将读事件参加事件循环
    5. 在读事件回调中处置数据,并根据数据是不是读取终了决定是不是继续添加读事件

        结合本文的示例代码,通过event_base_new()创立event_base,在初始化客户端socket(echo_client)之后,调用event_base_dispatch运行事件循环。

        echo_client函数初始化了socket,设置为非阻塞模式,调用connect连接到echoserver,然后添加一个写事件到事件循环中。当连接成功后,会触发写事件。这里将write_cb作为写事件的回调,在调用event_new()时传入。

        write_cb()写入一个字符串,然后添加一个读事件,在读事件中读取echoserver的回应。

        基本的进程就是这模样了。这是个简单的例子,更庞杂的例子,基本流程也是一样的。

        

    文章结束给大家分享下程序员的一些笑话语录: 问路
    有一个驾驶热气球的人发现他迷路了。他降低了飞行的高度,并认出了地面 上的一个人。他继续下降高度并对着那个人大叫,“打扰一下,你能告诉我我 在哪吗?”
    下面那个人说:“是的。你在热气球里啊,盘旋在 30 英尺的空中”。
    热气球上的人说:“你一定是在 IT 部门做技术工作”。
    “没错”,地面上的人说到,“你是怎么知道的?”
    “呵呵”,热气球上的人说,“你告诉我的每件事在技术上都是对的,但对都没 有用”。
    地面上的人说,“你一定是管理层的人”。
    “没错”,热气球上的人说,“可是你是怎么知道的?”
    “呵呵”,地面上的那人说到,“你不知道你在哪里,你也不知道你要去哪,你 总希望我能帮你。你现在和我们刚见面时还在原来那个地方,但现在却是我 错了”。

  • 相关阅读:
    【杂谈】需要mark的一些东西
    【codeforces】940F题解
    【codeforces】【比赛题解】#940 CF Round #466 (Div. 2)
    【FCS NOI2018】福建省冬摸鱼笔记 day6【FJOI 2018】福建省选混分滚蛋记 day1
    【FCS NOI2018】福建省冬摸鱼笔记 day5
    【FCS NOI2018】福建省冬摸鱼笔记 day4
    【FCS NOI2018】福建省冬摸鱼笔记 day3
    【FCS NOI2018】福建省冬摸鱼笔记 day2
    【FCS NOI2018】福建省冬摸鱼笔记 day1
    【6】装饰器、闭包、偏函数、变量作用域问题
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3085796.html
Copyright © 2011-2022 走看看