Asynchronous 如何在不阻塞的情况下读取套接字

Asynchronous 如何在不阻塞的情况下读取套接字,asynchronous,socket.io,julia,Asynchronous,Socket.io,Julia,我在处理服务器时遇到问题,向我发送初始的“问候邮件头”(smtp服务器): 在发送任何命令和从服务器接收任何答案之前,我需要阅读此标题,但我不知道如何执行此操作,因为Julia似乎不可能从IO流读取而不阻塞:“读取”命令及其类似项没有任何NB选项,nb_available始终为0,尽管我确切地知道server send me头和我的读取缓冲区不能为空(并且在“nb_available”之后发出的“read”命令会立即向我提供数据,而不会阻塞) 我不想将@async用于上述最简单的情况 谁知道,如

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

在发送任何命令和从服务器接收任何答案之前,我需要阅读此标题,但我不知道如何执行此操作,因为Julia似乎不可能从IO流读取而不阻塞:“读取”命令及其类似项没有任何NB选项,nb_available始终为0,尽管我确切地知道server send me头和我的读取缓冲区不能为空(并且在“nb_available”之后发出的“read”命令会立即向我提供数据,而不会阻塞)

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

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


在Julia中不使用“绿色线程”是否可能?

因为还没有人提供“官方”解决方案,下面是我上面提到的解决方法

功能:

#导致更新停滞的“nb”计数。
#注意异步性;这意味着刷新可能尚未发生
#当函数退出时。
函数刷新bufsize(个)
@异步eof;
一无所获;
结束;
#检查套接字是否被阻止(首先刷新字节数)
#注意,由于刷新是异步的,因此可能会误报“阻塞”,直到
#“刷新”操作实际完成;然而,如果套接字实际上是
#如果未阻止,则此函数的后续调用最终将正确执行
#报告插座未堵塞,一般情况下,误报堵塞一次
#当套接字实际空闲时,两次或两次可能是可以接受的(而不是
#而不是相反)。
功能被阻止(个)
刷新bufsize(s)
返回可用的nb_==0;
结束;
#在不使用流的情况下查看套接字的内容
功能peek(s、nb)
刷新bufsize(s)
s、 buffer.seekable=true;
输出=读取(s.缓冲器,nb);
seekstart(s.buffer);
s、 buffer.seekable=false
返回
结束;
示例:(控制台输出表示为“#>”注释,用于复制可复制代码)

server=listen(9001);
sOut=连接(9001);
sIn=接受(服务器);
nb_可用(sIn)
#> 0
isblocked(sIn)
#>真的
刷新bufsize(sIn);#我们希望没有变化,因为我们还没有写任何东西
isblocked(sIn)
#>真的
写(sOut,“问候和问候!\n”)
#> 27
写(sOut,“如果您能加入我们,我们将不胜荣幸。\n”)
#> 43
刷新bufsize(sIn);
isblocked(sIn)#注意:开始时可能会说true(直到刷新正确完成)
#>假的
nb_可用(sIn)
#> 27
字符串(peek(sIn,10))#在不消耗任何资源的情况下查看套接字内容
#>“格林廷克斯”
字符串(读取(sIn,NBU可用(sIn)))#正常读取(消耗)
#>“问候和问候!\n”
nb_可用(sIn)#注意0,即使第二个缓冲区正在等待。需要刷新!
#> 0
isblocked(sIn)#注意:在引擎盖下称为“刷新”
#(但要记住异步,也就是说,一开始可能会说‘true’)
#>假的
nb_可用(sIn)
#> 43
字符串(读取(sIn,nb_可用(sIn)))
#>“如果您能加入我们,我们将不胜荣幸。\n”
isblocked(sIn)
#>真的
编辑:比较而言,更典型的“异步”套接字会话(通常依赖于这种“阻塞”行为)可能如下所示:

server=listen(9002);
sOut=connect(9002);
sIn=接受(服务器);
TaskRef=@async try
虽然是真的
In=字符串(readavailable(sIn));
如果!i空(In);println(“从服务器接收:$In”);其他的打破结束
结束
println(“连接正常关闭”);
抓住E
println(“连接已关闭(状态为$E)”;
结束;
写(sOut,“不要重复我说的每句话!\n”);
#>从服务器收到:停止重复我所说的一切!
关闭(sIn)
#>连接正常关闭

我看不到任何功能允许您使用
MSG\u DONTWAIT
MSG\u PEEK
标记
recv
等,如果这是您的意思的话。唉,
@async
似乎是实现这一目标的途径。(如果我错了,很高兴被纠正)不是100%的“绿色线程”,但作为一种解决方法,我注意到在
nb\u available
之前执行
@async eof(socket)
似乎会更新其计数(也
socket.buffer.size
),使其可用(例如,检查下一条指令是否会阻塞)。此外,如果您想在不“花费”套接字缓冲区的情况下使用它,以便可以在不使用它们的情况下“窥视”传入消息,则可以将
socket.buffer.seekable
设置为true,并直接将读取/寻道设置为
socket.buffer
。请记住在完成后将其返回到
false
,这样您就可以再次直接从套接字读取。我假设这些是bug或必要的套接字错误,所以我不会假装这是可靠的建议。不过现在看来还不错。塔索斯,谢谢你的回答!我理解你的意思,但现在我无法想象,如何实现一些用于异步读写的通用库代码:我必须等待isblocked(sIn)=false并调用一些回调来从套接字读取一些数据,但这会导致(可能很短)轮询,如while
isblocked(sIn);;结束
:(如何避免?再次感谢!@drvtiny-hahah,好吧,我上面回答的全部要点是提供一个“单线程”基于轮询的解决方案,因为您说过希望避免异步执行!否则,是的,我同意,执行此操作的最佳方法确实是异步的!如果您愿意,我可以使用从套接字读取的典型异步方法更新我的答案?再次非常感谢您,Tasos!!
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