How to read from socket in non-blocking mode


#1

I was trying to skip some initial server info header when using tcp client in Julia 0.6.0:

julia> s=connect("smtp.mail.ru",25)
TCPSocket(RawFD(18) open, 0 bytes waiting)

julia> nb_available(s)
0

julia> nb_available(s)
0
(after 5 seconds or so...)
julia> nb_available(s)
0

julia> t=read(s,10)
10-element Array{UInt8,1}:
 0x32
 0x32
 0x30
 0x20
 0x73
 0x6d
 0x74
 0x70
 0x31
 0x34
(HOW, WHY???? nb_available==0, but read returns me 10 bytes?!)

... (read was repeated many times...)
julia> t=read(s,10)
^CERROR: InterruptException:
Stacktrace:
 [1] process_events at ./libuv.jl:82 [inlined]
 [2] wait() at ./event.jl:216
 [3] wait(::Condition) at ./event.jl:27
 [4] wait_readnb(::TCPSocket, ::Int64) at ./stream.jl:296
 [5] readbytes!(::TCPSocket, ::Array{UInt8,1}, ::Int64) at ./stream.jl:714
 [6] read(::TCPSocket, ::Int64) at ./io.jl:529

So… nb_available shows something incorrect. Mail server sends me some initial header, but nb_available cant see it and tell me that 0 bytes awaiting in the read buffer. Why?
Is there any other posobilities to skip server “greatings” header without blocking?

Thanks!


#2

nb_available only tells you whether some bytes can be read without blocking. read can return more data , but then it may block (as ?read says).


#3

All I/O in julia is non-blocking in the traditional sense of the word, because we don’t block threads on I/O activity. However, we do use tasks to simulate blocking I/O for ease of programming. The nb_available function isn’t super meaningful for sockets. It tells you how many bytes are available in the userspace buffer. It says nothing about now many bytes are available in the kernel, in various buffers along the network path or are in transit.


#4

But why nb_available == 0 and right after this - i can read more than 100 bytes without blocking? This is very strange, i think


#5

Thanks :slight_smile:

But… Anyway, how to read initial bytes which server may send to me/may not send - and avoid the risk to be blocked on read command?


#6

You do all your processing in a task.

@async begin
while !eof(socket)
line = readline(socket)
# process line
end
end

#7

What if we want to work interactively, meaning that I do not want to process the returned data in the task? Is there a way to have a timeout?

The purpose here is e.g. working with SCPI.


#8

Friendly bump here, timeouts are quite necessary when working with instruments.


#9
@async (sleep(timeout); close(socket))

#10

If I’m not mistaken, this will need a whole new socket to be created for the next message after the timeout, right?


#11

Also, if the read does complete, the socket will still get closed.