【发布时间】:2021-03-09 20:43:09
【问题描述】:
这是一个基于 echoServer 的 libevent,经过我的一些调整(非常小)。
问题是,再次运行客户端模拟时,它似乎卡住了。客户端是这样做的:它打开一个到这个服务器的 TCP 连接,发送一个小数据(大约 20B)并等待回复,然后它关闭与 TCP RST 的连接,然后重复。
经过数千次(有时约为 20000 次)迭代后,客户端停止了。 Wireshark 监听 loopback 接口显示,当它停止时,最后一个 TCP 会话有数据从客户端发送,但服务器没有回显/发送回客户端,导致客户端挂起。
有什么想法吗?提前致谢!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <netinet/tcp.h>
#include <event.h>
#include <event2/listener.h>
#include <event2/bufferevent_ssl.h>
struct event_base *base;
static void echo_read_cb(struct bufferevent *bev, void *ctx) {
/* This callback is invoked when there is data to read on bev. */
struct evbuffer *input = bufferevent_get_input(bev);
struct evbuffer *output = bufferevent_get_output(bev);
/* Copy all the data from the input buffer to the output buffer. */
int ret = evbuffer_add_buffer(output, input);
if (ret) {
printf("error happened when adding buf\n");
}
}
static void echo_event_cb(struct bufferevent *bev, short events, void *ctx) {
if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
int fd = bufferevent_getfd(bev);
evutil_closesocket(fd);
bufferevent_free(bev);
return;
}
}
static void accept_error_cb(struct evconnlistener *listener, void *ctx) {
struct event_base *base = evconnlistener_get_base(listener);
int err = EVUTIL_SOCKET_ERROR();
fprintf(stderr, "Got an error %d (%s) on the listener. "
"Shutting down.\n", err, evutil_socket_error_to_string(err));
}
static void accept_conn_cb(struct evconnlistener *serv, int sock, struct sockaddr *sa,
int sa_len, void *arg) {
struct bufferevent *bev = bufferevent_socket_new(
base, sock, BEV_OPT_CLOSE_ON_FREE);
int flag = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);
bufferevent_enable(bev, EV_READ|EV_WRITE);
}
int main(int argc, char **argv) {
struct evconnlistener *listener;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(9999);
sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
base = event_base_new();
listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
(struct sockaddr*)&sin, sizeof(sin));
if (!listener) {
perror("Couldn't create listener");
return 1;
}
evconnlistener_set_error_cb(listener, accept_error_cb);
event_base_loop(base, 0);
evconnlistener_free(listener);
return 0;
}
【问题讨论】:
-
所有临时端口卡在TIME_WAIT?
-
所有已完成的会话都以客户端发送 TCP RESET 结束。对于卡住的会话,根据wireshark的说法,TCP握手完成后,客户端将数据发送到服务器,但服务器没有将数据发送回客户端(应该回显)。在
echo_read_cb上添加了一些工具,结果服务器端认为客户端数据不是为卡住的会话而来的。我很迷惑。也许 libevent 内部的某些东西阻止了回调函数echo_read_cb的触发。 ???
标签: c linux sockets networking