c++ - OpenSSL 套接字 : Select always returns 0

标签 c++ sockets select openssl server

我做了一个带有阻塞套接字的小套接字回显服务器(见下面的代码),但是即使有消息要读取,select 语句也总是返回 0。其他一切都有效。如果您通过简单地将 1 分配给 selectResult 来替换 select 语句,则服务器可以正常工作。

服务器在虚拟机中的 Ubuntu 上运行,而客户端在主机系统(Windows 7 专业版)上。我的服务器 IDE 是 Eclipse 3.8,它使用 OpenSSL 1.0.1j。

要使此代码正常工作,您只需包含 OpenSSL 的根目录,将其库路径添加到链接器并链接到 ssl、crypto 和 dl(按此顺序)。您还需要证书和私钥。

提前致谢!

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>

using namespace std;
#define MAX_BUFFER 1024

int main()
{
    // Initializing...
    SSL_CTX*_ctx = NULL;
    SSL* _ssl = NULL;
    fd_set _fdSet;
    int _serverSocket = 0;
    int _port = 9090;
    timeval t;
    const char* certPath = "/home/alex/Certificate/cacert.pem";
    const char* pKeyPath = "/home/alex/Certificate/privkey.pem";

    // Init OpenSSL
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
    _ctx = SSL_CTX_new(TLSv1_1_server_method());
    if (_ctx == NULL)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

    // Set certificate and private key.
    if (SSL_CTX_use_certificate_file(_ctx, certPath, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    if (SSL_CTX_use_PrivateKey_file(_ctx, pKeyPath, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    if (!SSL_CTX_check_private_key(_ctx))
    {
        fprintf(stderr, "Private key does not match the public certificate\n");
        abort();
    }

    // Initialize server socket:
    // 1. set address
    struct sockaddr_in addr;
    int optval = 1;
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(_port);
    addr.sin_addr.s_addr = INADDR_ANY;

    // 2. init socket, set socket options, bind it to address
    _serverSocket = socket(PF_INET, SOCK_STREAM, 0);
    setsockopt(_serverSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if (bind(_serverSocket, (struct sockaddr*) &addr, sizeof(addr)) != 0)
    {
        perror("can't bind port");
        abort();
    }
    // 3. Prepare the socket to accept connections
    if (listen(_serverSocket, 1) != 0)
    {
        perror("Can't configure listening port");
        abort();
    }
    cout << "Server finished initializing." << endl;

    bool bServerStayAlive = true;
    while (bServerStayAlive)
    {
        cout << "Waiting for connection..." << endl;
        struct sockaddr_in addr;
        unsigned int len = sizeof(addr);
        int client = accept(_serverSocket, (struct sockaddr*) &addr, &len);

        printf("Connection: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        _ssl = SSL_new(_ctx);
        SSL_set_fd(_ssl, client);
        if (SSL_accept(_ssl) == -1) /* do SSL-protocol accept */
            ERR_print_errors_fp(stderr);
        else
        {
            while (bServerStayAlive)
            {
                FD_ZERO(&_fdSet);
                FD_SET(_serverSocket, &_fdSet);
                t.tv_sec = 1;
                t.tv_usec = 0;
                int selectResult = select(_serverSocket + 1, &_fdSet, NULL, NULL, &t);
                if (selectResult == 0)
                {
                    cout << "timeout" << endl;
                    continue;
                }
                if (selectResult < 0)
                {
                    cout << "Select error: " << selectResult << endl;
                    bServerStayAlive = false;
                    break;
                }

                cout << "Going to read something\n";
                unsigned char buffer[MAX_BUFFER];
                memset(buffer, 0, MAX_BUFFER);
                int bytes = SSL_read(_ssl, buffer, MAX_BUFFER); /* get request */
                if (bytes > 0)
                {
                    cout << "Received message: " << endl;
                    for (int i = 0; i < bytes; i++)
                        cout << buffer[i];
                    cout << endl;
                    SSL_write(_ssl, buffer, bytes);
                }
                else
                {
                    ERR_print_errors_fp(stderr);
                    break;
                }
            }
        }
        int sd = SSL_get_fd(_ssl); /* get socket connection */
        SSL_free(_ssl); /* release SSL state */
        close(sd); /* close connection */
        cout << "Connection was closed.\n";
    }
    // Uninitializing
    close(_serverSocket);
    SSL_CTX_free(_ctx);
    return 0;
}

最佳答案

我想你的意思是选择你刚刚接受的 client 套接字,而不是你接受连接的 _serverSocket

关于c++ - OpenSSL 套接字 : Select always returns 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30483945/

相关文章:

java - 未抛出 SocketTimeoutException

c# - <select> 标记多个属性使用 runat=server | 引发解析器错误类型为 'System.Boolean' 的对象

postgresql - 字段值以结尾的 Postgres SELECT 语句

c# - 如何在 ASP.NET 中按类而不是 ID 选择元素?

c++ - 取消引用字符串数组元素 c

c - 在 C 中启动并初始化新的 char 数组后变量发生更改

node.js - 使用Node.js套接字代码提交的FTP命令未处理

c++ - 除非通过引用传递,否则字符串类型无法正常工作

c++ - 在 C++ 中读取由 Java + 结构对齐打开的套接字

c++ - 我可以捆绑两个 MPI 消息吗?