当前位置: 首页 > 知识库问答 >
问题:

OpenSSL套接字:选择总是返回0

胡元忠
2023-03-14

我制作了一个带有阻塞套接字的小型套接字echo服务器(请参见下面的代码),但是select语句始终返回0,即使有消息要读取。其他的都管用。如果通过简单地将1赋给SelectResult来替换select语句,则服务器可以工作。

服务器在虚拟机中运行在Ubuntu上,而客户端在主机系统上(Windows7 professional)。我的服务器IDE是Eclipse3.8,它使用OpenSSL1.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个答案

谭勇
2023-03-14

我想您应该选择刚刚接受的客户端套接字,而不是接受连接的_serversocket

 类似资料:
  • 目标16061根3R FIFO 0,8 0T0 153467管道 目标16061根4U IPv4 153470 0T0 UDP*:3290 目标16061根5U sock 0,6 0T0 153471无法识别协议 目标16061根6U IPv4 153472 0T0 TCP*:3290(LISTEN) 目标16061根7U raw 0t0 153473 00000000:0001->0000000

  • 问题内容: 在Node.js中使用Mongoose,您可以使用find返回一些字段。例如。 但我似乎无法弄清楚如何使用findOneAndUpdate返回某些字段。 有人做到过吗?我在文档中找不到它。 问题答案: 从说明书,该参数需要一个关键的它,因为还有其他的细节,比如和地方适用。您 还 需要以下选项: 您也可以使用 请注意,没有返回的文档处于处理更新修改 之前 的状态。有时候这就是您的意思,但

  • 在TCP套接字代码中,我们创建了2个套接字。第一个接收新连接,第二个接收来自客户端的数据,并在建立新连接时创建。 TCP报头中的什么控制位允许服务器知道是将此段传递给ServerSocket(连接请求被发送到的那个)还是Socket(连接建立后为通信而创建的Socket)?

  • 问题内容: 关于Java中的serversockets,我已经看到了许多与此答案相似的答案:“假设您有一台服务器,其serversocket的端口为5000。客户端A和客户端B将连接到我们的服务器。 客户端A在端口5000上向服务器发送请求。客户端A侧的端口由操作系统选择。通常,操作系统会选择下一个可用的端口。该搜索的起点是先前使用的端口号+ 1(例如,如果操作系统最近碰到了我们的端口45546,

  • 客户端IP:客户端端口和服务器IP:服务器端口->协议(以区分TCP和UDP) 那么为什么accept()需要返回绑定到不同端口的套接字呢?每个报头中发送的四组信息是否足以区分来自不同机器的到同一服务器端口的多个连接,从而不需要使用服务器机器上的不同端口进行通信?

  • http://prntscr.com/9jhrwa“GUI看起来怎么样” 公共类Okno1扩展javax.swing.jFrame{ 在这里,我显示了按下这个按钮时的jScrollPanel,我还显示了如果我想在显示的JList中获得选定元素的索引时必须按下的按钮 在这里,我按下一个按钮,它应该为我提供所选项的索引,但它一直给我-1,无论JList上的项是否被选中都无关紧要