在阻塞模型中,先使用select读有数据,SSL连接没有关闭,在使用ssl_read读取数据返回-1。错误原因,优化代码举例
时间: 2024-02-21 20:56:32 浏览: 288
在阻塞模型中,如果select读取有数据的socket,但是在使用ssl_read读取数据时返回-1,可能是由于以下原因之一:
1. SSL连接在读取之前已经关闭。可以使用SSL_get_shutdown函数检查SSL连接的状态,如果返回非零值,则SSL连接已经关闭。
2. SSL连接遇到了不可恢复的错误。可以通过调用SSL_get_error函数来获取错误代码,根据不同的错误代码采取不同的处理方式。
为了优化代码,可以在ssl_read调用之前检查SSL连接的状态,例如使用SSL_get_shutdown函数。如果SSL连接已经关闭,则不应该再使用ssl_read读取数据。另外,可以使用SSL_CTX_set_mode设置SSL_MODE_AUTO_RETRY模式,这将自动重试SSL_read遇到可恢复错误的情况,避免了一些重复代码。例如:
```c
int ret;
do {
ret = SSL_read(ssl, buf, len);
} while (ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_WANT_READ);
```
这将在遇到SSL_ERROR_WANT_READ错误时自动重试SSL_read。如果有其他错误,则退出循环并进行适当的错误处理。
相关问题
在阻塞模型中,先使用select读有数据,SSL连接没有关闭,在使用ssl_read读取数据返回-1。ssl_pending优化代码举例
在阻塞模型中,如果select读取有数据的socket,但是在使用ssl_read读取数据时返回-1,可以使用SSL_pending函数来检查SSL连接中是否有数据可供读取。如果SSL_pending返回大于0的值,则可以使用SSL_read函数来读取剩余的数据。例如:
```c
int ret;
while ((ret = SSL_read(ssl, buf, len)) <= 0) {
if (SSL_get_error(ssl, ret) == SSL_ERROR_WANT_READ) {
/* 等待更多数据可用 */
continue;
}
if (SSL_pending(ssl) > 0) {
/* 读取剩余的数据 */
ret = SSL_read(ssl, buf, len);
break;
}
/* 处理其他错误 */
break;
}
```
这里使用了一个循环,如果SSL_read返回SSL_ERROR_WANT_READ错误,则继续等待更多的数据可用。如果SSL_pending返回大于0的值,则读取剩余的数据。如果有其他错误,则退出循环并进行适当的错误处理。
在阻塞模型中,select读有数据,ssl_read读取数据返回-1。优化代码
在阻塞模型中,如果select读有数据,但是ssl_read读取数据返回-1,可能是由于SSL协议错误、网络故障或者代码逻辑错误等原因导致的。针对这种情况,你可以尝试以下优化代码:
1. 在调用ssl_read之前,先检查SSL握手状态,确保握手已经成功完成,否则重新进行握手。
2. 在调用ssl_read之前,先检查SSL会话是否过期,如果过期,可以考虑重新建立SSL会话。
3. 在调用ssl_read之前,先检查网络连接状态,如果连接已经中断,可以考虑进行重连或者其他网络故障处理操作。
4. 如果ssl_read返回-1并且errno为EAGAIN或EWOULDBLOCK,则可以再次调用select等待数据可读,直到ssl_read返回正确的数据或者出现其他错误。
5. 在代码中加入错误处理代码,避免出现逻辑错误。同时,可以加入日志记录功能,便于排查问题。
示例代码:
```
// SSL握手
if (SSL_do_handshake(ssl) != 1) {
int err = SSL_get_error(ssl, ret);
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
// 握手未完成,等待下一次循环
continue;
} else {
// 握手失败,关闭连接
close(fd);
return -1;
}
}
// 检查SSL会话是否过期
if (SSL_session_reused(ssl) == 0) {
// SSL会话过期,重新建立SSL会话
SSL_set_session(ssl, NULL);
SSL_set_fd(ssl, fd);
if (SSL_connect(ssl) != 1) {
close(fd);
return -1;
}
}
// 检查网络连接状态
if (select(fd + 1, &readfds, NULL, NULL, &tv) <= 0) {
// 连接中断,重连或其他处理
close(fd);
return -1;
}
// 读取数据
int nread = 0;
while ((nread = SSL_read(ssl, buf, len)) <= 0) {
int err = SSL_get_error(ssl, nread);
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
// 数据未准备好,等待下一次循环
if (select(fd + 1, &readfds, NULL, NULL, &tv) <= 0) {
// 连接中断,重连或其他处理
close(fd);
return -1;
}
continue;
} else {
// 其他错误,退出循环
break;
}
}
// 处理读到的数据
// ...
```
需要注意的是,在循环读取数据时,应该加入超时机制,避免一直等待数据可读而导致程序阻塞。可以通过设置select的超时时间或者使用定时器来实现超时机制。
阅读全文