开发者

Lua socket receive string size

I have a Lua script that recursively sends commands and receives data back over a socket connection, using NSE (nmap scripting engine). It seems to usually work, until it gets a large string back, then it tends to truncate the received data. On sending the next command, the data after the truncation, that should have been received in the previous command, comes through (followed eventually by the correct data). simplified sample output below. Note "data38" is truncated and continues in next instance of t开发者_如何学运维he command:

"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

sample code is as follows:

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

The problem seems to be that the socket can only receive a certain number of bytes, and then returns. Socket is a global variable, as I do not want to open a new socket for every instance of "blah". Is there any way I can make the socket wait to receive all the data (until the string is null terminated for example) and then print the data??

Update I have been trying different approaches to pass a size parameter to the receive method, as stated in: http://w3.impa.br/~diego/software/luasocket/tcp.html However these seem to have no effect whatsoever eg.

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


The solution I've always used when passing a string or binary data over the network is to first pass the size of the field. Then you can run the receive until it matches the known length. This means the server will look like:

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)

And the client would look like:

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


I believe there is a bug in the luasocket library (at least the version used by the Corona SDK) which causes it to intermittantly corrupt large packets over TCP. This has been confirmed by the Corona SDK developers. The issue is suspected to be that the luasocket library does not handle TCP Retry requests properly. I am attempting to circumvent the error by restricting my frame size to less than the standard network (ipv4) MTU, hopefully this will avoid packet fragmentation and prevent the problem arising. I am achieving this by braking up the packet data myself into smaller frames then reassembling at the other end. MTU for IPV4 is usually 576 bytes, im trying with 512 to be safe.


Just to clarify, the correct parameter to socket.receive is '*a' not 'a*' - this may be why you are not receiving all the data from the socket.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