我有一个TCP网络库,它实现了一堆协议(redis,http等),它们是使用BSD套接字实现的。
许多代码使用select()和其他适用于BSD套接字的函数。我是否正确地认为这不适用于SSL套接字?或者他们会按原样工作吗?
我只是想知道SSL和BSD套接字是否如此不同,以至于它们需要一种完全不同的实现方法。
答案 0 :(得分:6)
假设您指的是OpenSSL,它位于套接字的顶部,它不会替换它。所以所有直接套接字操作,如select()
,仍然有效。但是,不同之处在于OpenSSL会为您处理读写操作,因此您可以将recv()
替换为ssl_read()
,将send()
替换为ssl_write()
,但您可以(在某些情况下)需要)仍然直接使用select()
。但是,您不能随时调用它,您必须等到OpenSSL告诉您调用它。因此,例如,如果您有一个首先调用select()
然后仅在recv()
报告可读性时调用select()
的阅读循环,则必须交换该逻辑。首先致电ssl_read()
,然后仅在select
返回ssl_read()
或SSL_ERROR_WANT_READ
时调用SSL_ERROR_WANT_WRITE
()(请注意ssl_read()
可执行写入操作在内部,ssl_write()
可以在内部执行读取操作。
答案 1 :(得分:2)
有一件事是你不应该对运行ssl连接的fd做一个选择。那是因为它可能会说你可以在ssl_read阻塞时读取它。然后由例如SSL执行密钥重新协商而不是应用程序数据变得可用。那是陷阱之一。
答案 2 :(得分:0)
这可能会迟到,但可能会为未来的用户提供很好的参考。在url http://developerweb.net/viewtopic.php?id=6824上使用select()函数有一个很好的主题。引用的一个例子如下
int sslsock_handle_nbio (ssl, ret, totv)
void *ssl; /* -> the SSL info */
int ret; /* the SSL I/O function return value */
struct timeval *totv; /* -> timeout info, or NULL */
{
int sfd, i;
fd_set rset, wset;
sfd = SSL_get_fd (ssl);
i = SSL_get_error (ssl, ret);
if (i == SSL_ERROR_WANT_READ) {
do {
FD_ZERO (&rset);
FD_SET (sfd, &rset);
i = select (sfd + 1, &rset, NULL, NULL, totv);
} while ((i < 0) && (errno == EINTR));
if (i == 0) {
/* the select() timed out */
ret = -2;
errno = ETIMEDOUT;
} else {
/* either an error, or it's readable */
ret = i;
}
} else if (i == SSL_ERROR_WANT_WRITE) {
do {
FD_ZERO (&wset);
FD_SET (sfd, &wset);
i = select (sfd + 1, NULL, &wset, NULL, totv);
} while ((i < 0) && (errno == EINTR));
if (i == 0) {
/* the select() timed out */
ret = -2;
errno = ETIMEDOUT;
} else {
/* either an error, or it's writable */
ret = i;
}
}
/* else, leave "ret" alone, and return it as-is */
return (ret);
}
仅在执行SSL_read()
或SSL_write()
之后才会这样做。