如何从socket中读取而不阻塞

时间:2017-07-07 11:23:16

标签: asynchronous socket.io julia

我在处理服务器时遇到了问题,向我发送了初始的“问候标题”(smtp服务器):

我需要在发送任何命令之前阅读此标题并从服务器接收任何答案,但我不知道,如何做到这一点,因为Julia似乎没有任何可能从IO流中读取而没有阻塞:“read”命令并且它的类似物没有任何NB选项,nb_available总是为0虽然我确切地知道服务器发送给我标题并且我的读取缓冲区不能为空(并且在“nb_available”之后立即发出“read”命令给我数据,没有阻塞)。

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

我不想将@async用于上述最简单的情况。

谁知道,如何在非阻塞模式下从TCP套接字读取,当我可以确定某种方式时,读取缓冲区是否包含任何数据或者/和/或tcp客户端发出的下一次读取是否会阻止整个客户端进程或者没有

朱莉娅是否有可能没有“绿色线程”使用?

1 个答案:

答案 0 :(得分:2)

由于没有人提供“官方”解决方案,这里是我上面提到的解决方法。

<强>功能

# Causes stagnant 'nb' count to be updated.
# Note asynchronous nature; this means refresh may not yet have occurred 
# when function has exited. 
function refreshBufsize(s)
  @async eof(s);
  return nothing;
end;

# Check if socket is blocked (refresh bytecount first)
# Note, since refresh is asynchronous, may misreport 'blockage' until
# 'refresh' operation is actually finished; however, if socket is actually
# unblocked, subsequent calls of this function will eventually properly
# report socket is not blocked, and in general, misreporting blockage once 
# or twice when socket is actually free is probably acceptable (rather 
# than other way round).
function isblocked(s)
  refreshBufsize(s)
  return nb_available(s) == 0;
end;

# Peek contents of socket without consuming stream
function peek(s, nb)
  refreshBufsize(s)
  s.buffer.seekable = true;
  Out = read(s.buffer, nb);
  seekstart(s.buffer);
  s.buffer.seekable = false
  return Out
end;

示例:(控制台输出表示为“#&gt;”注释,适用于可复制的代码)

server = listen(9001); 
sOut   = connect(9001); 
sIn    = accept(server);

nb_available(sIn)       
#> 0
isblocked(sIn)          
#> true
refreshBufsize(sIn); # we expect no change, as we haven't written anything yet
isblocked(sIn)          
#> true
write(sOut, "Greetinks and salutations!\n")  
#> 27
write(sOut, "We would be honoured if you would join us.\n") 
#> 43
refreshBufsize(sIn);
isblocked(sIn) # note: may say true at first (until refresh properly finished)
#> false
nb_available(sIn) 
#> 27
String( peek( sIn, 10)) # peek socket contents without consuming
#> "Greetinks "
String( read( sIn, nb_available( sIn))) # read (consume) as normal
#> "Greetinks and salutations!\n"
nb_available(sIn) # note 0 even though second buffer awaiting. needs refresh!
#> 0
isblocked(sIn) # note: called "refresh" under the hood 
               # (but keep async in mind, i.e. might say 'true' at first!)
#> false
nb_available(sIn)
#> 43
String( read( sIn, nb_available( sIn)))
#> "We would be honoured if you would join us.\n"
isblocked(sIn)
#> true

编辑:进行比较,一个更典型的“异步”套接字会话(通常依赖对这种“阻塞”行为)可能看起来像这样:

server = listen(9002);
sOut   = connect(9002);
sIn    = accept(server);

TaskRef = @async try 
  while true
    In = String(readavailable(sIn));
    if !isempty(In); println("Received from server: $In"); else; break; end
  end
  println("Connection closed normally");
catch E
  println("Connection closed (with status $E)");
end;

write(sOut, "Stop repeating everything I say!\n");
#> Received from server: Stop repeating everything I say!

close(sIn)
#> Connection closed normally