试图弄清楚如何通过套接字发送/读取数据。在远程服务器上,我创建新的netcat -l 4444
,然后从本地发送文本数据echo "test" | netcat remote.host 4444
。这总是可以的。
试图复制:
require "socket"
HOST = "remote.host"
PORT = 4444
ch_request = Channel(String).new
ch_response = Channel(String).new
spawn do
socket = TCPSocket.new(HOST, PORT)
loop do
select
when request = ch_request.receive
socket << request
socket.flush
end
if response = socket.gets
ch_response.send response
end
end
end
sleep 0.1
ch_request.send "hello"
loop do
select
when response = ch_response.receive
pp response
end
end
在我的梦里,我将数据发送到通道,从第一个循环读取它,然后发送到套接字。同样的方法,但是需要从第二个循环中读取相反的顺序。
在实践中,这不会发生。连接后在本地我得到了“测试”,什么也发不回。在远程上,我可以发送到本地,但在本地上,只能发送一次空字符串,之后仅发送空字符串。
这种行为是什么意思,以及如何实现计划的目标?
您没有显示,但是我想您有第二种实现,其中使用TCPServer
表示等效于netcat -l
。
您需要使用单独的光纤来读写套接字和通道。在不查看服务器的情况下很难判断到底会发生什么,但是我想您最终陷入了僵局,双方都在等待对方或用户的输入,但无法继续实际发送或读取任何内容。换句话说,您将发送/接收部分互锁,要求另一端谨慎地进行反应和相互作用,以免锁定客户端。这显然是一种脆弱的方法。
相反,您应确保任何光纤在一圈中最多只能进行一项操作。一个从套接字接收并将其转发到一个通道,第二个从套接字接收并将其转发到一个套接字,第三个从读取器一侧的通道接收并打印或执行您想做的任何数据,最后一个填充发送者频道。这样,任何操作都无法阻止其他操作之一。当然,这些光纤之一应该只是主程序之一。
在服务器中,您还需要一根光纤来接受客户端连接并为每个连接生成发送器和接收器循环。
最后请注意,只有一个select
分支的when
语句无效,您可以直接进行调用。如果需要在同一根光纤中同时读取或写入多个通道,则select
很有用,因此,例如,如果您有多个通道提供要发送到套接字的数据,则可以使用select
来避免两条光纤同时写入同一套接字会破坏消息。 select
的另一个用例是从带有超时的通道发送或接收。
谁正在寻找类似问题的答案。我想要的最终结果如下所示:
# Open socket for simulate remote server: `netcat -v -4 -l 4444`
require "socket"
HOST = "remote.host"
PORT = 4444
# JFYI: In real life this packed into class and I use class variable instead consts.
TUBE_REQUEST = Channel(String).new
TUBE_RESPONSE = Channel(String).new
SOCKET = TCPSocket.new(HOST, PORT)
spawn do
until SOCKET.closed?
if request = TUBE_REQUEST.receive
SOCKET << request
SOCKET.flush
end
end
end
spawn do
until SOCKET.closed?
if response = SOCKET.gets
TUBE_RESPONSE.send response
end
end
end
sleep 0.1
def receive_response
TUBE_RESPONSE.receive
end
def send(message, wait_for_response = true)
TUBE_REQUEST.send message
receive_response if wait_for_response
end
send("command with response")
send("command with new line and response\n")
send("command without new line and response", false)
它将发送每个命令并等待远程的回答(最后一个除外),然后调用下一个命令。