c - 为什么客户端的输出不会打印到屏幕上?
问题描述
我试图通过套接字注入远程代码,但由于某种原因,在编写命令cd
或任何其他命令时,这反过来又通过客户端给我一个答案,答案不会输出到屏幕上。
我尝试了各种输出到屏幕的方法,但没有一种方法有效。
输出的服务器部分:
void *ReadAndWriteSocket(void *entrypoint) {
char message[256];
char buffer[256];
while (1) {
if((sockStructure.n = recv(sockStructure.newsockfd, buffer, strlen(buffer), 0)) > 0) {
for(int i = 0; i < strlen(buffer) - 1; i++) {
printf("%s", buffer[i]);
}
}
}
scanf("%s", &message);
send(sockStructure.newsockfd, message, strlen(message), 0);
}
客户端代码:
require 'socket'
require 'open3'
def createClient(hostname, port)
s = TCPSocket.new hostname, port
while line = s.gets
if line == "exit"
s.close
elsif line[0..1] == "cd"
output = Dir.chdir(Dir.pwd + "/" + line[2..line.size].delete(" \t\n\r\0"))
s.puts(Dir.pwd)
end
stdin, stdout, stderr, wait_thr = Open3.popen3(line)
s.puts("#{stdout.read}")
end
end
createClient("127.0.0.1", 8082);
解决方案
一旦您收到哪怕是最微小的数据,您就会阻止scanf
而不是尝试接收更多数据。您要么需要同时支持在两个方向上移动数据(等待输入scanf
和数据输入recv
),要么在改变方向时需要更聪明。
考虑以下场景:
- 你打电话
ReadAndWriteSocket
。 - 您的调用只
recv
得到一个“H”,即消息的第一个字节。 - 您将“H”传递给
printf
,但没有打印任何内容,因为您的标准输出是行缓冲的。 - 您打电话
scanf
并永远等待,但什么都没有发生,因为用户在看到收到的消息之前无意输入任何内容。 - 您的代码将永远不会
recv
再次调用,太糟糕了,因为接收到的消息的其余部分正在接收缓冲区中等待,但您被困在scanf
.
当你的代码在两个方向移动数据时,你必须绝对确保当你应该等待的数据从另一个方向到来时,你永远不会阻塞等待接收数据。您的代码无法阻止这种情况。
更新:新代码的问题:
void *ReadAndWriteSocket(void *entrypoint) {
char message[256];
char buffer[256];
while (1) {
if((sockStructure.n = recv(sockStructure.newsockfd, buffer, strlen(buffer), 0)) > 0) {
这里发生了什么?您只能将字符串传递给strlen
. 但buffer
此处不包含字符串(它在第一次传递时未初始化,并且在后续传递中包含不相关的长度)。因此,您将长度的无意义值传递给recv
.
for(int i = 0; i < strlen(buffer) - 1; i++) {
printf("%s", buffer[i]);
这里有两个问题:首先,buffer[i]
不是字符串,%s
格式说明符用于字符串。其次,标准输出是行缓冲的,所以除非缓冲区恰好包含一行,否则它不会显示。
}
}
}
scanf("%s", &message);
为什么要在这里等待用户输入?如果您只收到一小部分消息,甚至没有收到整行消息,因此还没有输出任何内容怎么办?你怎么知道接下来你需要做的是接收来自用户的输入而不是接收其余的消息?
send(sockStructure.newsockfd, message, strlen(message), 0);
}
如果您有一些协议指定谁将在何时发送,谁将在何时接收消息,什么构成消息以及何时等待用户输入,则您必须编写实现该协议的代码。否则,当套接字的接收缓冲区中有数据时,您将陷入scanf
等待输入的困境。
推荐阅读
- azure-active-directory - “未能授权呼叫者,呼叫者不是设备所有者或管理员角色之一。” 微软图
- android - 图像未使用 Intent 发送到另一个活动
- python - 如何使用 Python Regex 查找末尾带有大写单词的句子?
- python - 如何绕过管理员权限从 Python 执行 shell 命令?
- perforce - 从 p4 工作区中删除整个目录树
- c# - 使用相同的 AmazonS3Client 实例进行并行请求?
- python - 休息 API 迭代,直到达到记录数
- visual-studio-code - tasks.json 的当前子文件夹变量
- javascript - 异步 Do While 循环
- c# - 如何在 Asp.net Mvc 中使用 @Html.DisplayFor 删除显示格式?