我是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我做错了什么。
答案 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)
返回零时,没有任何内容被放入提供的缓冲区中,因此这可能来自循环的某个先前迭代。
注意:
连接的TCP套接字是双向字节流。这意味着您可以发送几条“消息”并在另一侧的一个块中接收它们,或者相反。在循环中从套接字读取,直到您有足够的数据要处理,即使用显式的消息分隔符,或者预先添加后面的消息长度。这是您的应用程序级协议。
不要像这样混合使用C和C ++字符串。 std::string
有一个size()
方法,使用它而不是strlen( msgToSend.c_str() )
。
在堆栈上分配任何相当大的缓冲区,尤其是那些从网络接收输入的缓冲区是个坏主意。
打印或以其他方式传递未经验证的网络输入是严重的安全违规行为,会导致各种问题。
@ molbdnilo的答案是对的。我没有发现条件中的优先级问题。我的笔记仍然适用。