多个连接套接字c ++

Posted

技术标签:

【中文标题】多个连接套接字c ++【英文标题】:Multiple connections sockets c++ 【发布时间】:2018-01-01 21:19:01 【问题描述】:

我正在尝试实现自己的服务器和客户端,它们使用套接字来发送和接收数据。但是我在实现多线程方面遇到了一些问题。 我的 server.cpp

#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <thread>
using namespace std;

void connection_handler(int socket) 
    char client_message[256];
    memset(&client_message, 0, 256);
    size_t message_size = 0;

    while ((message_size = recv(socket, client_message, sizeof(client_message) - 1, 0)) > 0) 
        client_message[message_size] = '\0';
        cout << "[Server] Client message accepted" << endl;
        cout << "[Server] Client message: " << client_message << endl;

        if (write(socket, client_message, message_size) == -1) 
            cout << "[Client] Message sending failed" << endl;
            return;
        
        cout << "[Server] Message sent to client" << endl << endl;
        cout << "============================" << endl << endl;
        cout.flush();

        memset(&client_message, 0, 256);
    


int main() 
    unsigned short int PORT = 8080;
    int listener, client_socket;
    socklen_t client_len;

    struct sockaddr_in server_address;

    memset(&server_address, 0, sizeof(server_address));

    listener = socket(AF_INET, SOCK_STREAM, 0);

    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(PORT);
    if (inet_aton("127.0.0.1", &server_address.sin_addr) == 0) 
        cout << "[Server] Invalid IP address" << endl;
        return -1;
    

    if (bind(listener, (struct sockaddr*) &server_address, sizeof(server_address)) == -1) 
        cout << "[Server] Binding failed" << endl;
        return -1;
    
    cout << "[Server] All setting are done" << endl;
    cout << "[Server] Server enabled" << endl;

    if (listen(listener, 100) == -1) 
        cout << "[Server] Listening failed" << endl;
        return -1;
    
    cout << "[Server] Waiting for connection..." << endl;

    for (; ;) 
        client_socket = accept(listener, (struct sockaddr*) &server_address, &client_len);
        cout << "[Server] Connection accepted" << endl << endl;
        cout << "----------------------------" << endl << endl;

        int new_socket = client_socket;

        thread handling_thread(connection_handler, new_socket);
        handling_thread.detach();
    

我的client.cpp

#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;

int main() 
    unsigned short int PORT = 8080;
    int sockfd;
    char buffer[256] = 0;
    struct sockaddr_in server_address;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&server_address, '0', sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(PORT);
    server_address.sin_addr.s_addr = INADDR_ANY;

    if (connect(sockfd, (struct sockaddr*) &server_address, sizeof(server_address)) < 0) 
        cout << "[Client] Connection failed" << endl;
        return -1;
    
    cout << "[Client] All setting are done" << endl;
    cout << "[Client] Succefully connected to server" << endl << endl;
    cout << "----------------------------" << endl << endl;

    while (true) 
        string client_request;
        cout << "[Client] Enter a message: ";
        getline(cin, client_request);

        if (client_request == "-1") 
            write(sockfd, client_request.c_str(), client_request.size());
            close(sockfd);
            cout << endl << "[Client] Client exited" << endl;
            return 0;
        

        if (write(sockfd, client_request.c_str(), client_request.size()) == -1) 
            cout << "[Client] Message sending failed" << endl;
        
        cout << "[Client] Message sent to server" << endl;

        memset(&buffer, 0, 256);
        read(sockfd, buffer, 256);

        cout << "[Client] Server message: " << buffer << endl << endl;
        cout << "============================" << endl << endl;
        cout.flush();
    

在我再创建一个与服务器的连接之后,它可以正常工作,然后第二个客户端可以发送和接收数据,但此时第一个客户端无法正常工作。 我像这样编译我的程序:g++ server.cpp -lpthread -o server -std=c++11 然后在其他控制台选项卡中运行我编译的 client.cpp:./client。 为了检查多线程工作,我再次运行客户端(再次在另一个选项卡中)并尝试同时在两个选项卡中发送请求。 我想在我的程序中实现多线程。我该怎么做?

UPD:我正在使用 Linux

UPD2:问题已解决。修复了那里的代码。

【问题讨论】:

new_socketfor 循环的局部变量,因此线程持有的指针在线程使用它时将指向垃圾区,这真是太奇怪了。快速修复:按值传递,而不是作为指针传递。还要查看 selectepoll 或重叠 IO,具体取决于您的目标操作系统。 如果 message_size = recv(*socket, client_message, 256, 0) 读取 256 个字节,可能不相关的 client_message[message_size] = '\0'; 将刺穿 char client_message[256]; 并具有未定义的行为。试试message_size = recv(*socket, client_message, sizeof(client_message)-1, 0)吧。 @user4581301 哦,天哪.. 你的第一个提示对我有帮助,现在它工作得很好。非常感谢你:) 这里是一个使用 select 来处理只有一个线程的多个连接的示例:gnu.org/software/libc/manual/html_node/Server-Example.html 【参考方案1】:
    int new_socket = client_socket;

    thread handling_thread(connection_handler, &new_socket);
    handling_thread.detach();

这将初始化new_socket,它在此for循环内的本地范围内声明,然后将指向此new_socket的指针传递给一个新线程,该线程开始启动并分离。紧接着,这个for 循环迭代结束,这会破坏new_socket 对象,然后再开始这个循环的下一次迭代。

同时,执行线程反复尝试取消引用它收到的int *,它现在指向一个已销毁的对象。这会导致未定义的行为,并且可能是您的程序“不工作”的原因。

最简单的解决方案是在动态范围内创建int 套接字值,使用new,然后将指向这个newed 套接字值的指针传递给执行线程。当然,执行线程将负责检索套接字值,然后正确地deleteing 它,以避免内存泄漏。

这对于这个简单的程序应该足够了。为了可靠性,更复杂的程序可能需要稍微复杂的套接字和动态范围处理逻辑。

【讨论】:

哪种方式最好?在堆栈或堆中创建新套接字?现在我的程序运行良好,谢谢 在这种情况下,堆上是最简单的方法。它仍然可以完全在堆栈上完成(自动范围),但它需要一些工作 - 使用互斥锁和条件变量,父线程等待直到新线程将套接字值复制到自己的堆栈,然后发信号通知父线程继续。 new, delete ? - 为什么不简单地按值传递套接字整数? - 我想你已经想到了POSIX Threads C 接口,你不能(正确)将int 转换为void *,以便人们使用分配/解除分配方法将指针传递给线程

以上是关于多个连接套接字c ++的主要内容,如果未能解决你的问题,请参考以下文章

同一端口套接字C ++上的多个连接

一个端口上的多个连接

我可以将同一个套接字用于多个连接吗?

具有多个连接的 C++ 服务器套接字

C 套接字:客户端之间的 connect() 和/或 accept() 存在问题。 111:连接被拒绝

C |套接字未正确关闭