C ++网络,recv()无缘无故(?)失败

时间:2018-08-26 12:43:22

标签: c++ sockets networking tcp recv

我正在用C ++编写聊天服务器,这是出于我自己的娱乐,但对于一般的联网我还是相当陌生。我的知识来自Beej的指南this site和Kurose&Ross的自上而下的方法。

我的问题是,我写的代码很类似于在链接上可以找到的代码,但是它不起作用。当我尝试在服务器上使用recv()函数时,程序失败。

我知道recv()可以返回任意数量的字节,但是它只是给我-1。我知道我需要一个循环来组合正在发送的消息,但是到目前为止还没有类似的东西。但是,客户端中的send()表示它发送了缓冲区中指定的数量(是的,我知道这可能是过大的了,虽然不确定那是一个错误)。

在我看来,服务器似乎已关闭……我很确定自己在某个地方搞砸了,有些代码我真的不确定(请看注释)。昨天我设法使其正常工作,但此后出了点问题。

我真的是套接字编程和任何类型的网络的新手,但是函数调用和其他什么都不来自指南,我直觉这个问题将出在指定端口和地址的那部分上,也许是字节未到达服务器,因为我正在将它们发送到其他地方?但是,如果accept()有效,那是否就意味着建立了TCP连接,那之后我不应该使用它吗?

如果有帮助,我正在使用最新版本的Lubuntu linux。

如果发现问题,能否请您告诉我如何正确解决?无论如何,这是服务器的代码:

void start() {

    char message[1024] = "";

    int socketfd = socket( AF_INET, SOCK_STREAM, 0 ), opt = 1, new_socket;

    struct sockaddr_in address;
    struct sockaddr_storage cl_addr;
    socklen_t len = sizeof(address);

    if( socketfd != 0 ) {

        address.sin_family = AF_INET;
        address.sin_port = htons( PORT );
        address.sin_addr.s_addr = INADDR_ANY;

        if( setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(int)) < 0 ) {
            perror("Setsockopt failed");
            exit(EXIT_FAILURE);
        }

        if( bind( socketfd, (struct sockaddr*)&address, len ) < 0 ) {           
            perror("Couldn't bind to port");
            exit(EXIT_FAILURE);
        } 

        if( listen( socketfd, 3 ) < 0 ) {
            perror("Listening on port failed");
            exit(EXIT_FAILURE);
        }

        if( (new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len  ) < 0) ) {
            perror("Couldn't accept request");
            exit(EXIT_FAILURE);
        }

        /// This is where it fails
        std::cout << recv( new_socket, message, 1024, 0) <<  std::endl;
        close(new_socket);
    }
    else {
        perror("Couldn't open socket");
        exit(EXIT_FAILURE);
    }
    close( socketfd );
}

现在是客户端:

int main(void) {

int sockfd;

struct sockaddr_in serv_addr;
char hello[1024] = "Hello";

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

/// I'm not sure about this !! 
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if( sockfd == 0 ) {
    perror("Opening socket failed");
    exit(EXIT_FAILURE);
}

if( connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != -1 ) {
    /// Says it sent 1024, but sever doesn't recieve it, what gives ?
    int test = send( sockfd, hello, sizeof(hello), 0);
    std::cout << test << std::endl;
}
else {
    perror("Error");
    exit(EXIT_FAILURE);
}

如您所见,它类似于在链接上找到的代码。服务器代码只是一个功能,代码中还有其他部分,例如创建用户文件,但是在网络部分中却没有使用它们,因此,我不想再发布800行代码。服务器的main()就是我创建服务器类的对象并在其上调用start()。

我想在哪里做得更好,所以如果您发现我可以做得更好的事情,请告诉我,无论是通用编码风格还是其他。另外,这是我的第一个问题,我的母语不是英语,请对我轻松一点:)

1 个答案:

答案 0 :(得分:3)

这是一个括号问题。

此行:

if( (new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len  ) < 0) ) {

<运算符具有比=运算符更高的评估优先级。

new_socket被分配了对accept() < 0的求值,这是一个错误的表达式,因此new_socket被分配了零。

这可能就是您的意思:

if (new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len ) < 0)

但这很少会出错:

new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len  ); 
if (new_socket < 0) {
        perror("Couldn't accept request");
        exit(EXIT_FAILURE);
}