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.
精彩评论