网络编程-libevnet不带缓冲的事件框架

网络编程-libevnet不带缓冲的事件框架

1.1工作流程

图1 工作流程

常用的API:

分类

API

含义

 

事件

框架

struct event_base* event_base_new(void);

创建事件框架

event_base_free(struct event_base* base);

释放事件框架

const char *event_base_get_method(const struct event_base *base);

获取支持的使用IO方法

 

 

 

事件

struct event *event_new(struct event_base *base,

evutil_socket_t fd, shord what, event_callback_fn cb,

void *arg);

创建新事件:

EV_READ:读

EV_WRITE:写

EV_SIGNAL:信号量EV_PERSIST:持续触发EV_ET://边沿模式

void event_free(struct event *event);

释放事件

int event_add( struct event *ev, const struct timeval *tv);

设置未决事件

int event_del(struct event *ev);

设置已决事件

event_base_dispatch(struct event_base* base)

开始循环

int event_base_loopexit( struct event_base *base,

    const struct timeval *tv);

延迟终止循环(需等待本次事件完成)

int event_base_loopbreak(struct event_base *base);

立即终止循环

 先看效果:先开启服务器后开启服务器

这个例子简单的连接,取代传统的socket的编写网络编程,还有就是采用多路IO复用的方式来实现并发,此程序沒有进行优化,比如

  • 当首先启动客户端程序的时候,将发生崩溃
  • 当停止连接的时候,杀掉服务端,客户端将疯狂输出
  • 没有使用的其他的事件服务来优化代码,比如定时器,信号量等,这个主要在带缓存的事件服务框架里

1.2客户端代码

#include<sys/types.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<arpa/inet.h>  
#include<errno.h>  
#include<unistd.h>  
  
#include<stdio.h>  
#include<string.h>
#include<stdlib.h>  
  
#include<event.h>  
#include<event2/bufferevent.h>  
#include<event2/buffer.h>  
#include<event2/util.h>  

typedef struct sockaddr SA;  

typedef  struct
{
    char head[4];
    unsigned long pack_len;
    int code;
} msg_header;

char buf[50];

void read_cb(evutil_socket_t fd, short what, void *arg)
{
    char buf[1024] = {0};
    int len = read(fd, buf, sizeof(buf));
    printf("say:%s\n", buf);
    sleep(1);
}

  
int tcp_connect_server(const char* server_ip, int port)  
{  
    int sockfd, status, save_errno;  
    struct sockaddr_in server_addr;  
  
    memset(&server_addr, 0, sizeof(server_addr) );  
  
    server_addr.sin_family = AF_INET;  
    server_addr.sin_port = htons(port);  
    status = inet_aton(server_ip, &server_addr.sin_addr);  
  
    if( status == 0 ) 
    {  
        errno = EINVAL;  
        return -1;  
    }  
  
    sockfd = socket(PF_INET, SOCK_STREAM, 0);  
    if( sockfd == -1 )  
        return sockfd;  
  
    status = connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );  
  
    if( status == -1 )  
    {  
        save_errno = errno;  
        close(sockfd);  
        errno = save_errno;
        return -1;  
    }  
  
    evutil_make_socket_nonblocking(sockfd);  
  
    return sockfd;  
}  

void tcp_send(int sockfd)
{
    msg_header st1;
    memcpy(st1.head, "kpr", 4);
    st1.pack_len = 8;
    st1.code = 0;

    memcpy(buf, &st1, sizeof(msg_header));
    memcpy(buf+sizeof(msg_header),"lishuwei",9);
    
    printf("head:%s\n", st1.head);
    printf("code:%d\n", st1.code);
    printf("pack_len:%d\n", st1.pack_len);
    printf("key:%s\n", buf+sizeof(msg_header));

    if(-1==write(sockfd,buf,sizeof(buf)+1))
    {
        printf("socket write error");
    }
}

