0

I have a loop that reads from a socket in Lua:

socket = nmap.new_socket()
socket:connect(host, port)
socket:set_timeout(15000)
socket:send(command)
repeat
    response,data = socket:receive_buf("\n", true)
    output = output..data
until data == nil

Basically, the last line of the data does not contain a "\n" character, so is never read from the socket. But this loop just hangs and never completes. I basically need it to return whenever the "\n" delimeter is not recognised. Does anyone know a way to do this?

Cheers

Updated to include socket code

Update2
OK I have got around the initial problem of waiting for a "\n" character by using the "receive_bytes" method.

New code:

--socket set as above
repeat
    data = nil
    response,data = socket:receive_bytes(5000)
    output = output..data
until data == nil
return output

This works and I get the large complete block of data back. But I need to reduce the buffer size from 5000 bytes, as this is used in a recursive function and memory usage could get very high. I'm still having problems with my "until" condition however, and if I reduce the buffer size to a size that will require the method to loop, it just hangs after one iteration.

Update3 I have gotten around this problem using string.match and receive_bytes. I take in at least 80 bytes at a time. Then string.match checks to see if the data variable conatins a certain pattern. If so it exits. Its not the cleanest solution, but it works for what I need it to do. Here is the code:

repeat
     response,data = socket:receive_bytes(80)
     output = output..data
until string.match(data, "pattern")
return output
tshepang
  • 12,111
  • 21
  • 91
  • 136
greatodensraven
  • 281
  • 1
  • 7
  • 14
  • 1
    If `data` is ever `nil` to exit the loop, then you'll get an error in the concatenation. – lhf Jul 21 '11 at 14:16
  • Good point! The data has never been nil though. I dont think it ever will be nil either. If the receive method doesn't match the delimiter "\n", data will simply remain as it was? – greatodensraven Jul 21 '11 at 14:25
  • Yes, it will. Sockets have no end. You are responsible for framing. – Klinger Jul 21 '11 at 14:28
  • I have no control over the Server/Server code I should mention. I am unfamiliar with framing, but wouldn't that be done Server side? Regards – greatodensraven Jul 21 '11 at 14:35
  • 1
    Framing is collaborative, it's a protocol you both agree upon. You have control over the protocol, but server and client have no control over the network and that's where things can go bad. Also, the server may go bad too and you have to take care of those situations. – Klinger Jul 21 '11 at 15:00
  • If you are expecting "\n" as the end of your message and you are not receiving it something is wrong on the server side or you are having network problems, using a timeout, either by setting it or by using async, is your only option to not wait until a system timeout happens. – Klinger Jul 21 '11 at 15:05
  • Every line has a "\n" at the end of it except the last line. There is no problems server side, this is just the way the data is formatted. My data is read in line by line and appended to the variable "output". But the last line has no "\n", just some escape chars eg. _\0xC. I will read more on async. Cheers – greatodensraven Jul 21 '11 at 15:11
  • If you can not stablish the end of message your only way out is to deal with timeout. Can't you look for this escape char and consider this as the end of the message? Your code does not show any test to detect end of message, other than the nil. – Klinger Jul 21 '11 at 15:47
  • If the size of the message is known before hand, that would be the other way to detec end of message. – Klinger Jul 21 '11 at 15:49
  • Message size is not known beforehand, and varies. I have updated the code and changed method to receive_bytes. Need to just get that loop working correctly now – greatodensraven Jul 21 '11 at 15:58
  • If you have no way of framing your message, timeout is the only solution. I know how you feel, I was dealing with something like this just last week. I managed to conveive an "end of message" of sorts, but that was by no means 100% and very specific to my message. Using timeout was the only way to not just hang in there when data stopped coming before the expected "end of message". – Klinger Jul 21 '11 at 16:04
  • Can you send a second command, e.g. a ping or noop, to get a linefeed on the last line? – BMitch Jul 22 '11 at 11:21

2 Answers2

1

I believe the only way to deal with this situation in a socket is to set a timeout.

The following link has a little bit of info, but it's on http socket: lua http socket timeout

There is also this one (9.4 - Non-Preemptive Multithreading): http://www.lua.org/pil/9.4.html

And this question: http://lua-list.2524044.n2.nabble.com/luasocket-howto-read-write-Non-blocking-TPC-socket-td5792021.html

A good discussion on Socket can be found on this link:

http://nitoprograms.blogspot.com/2009/04/tcpip-net-sockets-faq.html

It's .NET but the concepts are general.

Community
  • 1
  • 1
Klinger
  • 4,900
  • 1
  • 30
  • 35
  • I have included the socket code, including the timeout. Even with the timeout it hangs. And I will need the socket to remain open as it will be used elsewhere. Regards – greatodensraven Jul 21 '11 at 14:06
  • @greatodensraven: Your code does not show you addressing the situation when the timeout happens. – Klinger Jul 21 '11 at 14:10
  • @greatodensraven: Non-Preemptive Multithreading may be what you are looking for. – Klinger Jul 21 '11 at 14:13
  • this method will be used in a recursive loop. A timeout will work, but it will slow the function down considerably. An alternative approach would suit tbh. Regards – greatodensraven Jul 21 '11 at 14:49
0

See update 3. Because the last part of the data is always the same pattern, I can read in a block of bytes and each time check if that block has the pattern. If it has the pattern it will mean that it is the end of the data, append to the output variable and exit.

greatodensraven
  • 281
  • 1
  • 7
  • 14