我是这个论坛的新手,所以如果我的问题没有被正确询问,我很抱歉。我会尽量保持清醒。
我正在尝试在Linux中编写两个程序(client.c和server.c,使用TCP套接字),但行为如下:
客户端向服务器发送包含要由服务器运行的命令(ls,mkdir等)的消息。
服务器运行这些命令,并将程序输出(stdout)发送回客户端。
客户端打印收到的程序输出。
到目前为止,我有这个:
server.c:
/*After creating socket with socket(), binding to address and port,
putting in listening mode and accepting connection*/
dup2(sock_client,1); //redirect stdout
while(1){
recv(sock_client,buf,MAX_MSG_LENGTH,0);
/*If the message recieved was END_STRING, exit this loop*/
if (strncmp(buf, END_STRING, MAX_MSG_LENGTH) == 0)
break;
system(buf);
}
client.c:
/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%s\n",buf);
}
我的问题是,如果一个命令有一个很长的输出,当显示下一个命令的输出时,它会留下一些“垃圾”,所以我想知道是否有一种方法来刷新套接字(显然不是,基于我的谷歌研究),或者可能以其他方式完成预期的服务器 - 客户端行为。
谢谢!
编辑:
好的,我已经完成了客户端。这是代码:
client.c:
/* After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
while(1){
read_size = read(sock,buf,MAX_MSG_LENGTH);
/*Print read_size characters from buf*/
printf("%.*s\n", read_size, buf);
if (read_size < MAX_MSG_LENGTH){
/*Keep on reading until read_size < MAX_MSG_LENGTH, then exit this loop*/
break;
}
}
/*Clear buffer, just in case*/
for (i = 0; i < MAX_MSG_LENGTH; i++){
buf[i] = 0;
}
正如评论一样,如果发送到服务器的命令没有任何标准输出(例如,mkdir new_directory
),则此程序将无法正常工作,因为在这种情况下,read()
将永久阻止客户端,导致服务器永远不会接收下一个要运行的命令或END_STRING
消息从客户端离开该程序。您可以通过使用非阻塞套接字并使用select()
从套接字读取来修复此问题,就像synther建议的那样。此外,在服务器中,在system(buf);
行之后,您应该添加fflush(0)
,这将刷新所有缓冲区(包括套接字,如果客户端发送的命令非常短,这可能很有用)输出)。
非常感谢!
答案 0 :(得分:0)
也许,你得到&#34;垃圾&#34;在客户端,当您的命令输出超过MAX_MSG_LENGTH
时。 read(sock,buf,MAX_MSG_LENGTH);
从socket读取MAX_MSG_LENGTH
个字节,下一次当你从下一个命令中读取时,读取socket中的剩余字符。
您可以在客户端以多种方式修复它。
read
返回读取的实际字节数。您可以将其与MAX_MSG_LENGTH
进行比较,并决定再读一次。但是,如果您的实际数据恰好是MAX_MSG_LENGTH
字节,那么您决定再次阅读并read
阻止当前不可用的等待数据(以及stdin
阻止,用户可以&#39; t发送新命令)。
使用非阻塞套接字修复1
中的问题。没有可用数据时,read
将立即返回。
将命令尾标记添加到服务器的输出中,客户端将知道何时停止读取并切换到stdin
读取。
使用select()
机制同时读取套接字和用户输入&#34;&#34;。当任何数据可用时,它允许从多个文件描述符(套接字和stdio
)读取。
此外,您对用户命令和服务器响应使用相同的缓冲区。通常,用户命令比服务器输出短,buf
可以包含最后一个服务器输出的部分。然后将这个用户命令和最后一个服务器输出的混合发送到服务器。
并且,如上所述,read
返回读取的实际字节数。您应该从buf
打印确切接收的字节数,而不是所有数据。
int ret = read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%.*s\n", ret, buf);
答案 1 :(得分:0)
感谢您的回答!
我尝试将其添加到我的client.c代码:
/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
/*Send command to server*/
send(sock,buf,MAX_MSG_LENGTH,0);
if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
/*If the message recieved was END_STRING, exit this loop*/
break;
}
while(1){
read_size = read(sock,buf,MAX_MSG_LENGTH); //read stdout from program
printf("%.*s\n", read_size, buf);
if (read_size < MAX_MSG_LENGTH){
/*Exit this loop when reading less that MAX_MSG_LENGTH*/
break;
}
}
/*Clear the 'buf' array. I don't know if this is really necessary*/
for (i = 0; i < MAX_MSG_LENGTH; i++){
buf[i] = 0;
}
}
现在,在每个命令之后,客户端只打印发送的最后一个命令的输出。如果这个解决方案是正确的,我会更彻底地测试它并编辑我的原始帖子,所以非常感谢!