套接字编程 C,接收消息是从以前的消息继承而来的



嗨,我正在尝试在我的服务器和客户端应用程序之间创建一个简单的用户名/密码读写。目前我的客户端工作正常。我遇到的问题出在我的服务器端。当我在客户端输入用户名时,我的服务器会正确捕获它。请参阅以下代码:

void authenticate_process(int cli_sockfd){
/* Authentication Process */
write(cli_sockfd, "USN", 3);
char *username;
username = recv_msg(cli_sockfd);
printf("[DEBUG] Client username is %s.n", username);
write(cli_sockfd, "PSW", 3);
char *password;
password = recv_msg(cli_sockfd);
printf("[DEBUG] Client Password is %s.n", password);
}

问题是例如,用户键入"Johnabscaras"作为用户名,然后代码将最后一个"ras"放入密码变量中。我的recv_msg函数如下所示:

/* Reads a message from the server socket. */
char *recv_msg(int sockfd)
{
int length;
char *msg;
msg = (char*) malloc (9);
/* All messages are 9 bytes. */
int n = read(sockfd, msg, 9);
return msg;
}

由于用户名和密码永远不会大于 9 个字节,因此为此进行了设置。但是我发现,在首次输入用户名时,如果您键入超过 9 个字符,多余的字符将被修改为密码变量。如果键入少于 9 个字符,代码将跳过,并且由于某种原因,密码变量会立即设置为 " "。有人可以解释并告诉我如何解决这个问题吗?

看起来您正在使用流套接字(SOCK_STREAM,即TCP(。流套接字基本上(从程序的角度来看(只是一个双向管道。

除了应用程序强加的内容之外,没有"消息"的概念。套接字只是发送和接收单个长字节流。write(fd, "foo", 3); write(fd, "bar", 3);write(fd, "foobar", 6);具有相同的效果。它以相同的顺序发送相同的字节。

如果您希望流传输多个单独的消息,则必须以某种方式对这些消息边界进行编码。

  • 例如,您可以决定每条消息的长度正好为 100 字节,然后始终发送/接收正好 100 个字节。
  • 或者,您可以使用显式终止符(例如''(标记消息的结尾。然后,接收代码必须循环,直到它看到''
  • 或者,您可以发送一个长度字段作为每条消息的第一部分;这样接收代码就可以提前知道需要分配和读取多少字节。

代码中的此注释指示您选择了选项 1:

/* All messages are 9 bytes. */

但显然发送代码有一个错误,因为它试图传输超过 9 个字节的消息,当然,这会被解释为多条消息。如果客户端发送 12 个字节,则这是一条 9 字节的消息,后跟另一条 3 字节的(不完整(消息。">目前我的客户端运行良好"?不,不是;至少如果您的接收代码正确,则不会。

另一个问题是

printf("[DEBUG] Client username is %s.n", username);

%s需要一个 C 字符串,即以 nul 结尾的字符序列。username没有 NUL 终止符(除非客户端决定显式发送''字节作为消息的一部分(。事实上,recv_msg的用户无法知道收到了多少数据。如果它总是正好是 9 个字节,

printf("%.9s", username);

会起作用,但recv_msg并不能确保是这种情况:

int n = read(sockfd, msg, 9);

它只是忽略n,因此msg的全部或部分可能未初始化,并且调用代码无法分辨。

最新更新