Socket服务器以缓冲区大小接收数据

问题描述 投票:0回答:1

我一个接一个的发送不同大小的数据包,怎么能按我发送的大小分别接收,而不是累计在缓冲区里。现在服务器好像是把缓冲区加满为止,然后我就可以处理了。

举个例子。

缓冲区大小: 84.

从客户端发送:84字节,76字节,76字节,80字节。

在服务器中接收。84个字节,84个字节,84个字节,64个字节。

我想按我发送的内容接收。这可能吗?

    int port = stoi(getConfig("server_port"));
    std::string ipAddress = getConfig("ip_address");

    // Create a socket
    int listening = socket(AF_INET, SOCK_STREAM, 0);
    if (listening < 0){
        std::cerr << "Can't create a socket!" << endl;
        Logger("Can't create a socket!");
        exit(-1);
    }
    std::cout << "The socket server was created successfully." << endl;

    // Bind the socket to a IP / port
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(port);
    inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);

    if (bind(listening, (sockaddr*)&hint, sizeof(hint)) < 0){
        cerr << "Can't bind to IP/port!" << endl;
        Logger("Can't bind to IP/port!");
        exit(-1);
    }

    // Mark the socket for listening in
    if (listen(listening, SOMAXCONN) < 0){
        cerr << "Can't listen!" << endl;
        Logger("Can't listen!");
        exit(-1);
    }

    // Accept a call
    sockaddr_in client;
    socklen_t clientSize = sizeof(client);
    char host[NI_MAXHOST];
    char svc[NI_MAXSERV];

    while(true){
        int clientSoket = accept(listening, (sockaddr*)&client, &clientSize);
        if(clientSoket < 0){
            cerr << "Problem with client connecting!" << endl;
            Logger("Problem with client connecting!");
            break;
        }
        cout << "The client whas conected successfully." << endl;

        memset(host, 0, NI_MAXHOST);
        memset(svc, 0, NI_MAXSERV);

        int result = getnameinfo((sockaddr*)&client, clientSize, host, NI_MAXHOST, svc, NI_MAXSERV, 0);
        if(result == 0) {
            cout << host << " connected on " << svc << endl;
        } else {
            inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
            cout << host << " connected on " << ntohs(client.sin_port) << endl;
        }

        // While receiving
        char buff[84];
        while(true){
            // Clear the buffer
            memset(buff, 0, sizeof(buff));

            // Wait for a message
            int bytesRecv = recv(clientSoket, buff, sizeof(buff), 0);
            if(bytesRecv < 0){
                cerr << "There was a connection issue!" << endl;
                Logger("There was a connection issue!");
                break;
            }

            if(bytesRecv == 0){
                cout << "The client disconnected." << endl;
                Logger("The client disconnected");
                break;
            }

            cout << "bytesRecv: " << bytesRecv << endl;
       }

       // Close the socket
       close(clientSoket);
    }

c++ tcpserver
1个回答
1
投票

不,流套接字不是这样的。

流套接字是一个非结构化的字节流,没有任何结构。在这方面,它和普通文件没有什么不同。如果你把大小不一的记录写到一个明文文件中,现在你准备把它们读回来,你希望如何读取大小不一的记录呢?

无论你在这里给出的答案是什么,同样的答案也适用于套接字,但有一个额外的变化,那就是 read() 在插座上,你不能保证你能读到多少内容,只能保证它小于或等于 size 参数为 read(). 这是唯一的保证,你会得到从。read().

如果发件人叫 write() 两次(顺便说一下,插座也不能保证无论你想怎么做 write,那么多的东西被写出来。write 也可以返回一个小于或等于其 size 参数,至于如何处理就看你的代码了),一次写了76个字节,第二次写了84个。read()ing,(假设一个足够大的缓冲区大小)可以在初始读取时读取1到160个字节之间的任何数量的字节。

如果你想实现一些形式化的结构,比如记录,那就要看你如何在这些约束条件下实现它。也许通过发送每个记录的大小,以字节为单位,然后是记录本身。或者做任何你想做的事情。只需记住,你不能保证,无论如何,每个记录的数量是多少。read() 返回。例如,如果你要先发送记录数,作为一个四字节的值。你的初始 read() 可能返回一个、两个或三个字节。你的代码必须准备好处理任何可能的情况。

© www.soinside.com 2019 - 2024. All rights reserved.