int start_connct(char* server_ip, int port)  
{   

   printf("msg_header111:%d",sizeof( msg_header));

    //两个参数依次是服务器端的IP地址、端口号  
    int sockfd = tcp_connect_server(server_ip, port);  
    if( sockfd == -1)  
    {  
        perror("tcp_connect error ");  
        return -1;  
    }  
  
    printf("connect to server successful\n");  

    tcp_send(sockfd);

    struct event_base* base = NULL;
    base = event_base_new();

    // 创建事件
    struct event* ev = NULL;
    ev = event_new(base, sockfd, EV_READ | EV_PERSIST, read_cb, NULL);
    event_add(ev, NULL);

    event_base_dispatch(base);

    event_free(ev);
    event_base_free(base);
    close(sockfd);
    printf("finished \n");  
    return  1;  
}  

int main(int argc,char* argv[])
{
    start_connct(argv[1],atoi(argv[2]));
    return 0;
}

1.3 服务器

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "arpa/inet.h"
#include "event.h"
#include <signal.h>

typedef struct sockaddr SA;

typedef  struct
{
    char head[4];
    unsigned long pack_len;
    int code;
} msg_header;

void accept_cb(int fd, short events, void* arg);
void socket_read_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int  tcp_server_init(int port, int listen_num);

int main(int argc, char** argv)
{
    int listener = tcp_server_init(9999, 10);
    if( listener == -1 )
    {
        perror(" tcp_server_init error ");
        return -1;
    }

    struct event_base* base = event_base_new();
    struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
                                        accept_cb, base);
    event_add(ev_listen, NULL);

    event_base_dispatch(base);
    event_base_free(base);
    
    return 0;
}

void accept_cb(int fd, short events, void* arg)
{
    evutil_socket_t sockfd;

    struct sockaddr_in client;
    socklen_t len = sizeof(client);

    sockfd = accept(fd, (struct sockaddr*)&client, &len );
    evutil_make_socket_nonblocking(sockfd);
    printf("accept a client %d\n", sockfd);

    struct event_base* base = (struct event_base*)arg;
    struct bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg);

    bufferevent_enable(bev, EV_READ | EV_PERSIST);
}

void socket_read_cb(struct bufferevent* bev, void* arg)
{
    msg_header st2;
    char msg[4096];

    size_t len = bufferevent_read(bev, msg, sizeof(msg));

    memcpy(&st2, msg, sizeof(msg_header));
    printf("socket_read_cb head:%s\n", st2.head);
    printf("socket_read_cb code:%d\n", st2.code);
    printf("socket_read_cb pack_len:%d\n", st2.pack_len);
    printf("socket_read_cb key:%s\n", msg+sizeof(msg_header));
    
    bufferevent_write(bev,msg,sizeof(msg_header)+st2.pack_len);
}

void event_cb(struct bufferevent *bev, short event, void *arg)
{
    if (event & BEV_EVENT_EOF)
        printf("connection closed\n");
    else if (event & BEV_EVENT_ERROR)
        printf("some other error\n");

    bufferevent_free(bev);
}

int tcp_server_init(int port, int listen_num)
{   
    int errno_save;
    evutil_socket_t listener;
    
    listener = socket(AF_INET, SOCK_STREAM, 0);
    if( listener == -1 )
        return -1;
    
    //允许多次绑定同一个地址。要用在socket和bind之间
    evutil_make_listen_socket_reuseable(listener);
    
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(port);

    if( bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
        goto error;

    if( listen(listener, listen_num) < 0)
        goto error;

    //跨平台统一接口,将套接字设置为非阻塞状态
    evutil_make_socket_nonblocking(listener);

    return listener;

error:
    evutil_closesocket(listener);
    
    return -1;
}

参考:

https://blog.gmem.cc/libevent-study-note

https://blog.csdn.net/weixin_44718794/article/details/107065921 

先看效果:先开启服务器后开启服务器

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值