一个轻量级跨平台网络事件库

一、性能对比

setup time event processing time

二、使用例程


#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include "picoev.h"
#include "picoev_w32.h"

#ifndef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#endif

#define HOST 0 /* 0x7f000001 for localhost */
#define PORT 23456
#define MAX_FDS 1024
#define TIMEOUT_SECS 10

static void setup_sock(int fd)
{
  char on = 1, r;
  unsigned long flag = 1;

  r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
  assert(r == 0);
  ioctlsocket(fd, FIONBIO, &flag);
  assert(r == 0);
}

static void close_conn(picoev_loop* loop, int fd)
{
  picoev_del(loop, fd);
  close(picoev_w32_fd2sock(fd));
  printf("closed: %d\n", fd);
}

static void rw_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
{
    if ((events & PICOEV_TIMEOUT) != 0) 
    {
        //超时
        close_conn(loop, fd);
    } 
    else if ((events & PICOEV_READ) != 0) 
    {
        //更新超时,读取数据
        char buf[1024];
        ssize_t r;
        picoev_set_timeout(loop, fd, TIMEOUT_SECS);
        r = recv(picoev_w32_fd2sock(fd), buf, sizeof(buf), 0);
        switch (r) 
        {
            case 0: //链接被客户端关闭
                close_conn(loop, fd);
            break;
            case -1: //出现异常
            if (errno == EAGAIN || errno == EWOULDBLOCK) 
            { 
                //稍后重试
                break;
            } 
            else 
            { 
                //严重出错
                close_conn(loop, fd);
            }
            break;
        default: //获取一些数据,并把这些数据回送回去
            if (send(picoev_w32_fd2sock(fd), buf, r, 0) != r) 
            {
                //一次发送所有数据失败,关闭
                close_conn(loop, fd); 
            }
        break;
    }

  }
}

static void accept_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
{
    int newfd = accept(picoev_w32_fd2sock(fd), NULL, NULL);
    if (newfd != -1) 
    {
        int sock = picoev_w32_sock2fd(newfd);
        printf("connected: %d\n", sock);
        setup_sock(newfd);
        picoev_add(loop, sock, PICOEV_READ, TIMEOUT_SECS, rw_callback, NULL);
    }
}

int main(void)
{
    picoev_loop* loop;
    int listen_sock;
    char flag;

    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 0), &wsaData);

    assert((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) != -1);
    flag = 1;
    assert(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == 0);
    struct sockaddr_in listen_addr;
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_port = htons(PORT);
    listen_addr.sin_addr.s_addr = htonl(HOST);
    assert(bind(listen_sock, (struct sockaddr*)&listen_addr, sizeof(listen_addr)) == 0);
    assert(listen(listen_sock, 5) == 0);
    setup_sock(listen_sock);

    //初始化库
    picoev_init(MAX_FDS);
    //创建事件循环
    loop = picoev_create_loop(60);
    //添加监听套接字
    picoev_add(loop, picoev_w32_sock2fd(listen_sock), PICOEV_READ, 0, accept_callback, NULL);
    //循环
    while (1) 
    {
        fputc('.', stdout); fflush(stdout);
        picoev_loop_once(loop, 10);
    }
    //清除事件循环
    picoev_destroy_loop(loop);
    picoev_deinit();

    return 0;
}