网站建设交接表,wordpress主题 免费 自媒体,网站建设的发展趋势,php微信微网站怎么做文章目录 当客户端关闭后#xff0c;Epoll 的 TCP socket 服务端会收到两次断开事件可能有以下原因及解决方法#xff1a;原因分析解决方法 问题ssl socket服务端代码出错现象第一次尝试修改正确改法附上客户端代码 记录ssl epoll的tcp socket服务端在客户端断开时接收到多次… 文章目录 当客户端关闭后Epoll 的 TCP socket 服务端会收到两次断开事件可能有以下原因及解决方法原因分析解决方法 问题ssl socket服务端代码出错现象第一次尝试修改正确改法附上客户端代码 记录ssl epoll的tcp socket服务端在客户端断开时接收到多次disconnect事件导致崩溃的问题. 流程:在linux服务器上跑socke服务, 客户端连接后发送数据,服务端回复, 客户端接收到回复后关闭. 当客户端关闭后Epoll 的 TCP socket 服务端会收到两次断开事件可能有以下原因及解决方法
原因分析
网络延迟或数据包重传 网络环境不稳定可能导致数据包延迟到达或重传。当客户端关闭连接时发送的断开信号可能由于网络延迟在服务端被接收多次。 这种情况下服务端可能会误认为有多个断开事件发生。服务端处理逻辑问题 服务端在处理断开事件时如果没有正确地标记已处理的事件或者没有及时清理相关资源可能会导致后续再次触发相同的断开事件。 例如在处理第一个断开事件后服务端可能没有将对应的文件描述符从 Epoll 实例中移除导致下一次轮询时再次触发该事件。SSL 层的影响 如果使用了 SSL 加密SSL 层的关闭过程可能会与底层的 TCP 连接关闭产生交互问题导致服务端收到多次断开事件。 SSL 的关闭握手过程可能会产生额外的数据包被服务端误认为是新的断开事件。
解决方法
处理网络问题 可以通过优化网络环境、增加超时时间等方式来减少网络延迟和数据包重传的影响。 对于关键的应用可以考虑使用更稳定的网络连接或者采用网络冗余技术。优化服务端处理逻辑 在服务端处理断开事件时确保正确地标记已处理的事件并及时清理相关资源。 例如在处理断开事件后立即将对应的文件描述符从 Epoll 实例中移除避免再次触发相同的事件。
问题ssl socket服务端代码
这段代码是用AI工具自动生成的, 拿来调试后发现有问题
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include sys/socket.h
#include sys/epoll.h
#include netinet/in.h
#include openssl/ssl.h
#include openssl/err.h#define MAX_EVENTS 10
#define BUFFER_SIZE 1024void handle_error(const char* msg) {perror(msg);exit(EXIT_FAILURE);
}SSL_CTX* init_ssl_context() {SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();SSL_CTX* ctx SSL_CTX_new(TLS_server_method());if (!ctx) {ERR_print_errors_fp(stderr);exit(EXIT_FAILURE);}if (SSL_CTX_use_certificate_file(ctx, server.crt, SSL_FILETYPE_PEM) 0) {ERR_print_errors_fp(stderr);exit(EXIT_FAILURE);}if (SSL_CTX_use_PrivateKey_file(ctx, server.key, SSL_FILETYPE_PEM) 0) {ERR_print_errors_fp(stderr);exit(EXIT_FAILURE);}return ctx;
}void handle_client(SSL* ssl, int epollfd, int client_socket) {char buffer[BUFFER_SIZE];int bytes_read SSL_read(ssl, buffer, BUFFER_SIZE - 1);if (bytes_read 0) {buffer[bytes_read] \0;printf(Received: %s, buffer);SSL_write(ssl, buffer, bytes_read);} else {if (bytes_read 0) {printf(Connection closed by client\n);} else {ERR_print_errors_fp(stderr);}close(client_socket);SSL_shutdown(ssl);SSL_free(ssl);epoll_ctl(epollfd, EPOLL_CTL_DEL, client_socket, NULL);}
}int main() {int server_socket, client_socket;struct sockaddr_in server_addr, client_addr;socklen_t client_addr_len sizeof(client_addr);SSL_CTX* ssl_ctx init_ssl_context();server_socket socket(AF_INET, SOCK_STREAM, 0);if (server_socket -1) {handle_error(socket);}memset(server_addr, 0, sizeof(server_addr));server_addr.sin_family AF_INET;server_addr.sin_addr.s_addr INADDR_ANY;server_addr.sin_port htons(12345);if (bind(server_socket, (struct sockaddr*)server_addr, sizeof(server_addr)) -1) {handle_error(bind);}if (listen(server_socket, 10) -1) {handle_error(listen);}int epollfd epoll_create1(0);if (epollfd -1) {handle_error(epoll_create1);}struct epoll_event event;event.events EPOLLIN;event.data.fd server_socket;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, server_socket, event) -1) {handle_error(epoll_ctl);}printf(EPOLL_CTL_ADD:%d\n, server_socket);struct epoll_event events[MAX_EVENTS];while (1) {int nfds epoll_wait(epollfd, events, MAX_EVENTS, -1);if (nfds -1) {handle_error(epoll_wait);}for (int i 0; i nfds; i) {if (events[i].data.fd server_socket) {client_socket accept(server_socket, (struct sockaddr*)client_addr, client_addr_len);if (client_socket -1) {handle_error(accept);}SSL* ssl SSL_new(ssl_ctx);SSL_set_fd(ssl, client_socket);if (SSL_accept(ssl) 0) {ERR_print_errors_fp(stderr);close(client_socket);continue;}event.events EPOLLIN;event.data.ptr ssl; // 重点是这两行, 后面会分析//event.data.fd client_socket;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, client_socket, event) -1) {handle_error(epoll_ctl);}printf(New client connected, EPOLL_CTL_ADD:%d, ssl:%p\n, client_socket, ssl);} else {// 这里用了data.ptr 与data.fdSSL* ssl (SSL*)events[i].data.ptr;printf(data fd:%d ssl:%p\n, events[i].data.fd, ssl);handle_client(ssl, epollfd, events[i].data.fd);}}}close(server_socket);SSL_CTX_free(ssl_ctx);return 0;
}出错现象
EPOLL_CTL_ADD:3
New client connected, EPOLL_CTL_ADD:5
Received: 1
Connection closed by client
Connection closed by client
段错误 (核心已转储)
经过调试发现,每次客户端close后,服务端会接收到两次的disconnect事件, 导致重复关闭从而崩溃.
第一次尝试修改
handle_client(SSL* ssl, int epollfd, int client_socket)中会调用close(client_socket), 发现client_socket值没传. event.data.ptr ssl; // 重点是这两行, 后面会分析event.data.fd client_socket;// 把这行注释打开,把client_socket传递到event中这么改后,还是会崩溃. 通过man查看event的结构体epoll_data原型, 发现data是union类型, ptr与fd不能同时赋值, 所以第一次改法失败. epoll_data结构如下 typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;} epoll_data_t;struct epoll_event {uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};正确改法
client_socket从ssl中获取,不需要额外传递, 如图, 左边是问题代码, 右边是改正过的代码
附上客户端代码
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include sys/socket.h
#include sys/epoll.h
#include netinet/in.h
#include openssl/ssl.h
#include openssl/err.h
#include arpa/inet.h#define BUFFER_SIZE 1024void handle_error(const char* msg) {perror(msg);exit(EXIT_FAILURE);
}SSL_CTX* init_ssl_context() {SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();SSL_CTX* ctx SSL_CTX_new(TLS_client_method());if (!ctx) {ERR_print_errors_fp(stderr);exit(EXIT_FAILURE);}return ctx;
}int main() {int client_socket;struct sockaddr_in server_addr;SSL_CTX* ssl_ctx init_ssl_context();client_socket socket(AF_INET, SOCK_STREAM, 0);if (client_socket -1) {handle_error(socket);}memset(server_addr, 0, sizeof(server_addr));server_addr.sin_family AF_INET;server_addr.sin_addr.s_addr inet_addr(127.0.0.1);server_addr.sin_port htons(12345);if (connect(client_socket, (struct sockaddr*)server_addr, sizeof(server_addr)) -1) {handle_error(connect);}SSL* ssl SSL_new(ssl_ctx);SSL_set_fd(ssl, client_socket);if (SSL_connect(ssl) 0) {ERR_print_errors_fp(stderr);close(client_socket);exit(EXIT_FAILURE);}char buffer[BUFFER_SIZE];printf(Enter a message to send to the server: );fgets(buffer, BUFFER_SIZE, stdin);SSL_write(ssl, buffer, strlen(buffer));int bytes_read SSL_read(ssl, buffer, BUFFER_SIZE - 1);if (bytes_read 0) {buffer[bytes_read] \0;printf(Received from server: %s, buffer);} else {ERR_print_errors_fp(stderr);}SSL_shutdown(ssl);SSL_free(ssl);close(client_socket);SSL_CTX_free(ssl_ctx);return 0;
}作者:帅得不敢出门 原创文章谢绝转载