echo server

1.The libevent API provides a mechanism[机制] to execute a callback function when a specific event occurs on a file descriptor or after a timeout has been reached. Furthermore, libevent also support callbacks due to signals or regular timeouts.

//支持I/O 信号 定时器

2.libevent supports /dev/poll, kqueue(2), event ports, POSIX select(2), Windows select(), poll(2), and epoll(4).

3.Libevent can also be used for multi-threaded applications, either by isolating[孤立] each event_base so that only a single thread accesses it, or by locked access to a single shared event_base. 

//默认单线程,也可以用于多线程(一个线程一个event_base,或者加锁)。

跨平台、异步事件驱动:ACE_Reactor好像也是事件驱动、Reactor模式

// echo server.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <event2/event.h>
#include <event2/bufferevent.h>

void do_accept(evutil_socket_t listener, short event, void *arg);
void read_cb(struct bufferevent *bev, void *arg);
void error_cb(struct bufferevent *bev, short event, void *arg);
void write_cb(struct bufferevent *bev, void *arg);

int _tmain(int argc, _TCHAR* argv[])
{
	int ret = 0;

#ifdef WIN32  
	WSADATA wsa_data;  
	WSAStartup(0x0201, &wsa_data);  
#endif

	evutil_socket_t lsocket;
	lsocket = socket(AF_INET,SOCK_STREAM,0);

	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.S_un.S_addr = 0;
	sin.sin_port = htons(8889);

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

	if(listen(lsocket,10) < 0)
	{
		perror("listen");
		return -1;
	}

	struct event_base *base = event_base_new();
	struct event* listen_event;
	listen_event = event_new(base,lsocket,EV_READ|EV_PERSIST,do_accept,(void*)base);
	event_add(listen_event,NULL);
	event_base_dispatch(base);

	return 0;
}

void do_accept(evutil_socket_t tsocket,short event,void *arg)
{
	typedef int socklen_t;
	struct event_base *base = (struct event_base*)arg;
	struct sockaddr_in sin;
	socklen_t slen = sizeof(sin);
	evutil_socket_t fd = accept(tsocket,(struct sockaddr*)&sin,&slen);
	if(fd < 0)
	{
		perror("accept");
		return;
	}

	struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	bufferevent_setcb(bev, read_cb, NULL, error_cb, arg);
	bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
}

void read_cb(struct bufferevent *bev, void *arg)
{
#define MAX_LINE    256
	char line[MAX_LINE+1];
	evutil_socket_t fd = bufferevent_getfd(bev);

	int n = 0;
	while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) 
	{
		line[n] = '\0';
		printf("fd=%u, read line: %s\n", fd, line);
		bufferevent_write(bev, line, n);
	}
}

void write_cb(struct bufferevent *bev, void *arg) 
{
}

void error_cb(struct bufferevent *bev, short event, void *arg)
{
	evutil_socket_t fd = bufferevent_getfd(bev);
	printf("fd = %u, ", fd);
	if (event & BEV_EVENT_TIMEOUT) 
	{
		printf("Timed out\n"); //if bufferevent_set_timeouts() called
	}
	else if (event & BEV_EVENT_EOF) 
	{
		printf("connection closed\n");
	}
	else if (event & BEV_EVENT_ERROR) 
	{
		printf("some other error\n");
	}
	bufferevent_free(bev);

  evutil_socket_t:在除Windows之外的大多数地方,套接字是个整数,操作系统按照数值次序进行处理。然而,使用Windows套接字API时,socket类型为SOCKET(句柄),收到这个句柄的次序是未定义的。所以,在Windows中,libevent定义evutil_socket_t类型为整型指针,可以处理socket()或者accept()的输出,而没有指针截断的风险,如以下宏:

#ifdef WIN32
#define evutil_socket_t intptr_t
#else
#define evutil_socket_t int
#endif
echo代码来自网络


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
lwIP(Lightweight IP)是一个轻量级的开源TCP/IP协议栈,它被设计为可移植、可扩展和高度定制化,适用于各种嵌入式系统。其中,echo server是lwIP协议栈中比较基本的一个应用。 Echo server的作用是将接收到的数据原样返回给发送方。在lwIP中,echo server是由一个名为echod的应用程序实现的。下面,我将详细介绍lwIP echo server的实现流程。 1. 创建socket 首先,我们需要创建一个socket,用于监听客户端的连接请求。在lwIP中,socket是通过调用lwip_socket()函数创建的。例如: ``` int sock = lwip_socket(AF_INET, SOCK_STREAM, 0); ``` 其中,AF_INET表示IPv4地址族,SOCK_STREAM表示TCP协议。 2. 绑定IP地址和端口号 创建socket后,我们需要将其绑定到一个IP地址和端口号上,以便客户端能够连接到服务器。在lwIP中,可以通过调用lwip_bind()函数实现。例如: ``` struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(7); // Echo server默认端口号为7 addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网络接口 lwip_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); ``` 其中,INADDR_ANY表示监听所有网络接口。 3. 监听连接请求 绑定端口号后,我们需要开始监听连接请求。在lwIP中,可以通过调用lwip_listen()函数实现。例如: ``` lwip_listen(sock, 5); // 允许同时连接的客户端数量为5 ``` 4. 接受连接 当有客户端连接到服务器时,我们需要接受连接请求,并创建一个新的socket用于与该客户端通信。在lwIP中,可以通过调用lwip_accept()函数实现。例如: ``` struct sockaddr_in client_addr; int client_sock = lwip_accept(sock, (struct sockaddr *)&client_addr, sizeof(client_addr)); ``` 5. 接收数据 当与客户端建立连接后,我们需要等待客户端发送数据。在lwIP中,可以通过调用lwip_read()函数实现。例如: ``` char buf[1024]; int len = lwip_read(client_sock, buf, sizeof(buf)); ``` 6. 发送数据 接收到客户端的数据后,我们需要将其原样返回给客户端。在lwIP中,可以通过调用lwip_write()函数实现。例如: ``` lwip_write(client_sock, buf, len); ``` 7. 关闭socket 当通信结束后,我们需要关闭与客户端建立的socket。在lwIP中,可以通过调用lwip_close()函数实现。例如: ``` lwip_close(client_sock); ``` 8. 释放资源 最后,我们需要释放创建的socket资源。在lwIP中,可以通过调用lwip_shutdown()函数实现。例如: ``` lwip_shutdown(sock, SHUT_RDWR); ``` 以上就是lwIP echo server的实现流程。需要注意的是,echod应用程序是在一个单独的线程中运行的,它不断地等待客户端的连接请求,并在接收到数据后将其原样返回给客户端。如果有多个客户端连接到服务器,echod应用程序会为每个客户端创建一个新的socket,从而实现多客户端同时连接的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值