gpt4 book ai didi

c - 非阻塞 BIO 并在 BIO_do_connect 后挂起

转载 作者:太空宇宙 更新时间:2023-11-03 12:52:28 27 4
gpt4 key购买 nike

我正在用 C 语言编写一个小型 IRC 机器人,使用 openssl 来启动安全套接字。它不是写得最漂亮的机器人,但它主要只是为了了解 openssl API 的工作原理。目前我有以下代码:

#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

int main() {
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();

BIO *bio;
SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());
SSL * ssl;

SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs/");
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, & ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
BIO_set_nbio(bio, 1);
BIO_set_conn_hostname(bio, "irc.freenode.net:6697");
BIO_do_connect(bio);

if(SSL_get_verify_result(ssl) != X509_V_OK) {
printf("error\n");
}

char irc1[] = "NICK bartender\r\n";
char irc2[] = "USER bartender * * :serve(&drinks);\r\n";

BIO_write(bio, irc1, strlen(irc1));
BIO_write(bio, irc2, strlen(irc2));

fd_set read_set;
int sock = BIO_get_fd(bio, NULL);

while(1) {
FD_ZERO(&read_set);
FD_SET(sock, &read_set);

struct timeval timeout = { 0, 0 };
select(sock+1, &read_set, NULL, NULL, &timeout);

if(FD_ISSET(sock, &read_set)) {
char buf[21];
size_t x = BIO_read(bio, buf, 20);

if(x == 0) {
continue;
} else if(x == -1){
int code = ERR_get_error();

if(code == 0) {
continue;
}

printf("(%d)%s\n", code, ERR_error_string(code, NULL));
} else {
buf[x] = '\0';
printf("%s", buf);
}
}
}
}

每当我编译并运行这段代码时,它就会挂起并且不打印任何内容。但是,如果我删除第 20 行(当前将套接字置于非阻塞模式),它就可以正常工作。为什么将套接字置于非阻塞模式会导致此行为?谢谢你,祝你有美好的一天!

最佳答案

Whenever I run this code, it just hangs and prints nothing. However, if I remove line 20 (which currently puts the socket into nonblocking mode) it works fine.

BIO_do_connect以非阻塞模式立即返回。你应该循环 BIO_should_retry .这是手册页必须说明的关于 BIO_do_connect 的内容:

BIO_do_connect() attempts to connect the supplied BIO. It returns 1 if the connection was established successfully. A zero or negative value is returned if the connection could not be established, the call BIO_should_retry() should be used for non blocking connect BIOs to determine if the call should be retried.


Why does putting the socket in non-blocking mode cause this behavior?

调用BIO_do_connect立即返回; socket/bio 可能还没有准备好接收数据。


BIO_do_connect 上循环的替代方法/BIO_should_retry是等待底层文件描述符。它是 OpenSSL 在 ocsp 中使用的技术子命令(源代码可以在 <openssl src>/apps/ocsp.c 中找到):

if (req_timeout != -1)
BIO_set_nbio(cbio, 1);

rv = BIO_do_connect(cbio);

if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
BIO_puts(err, "Error connecting BIO\n");
return NULL;
}

if (BIO_get_fd(cbio, &fd) < 0) {
BIO_puts(bio_err, "Can't get connection fd\n");
goto err;
}

if (req_timeout != -1 && rv <= 0) {
FD_ZERO(&confds);
openssl_fdset(fd, &confds);
tv.tv_usec = 0;
tv.tv_sec = req_timeout;
rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
if (rv == 0) {
BIO_puts(err, "Timeout on connect\n");
return NULL;
}
}

另见 Non-blocking BIO and BIO_do_connect problem在 OpenSSL 用户邮件列表中。还有一个 few hits on Stack Overflow ,但我不确定哪个最适合这个问题:

关于c - 非阻塞 BIO 并在 BIO_do_connect 后挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39058675/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com