一、概述
sol_socket是一种基于事件驱动的网络I/O库,它能够在不同的平台上提供高性能、高可靠性的网络通信。sol_socket是一个轻型的库,它的核心是使用非阻塞I/O和事件通知处理I/O读写事件。sol_socket封装了socket系统调用和网络事件处理模型,提供了方便的编程接口。
二、基本使用
在使用sol_socket前,需要先建立一个event_base(事件处理器)对象、一个或多个event(事件)对象。
struct event_base* base = event_base_new();
struct event* ev = event_new(base, sock_fd, EV_READ|EV_PERSIST, sock_accept_cb, NULL);
以上代码建立了一个event_base对象和一个event对象。其中sock_fd是一个已经建立连接的socket文件描述符,EV_READ是事件类型,表示该事件是一个可读事件,EV_PERSIST表示事件触发后不自动删除。
接下来需要设置回调函数,当事件触发后会调用该回调函数:
void sock_accept_cb(int fd, short events, void* arg){
//处理事件的函数
}
以上代码是一个简单的回调函数,用于处理socket连接。
最后需要将事件添加到事件处理器的监听队列中:
event_add(ev, NULL);
以上代码实现了将事件添加到监听队列中。
三、事件类型
sol_socket定义了五种事件类型:
- EV_TIMEOUT:超时事件
- EV_READ:读事件
- EV_WRITE:写事件
- EV_SIGNAL:信号事件
- EV_PERSIST:事件持久化(只有添加的事件才会在事件处理完毕后从监听队列中删除,其它因为一次性事件(如超时事件)只会被处理一次)
四、常用函数介绍
1、event_base_new()
该函数用于建立一个事件处理器对象,返回该对象指针。
struct event_base* base = event_base_new();
2、event_new()
该函数用于建立一个事件对象,返回该对象指针。其中sock_fd是一个已经建立连接的socket文件描述符,EV_READ是事件类型,表示该事件是一个可读事件,EV_PERSIST表示事件触发后不自动删除。
struct event* ev = event_new(base, sock_fd, EV_READ|EV_PERSIST, sock_accept_cb, NULL);
3、event_add()
该函数用于将事件添加到事件处理器的监听队列中。
event_add(ev, NULL);
4、event_del()
该函数用于将事件从事件处理器的监听队列中删除。
event_del(ev);
5、event_priority_set()
该函数用于设置事件优先级,优先级越高的事件会优先被处理。默认优先级为0。正数优先级越高。
event_priority_set(ev, 1);
6、event_active()
该函数用于激活事件,并触发事件回调函数。
event_active(ev, EV_READ, 1);
五、完整示例代码
下面是一个简单的使用sol_socket库实现的基于TCP的echo服务器:
static void on_read(int fd, short event, void* arg);
static void on_accept(int fd, short event, void* arg);
int main(int argc, char **argv)
{
int listen_fd;
struct sockaddr_in address;
int reuseaddr_on = 1;
struct event_base *base;
struct event *listener_event;
if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Couldn't create server socket");
return 1;
}
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8888);
if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on,sizeof(reuseaddr_on)) == -1) {
perror("Setting SO_REUSEADDR failed");
return 1;
}
if (bind(listen_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
perror("Could not bind socket");
return 1;
}
if (listen(listen_fd, 10) < 0) {
perror("Could not open socket for listening");
return 1;
}
base = event_base_new();
if (!base) {
perror("Could not initialize libevent");
return 1;
}
listener_event = event_new(base, listen_fd, EV_READ | EV_PERSIST, on_accept, (void*)base);
event_add(listener_event, NULL);
event_base_dispatch(base);
return 0;
}
static void on_accept(int fd, short event, void* arg){
struct event_base *base = arg;
int client_fd;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
client_fd = accept(fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
perror("accept failed");
return;
}
printf("Accepted connection from %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
struct event *client_event = event_new(base, client_fd, EV_READ | EV_PERSIST, on_read, (void*)&client_fd);
event_add(client_event, NULL);
}
static void on_read(int fd, short event, void* arg){
char recvbuf[1024] = {0};
int client_fd = *(int*)arg;
int recvlen = recv(client_fd, recvbuf, sizeof(recvbuf), 0);
if (recvlen <= 0) {
printf("Client disconnected.\n");
close(client_fd);
event_del((struct event*)arg);
event_free((struct event*)arg);
return;
}
printf("Received data from client: %s", recvbuf);
send(client_fd, recvbuf, strlen(recvbuf), 0);
}
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/240325.html