在C ++中使用Unix套接字编程,recv返回0,但仍然接收数据,但有时接收的内容多于发送的内容

时间:2014-04-22 03:09:02

标签: c++ sockets unix

我是C ++和套接字编程的新手。我和Beej的导游一起学习,所以我的代码几乎与指南相同,但我正在努力学习奇怪的错误。

首先,我的服务器的recv()返回0.根据文档,客户端应该优雅地关闭连接,以便recv()返回0.不是我的情况。它返回0,同时,我仍然从客户端收到数据。所以,Beej的接受方式对我来说不起作用。有人可以解释一下这是如何实现的吗?

char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0); 
buf[numbytes] = '\0';

这里的最后一行,因为numbytes为0,它会清除我收到的所有消息。所以我不得不对此发表评论。现在,我的代码看起来像这样

char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0); 
//buf[numbytes] = '\0';
printf("received: %s\n", buf); 

现在可以接收客户端发送的一些消息。但是,我在客户端进行了一些字符串操作(追加),然后发送了消息。现在,我在客户端发送字符串长度为29,但服务器接收41个字符,带有奇怪的字符。 我发送的内容:收到:登录#1 Mary 123456 451912345 收到:登录#1 Mary 123456451912345ÿ>É“ÿy@ÿ>Ád

以下是我在服务器中收到的信息:

while(1) { // main accept() loop

    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
    if (new_fd == -1) {
        perror("accept");
        continue;
    }
    char buf[MAXDATASIZE];
    int numbytes;
    if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1) 
    perror("recv");
    //buf[numbytes] = '\0'; // this had to be commented out
    printf("received: %s\n", buf); // prints out with weird characters

    string msgRcved = buf;

        close(new_fd); 
}

这是我从客户端发送的方式:

// string loginCredential is loaded with "1 Mary 123456 451912345" at this point
loginCredentials.insert(0, "Login#");
const char* msgToSend = loginCredentials.c_str();
int numbytesSent;
if (numbytesSent = send(sockfd, msgToSend, strlen(msgToSend), 0) == -1)
    perror("send");

我想知道我的recv在第一次返回0时如何接收数据。而且,我想知道从客户端/发送数据到服务器的数据recv我做错了什么。

3 个答案:

答案 0 :(得分:3)

您有优先权问题。

此:

if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1) 

相当于

if (numbytes = (recv(new_fd, buf, MAXDATASIZE-1, 0) == -1))

recv(new_fd, buf, MAXDATASIZE-1, 0) == -1
<{1}}成功时,

为0。

发送端存在同样的问题。

没有理由写出这种尴尬和容易出错的情况 这更安全:

recv

答案 1 :(得分:2)

你必须测试数字&#39;为零,单独,如果你让它关闭套接字并退出读循环,因为对等关闭了连接。 否则,并假设您还测试了-1,您只需要处理&#39; numbytes&#39;缓冲区的字节数。不是所有的人。否则,您可能会重新处理已处理的字节。在这种情况下,这可能意味着恢复以null终止缓冲区的行,或者它可能意味着:

printf("%.*s", numbytes, buf);

答案 2 :(得分:0)

您正在打印堆栈分配缓冲区中的垃圾,而不是客户端发送的垃圾。当recv(2)返回零时,没有任何内容被放入提供的缓冲区中,因此这可能来自循环的某个先前迭代。

注意:

  1. 连接的TCP套接字是双向字节流。这意味着您可以发送几条“消息”并在另一侧的一个块中接收它们,或者相反。在循环中从套接字读取,直到您有足够的数据要处理,即使用显式的消息分隔符,或者预先添加后面的消息长度。这是您的应用程序级协议

  2. 不要像这样混合使用C和C ++字符串。 std::string有一个size()方法,使用它而不是strlen( msgToSend.c_str() )

  3. 在堆栈上分配任何相当大的缓冲区,尤其是那些从网络接收输入的缓冲区是个坏主意。

  4. 打印或以其他方式传递未经验证的网络输入是严重的安全违规行为,会导致各种问题。

  5. 编辑0:

    @ molbdnilo的答案是对的。我没有发现条件中的优先级问题。我的笔记仍然适用。