面试题答案
一键面试整体架构设计
- 网络层:负责监听客户端的TCP连接请求。使用libevent的
evconnlistener
来监听指定端口,当有新连接到来时,evconnlistener
会触发相应的回调函数。 - 连接管理模块:维护所有客户端的连接信息。可以使用一个数据结构(如链表或哈希表)来存储每个连接对应的
event_base
、bufferevent
等相关信息。 - 消息分发模块:接收来自客户端的消息,并将其分发给相应的处理逻辑。可以根据消息的类型(如聊天消息、用户登录消息等)来进行分发。
- 业务逻辑处理模块:处理具体的业务逻辑,如用户认证、消息存储、消息转发等。
- 异常处理模块:处理连接异常、消息格式错误等各种异常情况。
利用libevent处理关键环节
连接管理
- 监听新连接:
struct event_base *base = event_base_new(); struct evconnlistener *listener = evconnlistener_new_bind( base, accept_conn_cb, // 新连接到来的回调函数 (void *)base, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 10, evutil_make_sockaddr("0.0.0.0", 12345) );
- 处理新连接:
static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data) { struct event_base *base = (struct event_base *)user_data; struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, read_cb, NULL, error_cb, NULL); bufferevent_enable(bev, EV_READ|EV_WRITE); }
- 维护连接状态:将每个连接对应的
bufferevent
等信息存储在连接管理模块的数据结构中,以便后续进行消息发送、连接关闭等操作。
消息分发
- 读取消息:
static void read_cb(struct bufferevent *bev, void *ctx) { char buf[1024]; size_t len = bufferevent_read(bev, buf, sizeof(buf)); if (len > 0) { buf[len] = '\0'; // 解析消息类型,进行分发 // 例如: if (strncmp(buf, "LOGIN", 5) == 0) { handle_login(bev, buf + 5); } else if (strncmp(buf, "CHAT", 4) == 0) { handle_chat(bev, buf + 4); } } }
- 分发到业务逻辑:根据消息类型调用相应的业务逻辑处理函数,如
handle_login
、handle_chat
等。这些函数负责具体的业务处理,如用户认证、消息转发等。
异常处理
- 连接异常:
static void error_cb(struct bufferevent *bev, short what, void *ctx) { if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { // 连接关闭或发生错误,从连接管理模块中移除该连接 // 例如: remove_connection(bev); bufferevent_free(bev); } }
- 消息格式错误:在消息解析过程中,如果发现消息格式不符合预期,向客户端发送错误消息,并关闭连接。例如:
void handle_invalid_message(struct bufferevent *bev) { bufferevent_write(bev, "ERROR: INVALID MESSAGE FORMAT", 26); bufferevent_free(bev); }