OpenSSL套接字:选择始终返回0

时间:2015-05-27 13:28:53

标签: c++ sockets select openssl server

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

服务器在VM中的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;
}

1 个答案:

答案 0 :(得分:2)

我认为您打算选择刚接受的client套接字,而不是您接受连接的_serverSocket