嗨,我正在尝试在服务器和客户端应用程序之间创建一个简单的用户名/密码读写。目前,我的客户端运行良好。我遇到的问题在服务器端内部。当我在客户端输入用户名时,服务器会正确捕获该用户名。请参见以下代码:
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个,则多余的字符将被修改为password变量。如果您输入的字符少于9个,则代码会跳过,并且出于某种原因,密码变量会立即设置为“”。有人可以解释一下,告诉我如何解决吗?
答案 0 :(得分:0)
您似乎正在使用流套接字(SOCK_STREAM
,即TCP)。从应用程序的角度来看,流套接字基本上只是一个双向管道。
除了您的应用程序强加的内容外,没有“消息”的概念。套接字仅发送和接收单个长字节流。 write(fd, "foo", 3); write(fd, "bar", 3);
与write(fd, "foobar", 6);
具有相同的作用。它以相同的顺序发送相同的字节。
如果您希望流传输多条单独的消息,则必须以某种方式对这些消息边界进行编码。
'\0'
)标记消息的结尾。然后,接收到的代码将不得不循环直到看到'\0'
。您的代码中的此注释表示您选择了选项1:
/* All messages are 9 bytes. */
但是显然,发送代码有一个错误,因为它试图传输一条9字节以上的消息,然后将其解释为多条消息。如果客户端发送12个字节,则该消息为9个字节,然后是另一个(不完整的)3个字节的消息。 “ 当前我的客户端运行正常”?不,不是;不是。至少在您的接收码正确的情况下不是。
另一个问题是
printf("[DEBUG] Client username is %s.\n", username);
%s
需要一个C字符串,即一个以N终止的字符序列。 username
没有NUL终止符(除非客户端决定显式发送'\0'
字节作为消息的一部分)。实际上,recv_msg
的用户无法知道收到了多少数据。如果总是9个字节,
printf("%.9s", username);
可以工作,但是recv_msg
不能确保确实如此:
int n = read(sockfd, msg, 9);
它只是忽略了n
,因此msg
的全部或部分可能未初始化,并且调用代码无法分辨。