TCP服务器/客户端:客户端recv()返回空白缓冲区

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP服务器/客户端:客户端recv()返回空白缓冲区相关的知识,希望对你有一定的参考价值。

我用C ++创建了一个TCP服务器/客户端。客户端从stdin获取输入char数组。然后客户端将其发送到服务器。服务器的工作是使用来自客户端的修改形式的消息进行响应。服务器的修改:用'X'替换输入消息的第一个字符

它在第一个输入消息上按预期工作,但客户端从第二个消息开始接收格式错误的数据。

./client.bin输出:

helloworld          <-----stdin
TX: helloworld
RX: Xelloworld
test                <-----stdin
TX: test
RX: 0est
somethingelse       <-----stdin
TX: somethingelse
RX: Xest

./echoserver.bin输出:

RX: helloworld
TX: Xelloworld
RX: test
TX: Xest
RX: somethingelse
TX: Xomethingelse

echo server.曹操:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>   
#define  PORT 8080
#define  BUF_SIZE 1024

void error_exit(std::string text)
{
    std::cerr << text << std::endl;
    exit(1);
}

int main()
{
    int sd;
    int connection;
    int valread;
    int opt = 1;
    char buffer[BUF_SIZE] = {0};
    if ((sd = socket(AF_INET,SOCK_STREAM,0)) == 0)
        error_exit("socket failure");

    if (setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,
            &opt, sizeof(opt)))
        error_exit("failed to set socket opts");

    sockaddr_in address;
    address.sin_family      = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port        = htons(PORT);
    if (bind(sd, (struct sockaddr *)&address, sizeof(address)) != 0)
        error_exit("failed to bind socket");

    if (listen(sd,3) < 0)
        error_exit("failed to listen");

    int addrlen = sizeof(address);
    if ((connection = accept(sd, (struct sockaddr*)&address,
                    (socklen_t*)&addrlen)) < 0)
        error_exit("failed to accept socket link");

    while (1)
    {
        memset(&buffer[0],'0', sizeof(buffer));
        if (recv(connection,buffer,BUF_SIZE-1,0) <= 0)
            break;
        std::cout << "RX: " << buffer << std::endl;
        buffer[0] = 'X';
        std::cout << "TX: " << buffer << std::endl;
        send(connection,buffer,BUF_SIZE,0);
    }
    return 0;
}

client.曹操

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUF_SIZE 1024

void error_exit(std::string text)
{
    std::cerr << text << std::endl;
    exit(1);
}

int main()
{
    int sd;
    int valread;
    struct sockaddr_in address;
    struct sockaddr_in server_addr;
    char buffer[BUF_SIZE] = {0};

    if ((sd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        error_exit("failed to create socket");

    memset(&server_addr, '0', sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_port   = htons(PORT);

    if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0)
        error_exit("Invalid Address");

    if (connect(sd,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0)
        error_exit("Connection Failure");

    std::cin >> buffer;
    while (buffer[0] != 'q')
    {
        std::cout << "TX: " << buffer << std::endl;

        send(sd,buffer,BUF_SIZE-1,0);
        if ( recv(sd,buffer,BUF_SIZE-1,0) <= 0)
            error_exit("Failed to receive");
        std::cout << "RX: " << buffer << std::endl;
        memset(&buffer[0],'0', sizeof(buffer));
        std::cin >> buffer;
    }
    return 0;
}
答案

你的发送调用总是发送1023个字节,但是你的recv调用并不一定要下载所有那些数据,你需要在循环中调用recv,直到你拥有所有发送的数据或传递MSG_WAITALL标志。

以上是关于TCP服务器/客户端:客户端recv()返回空白缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

gen_tcp:recv/2 返回错误,einval

在 C 中处理来自 recv() TCP 的部分返回

004-Tcp

TCP:recv() 获取 ECONNRESET

为啥 sys socket recv 函数不填充数据但返回字节长度?

如果达到超时,gen_tcp:recv/3 是不是会关闭套接字?