客户端 read() 获取消息的随机尾随字符(使用套接字的 TCP 客户端-服务器)
Posted
技术标签:
【中文标题】客户端 read() 获取消息的随机尾随字符(使用套接字的 TCP 客户端-服务器)【英文标题】:Clinet-side read() gets random trailing characters to the message (TCP client-server using sockets) 【发布时间】:2019-01-06 07:40:46 【问题描述】:练习 C 网络编程:我正在编写一个简单的 TCP 客户端-服务器应用程序,它应该将消息(在每个客户端的单独线程中)作为字符串从服务器发送到客户端并在客户端(稍后将成为控制台商店应用程序)。我首先发送消息的大小,然后使用套接字write()
函数发送消息本身。服务器端:
void answer(void *arg)
struct thData tdL;
tdL= *((struct thData*)arg);
// Welcome message
char *initMsgToClient;
getInitialMessage(&initMsgToClient);
int len_initMsgToClient = strlen(initMsgToClient);
// Returning message to client
if ( write (tdL.cl, &len_initMsgToClient, sizeof(int)) <= 0 )
printf("[Thread %d] ",tdL.idThread);
perror ("[Thread] Error at write(): len_initMsgToClient to client.\n");
if (write (tdL.cl, initMsgToClient, len_initMsgToClient) <= 0)
printf("[Thread %d] ",tdL.idThread);
perror ("[Thread]Error at write(): initMsgToClient to client.\n");
else
printf ("[Thread %d] Message was sent with success.\n",tdL.idThread);
void getInitialMessage(char **paramMessage)
char *resultMessage = "Welcome to Console Shopper!";
*paramMessage = resultMessage;
在客户端,我首先读取大小和消息本身并打印它,但每次运行./client
时,我都会在消息中得到不同的随机尾随字符。客户端:
char welcomeMessageFromServer[512];
int lenWelcomeMsg;
// Reading size of first mesage: lenWelcomeMsg
if (read(sd, &lenWelcomeMsg, sizeof(int)) < 0)
perror ("[client] Error reading len welcome message from server.\n");
// Reading initial message from server: welcomeMessageFromServer
if (read(sd, welcomeMessageFromServer, lenWelcomeMsg) < 0)
perror ("[client] Error reading welcome message from server.\n");
return errno;
printf("%s",welcomeMessageFromServer);
printf("\n");
为简单起见,我省略了添加套接字和线程处理的代码,大部分来自教程,因此应该是正确的。我很确定我对正在发送/接收的消息的大小做错了什么。
我对./client
多次运行的输出:
Welcome to Console Shopper!
Welcome to Console Shopper!�
Welcome to Console Shopper!������i0
Welcome to Console Shopper!������UF+:
有时它会做对。为了始终获得正确的信息,我应该更正什么?
【问题讨论】:
【参考方案1】:// Reading initial message from server: welcomeMessageFromServer
if (read(sd, welcomeMessageFromServer, lenWelcomeMsg) < 0)
perror ("[client] Error reading welcome message from server.\n");
return errno;
printf("%s",welcomeMessageFromServer);
这里有两个问题:
%s
格式说明符仅适用于 C 样式字符串。为了使您收到的消息成为 C 风格的字符串,您需要在其末尾添加一个终止零字节。
read
函数不能确保它接收到所有请求的字节。如果没有收到完整的消息,则需要检查返回值并再次调用它。
试试这样的函数:
ssize_t readAll (int fd, void *vbuf, size_t count)
char *buf = (char *) vbuf;
ssize_t read_so_far = 0;
while (count > 0)
ssize_t ret = read(fd, buf, count);
if (ret < 0)
return ret;
if (ret == 0)
return read_so_far;
count -= ret;
read_so_far += ret;
buf += ret;
return read_so_far;
那么你可以这样做:
// Reading initial message from server: welcomeMessageFromServer
if (readAll(sd, welcomeMessageFromServer, lenWelcomeMsg) != lenWelcomeMsg)
perror ("[client] Error reading welcome message from server.\n");
return errno;
welcoemMessageFromServer[lenWelcomeMsg] = 0;
printf("%s",welcomeMessageFromServer);
【讨论】:
我应该做同样的事情来读取任何 int 或 read() 在整数的情况下应该是安全的吗? 您忽略了如果对等方正常断开连接,read()
返回 0 的可能性。 if (ret < 0)
应该是 if (ret <= 0)
否则你会陷入死循环。调用者必须决定它想如何处理readAll() < count
(因为某些协议可以在读取过程中断开连接,例如 FTP,而其他协议则不行)。
@Elliad 你应该做同样的事情来阅读int
,很好。谁知道呢,你可能只读取一个字节。并阅读上面关于正常断开连接导致read
返回零的可能性的评论。 (我对答案中的代码进行了一些可能的更新,这样至少它不会无休止地循环。)
你是否忽略了初始化ssize_t ret_so_far = 0
?以上是关于客户端 read() 获取消息的随机尾随字符(使用套接字的 TCP 客户端-服务器)的主要内容,如果未能解决你的问题,请参考以下文章