【问题标题】:Lua socket receive string sizeLua 套接字接收字符串大小
【发布时间】:2011-07-20 11:45:37
【问题描述】:

我有一个 Lua 脚本,它使用 NSE(nmap 脚本引擎)递归地发送命令并通过套接字连接接收数据。它似乎通常工作,直到它得到一个大字符串,然后它倾向于截断接收到的数据。在发送下一个命令时,应该在前一个命令中接收到的数据之后通过(最终是正确的数据)。下面的简化示例输出。注意“data38”被截断并在命令的下一个实例中继续:

"send command1"
"recieved data ="
data1
data2
data3
....
....
....
data37
da 
**returning**
"send command2"
"received data ="
ta38 (should be from command1)
data39 (should be from command1)
etc etc etc

示例代码如下:

local function blah(id)

local response
local data
local commmand

command = "dir..id"

socket:send(command)
response,data = socket:receive()

print(data)

--do recursion her depending on data results.

 print "**returning**"
 return

action = function(host,port)
     socket = nmap.new_socket()
     socket:connect(host,port)
     socket:set_timeout(15000)
     test = blah(id)
return test

问题好像是socket只能接收一定数量的字节,然后返回。套接字是一个全局变量,因为我不想为每个“blah”实例打开一个新套接字。有什么办法可以让套接字等待接收所有数据(例如,直到字符串为空终止)然后打印数据??

更新 我一直在尝试不同的方法将大小参数传递给接收方法,如下所述: http://w3.impa.br/~diego/software/luasocket/tcp.html 然而,这些似乎没有任何效果,例如。

response,data = socket:receive(65536)
response,data = socket:receive('a*')

【问题讨论】:

    标签: sockets lua truncation


    【解决方案1】:

    通过网络传递字符串或二进制数据时,我一直使用的解决方案是首先传递字段的大小。然后您可以运行接收,直到它与已知长度匹配。这意味着服务器将如下所示:

    command,err_msg=socket:receive()
    -- build response
    socket:send(string.len(response))
    -- Note, you should also check for incomplete sends and 
    -- run this in a loop until all data has been sent
    socket:send(response)
    

    客户端看起来像:

    socket:send(command)
    resp_len,err_msg = socket:receive()
    response=""
    repeat
      resp_cur,err_msg = socket:receive(resp_len - string.len(response))
      if resp_cur then
        response = response .. resp_cur
      end
    until !resp_cur or string.len(response) >= resp_len end
    -- handle any errors from an incomplete receive here
    

    【讨论】:

    • 我不知道每次调用该函数时返回的数据大小,数据大小可能会有所不同。我试过 socket:receive('a*') 从套接字读取直到连接关闭。但结果是一样的。
    • 这就是为什么我建议你先发送尺寸
    • 你的意思是像:response,data = socket:receive(65536)??我试图按照这些思路实现一些东西,但似乎仍然没有区别
    • @greatodensraven:我已经用代码更新了答案以使其更加清晰。
    【解决方案2】:

    我相信 luasocket 库(至少 Corona SDK 使用的版本)中存在一个错误,导致它间歇性地破坏 TCP 上的大数据包。 Corona SDK 开发人员已经确认了这一点。问题怀疑是luasocket库没有正确处理TCP Retry请求。我试图通过将我的帧大小限制为小于标准网络 (ipv4) MTU 来规避错误,希望这将避免数据包碎片并防止出现问题。我通过自己将数据包数据分解成更小的帧然后在另一端重新组装来实现这一点。 IPV4 的 MTU 通常为 576 字节,我尝试使用 512 以确保安全。

    【讨论】:

      【解决方案3】:

      澄清一下,socket.receive 的正确参数是 '*a' 而不是 'a*' - 这可能是您没有从套接字接收所有数据的原因。

      【讨论】: