当 HTTP 服务器完成发送信息时,即使服务器完成发送数据,SSL_read 函数也会陷入等待响应的状态。
我尝试使用 SSL 默认错误处理来检查错误,但这不起作用,因为没有错误,它只是等待响应。我尝试过使套接字成为非阻塞,但它不适用于 SSL 套接字,并且在网上找不到任何有关它的信息。我正在使用winsock2。
问题出在这里:
do {
bytesRead = SSL_read(ssl, buffer, sizeof(buffer) - 1);
buffer[bytesRead] = '\0';
printf("%s\n", buffer);
sscanf_s(buffer, "HTTP/1.%*d %d", &statusCode);
} while (bytesRead > 0);
这是完整的代码,稍作编辑:
int xxx() {
WSADATA wsaData;
SSL_CTX* sslContext = NULL;
char* httpRequest = "just the request, not important"
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Failed to initialize Winsock.\n");
return -1;
}
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
sslContext = SSL_CTX_new(TLS_client_method());
SOCKET socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketClient == INVALID_SOCKET)
{
printf("Failed to create socket.\n");
closesocket(socketClient);
WSACleanup();
return -1;
}
struct addrinfo* result = NULL;
if (getaddrinfo("example.com", "https", NULL, &result) != 0)
{
printf("Failed to resolve hostname.\n");
closesocket(socketClient);
WSACleanup();
return -1;
}
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = ((struct sockaddr_in*)result->ai_addr)->sin_addr.s_addr;
serverAddr.sin_port = htons(443);
freeaddrinfo(result);
if (connect(socketClient, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
printf("Failed to connect to server.\n");
closesocket(socketClient);
WSACleanup();
return -1;
}
SSL* ssl = SSL_new(sslContext);
SSL_set_fd(ssl, socketClient);
if (SSL_connect(ssl) != 1) {
printf("SSL handshake failed.\n");
SSL_free(ssl);
closesocket(socketClient);
WSACleanup();
return -1;
}
if (SSL_write(ssl, httpRequest, strlen(httpRequest)) <= 0) {
printf("Failed to send HTTP request.\n");
SSL_free(ssl);
closesocket(socketClient);
WSACleanup();
return -1;
}
char buffer[4096];
int bytesRead = 0;
int statusCode = 0;
do {
bytesRead = SSL_read(ssl, buffer, sizeof(buffer) - 1);
buffer[bytesRead] = '\0';
sscanf_s(buffer, "HTTP/1.%*d %d", &statusCode);
} while (bytesRead > 0);
SSL_shutdown(ssl);
SSL_free(ssl);
closesocket(socketClient);
WSACleanup();
}
阻塞套接字上的 SSL_read 将阻塞,直到底层 TCP 连接关闭、SSL 会话关闭 (SSL_shutdown) 或发生错误。当“服务器完成发送数据”时它不会关闭,因为服务器完成时套接字或 SSL 会话不知道。
使用 HTTP,客户端可以在响应完成后要求服务器关闭连接,同时添加
Connection: close
标头。但请注意,目前 HTTP 请求已完全损坏,与 HTTP 协议完全不同。