通过套接字从光纤发送和读取数据

问题描述 投票:0回答:2

试图弄清楚如何通过套接字发送/读取数据。在远程服务器上,我创建新的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

在我的梦里,我将数据发送到通道,从第一个循环读取它,然后发送到套接字。同样的方法,但是需要从第二个循环中读取相反的顺序。

在实践中,这不会发生。连接后在本地我得到了“测试”,什么也发不回。在远程上,我可以发送到本地,但在本地上,只能发送一次空字符串,之后仅发送空字符串。

这种行为是什么意思,以及如何实现计划的目标?

sockets crystal-lang fibers
2个回答
1
投票

您没有显示,但是我想您有第二种实现,其中使用TCPServer表示等效于netcat -l

您需要使用单独的光纤来读写套接字和通道。在不查看服务器的情况下很难判断到底会发生什么,但是我想您最终陷入了僵局,双方都在等待对方或用户的输入,但无法继续实际发送或读取任何内容。换句话说,您将发送/接收部分互锁,要求另一端谨慎地进行反应和相互作用,以免锁定客户端。这显然是一种脆弱的方法。

相反,您应确保任何光纤在一圈中最多只能进行一项操作。一个从套接字接收并将其转发到一个通道,第二个从套接字接收并将其转发到一个套接字,第三个从读取器一侧的通道接收并打印或执行您想做的任何数据,最后一个填充发送者频道。这样,任何操作都无法阻止其他操作之一。当然,这些光纤之一应该只是主程序之一。

在服务器中,您还需要一根光纤来接受客户端连接并为每个连接生成发送器和接收器循环。

最后请注意,只有一个select分支的when语句无效,您可以直接进行调用。如果需要在同一根光纤中同时读取或写入多个通道,则select很有用,因此,例如,如果您有多个通道提供要发送到套接字的数据,则可以使用select来避免两条光纤同时写入同一套接字会破坏消息。 select的另一个用例是从带有超时的通道发送或接收。


0
投票

谁正在寻找类似问题的答案。我想要的最终结果如下所示:

# 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)

它将发送每个命令并等待远程的回答(最后一个除外),然后调用下一个命令。

© www.soinside.com 2019 - 2024. All rights reserved.