Asynchronous 如何在不阻塞的情况下读取套接字
我在处理服务器时遇到问题,向我发送初始的“问候邮件头”(smtp服务器): 在发送任何命令和从服务器接收任何答案之前,我需要阅读此标题,但我不知道如何执行此操作,因为Julia似乎不可能从IO流读取而不阻塞:“读取”命令及其类似项没有任何NB选项,nb_available始终为0,尽管我确切地知道server send me头和我的读取缓冲区不能为空(并且在“nb_available”之后发出的“read”命令会立即向我提供数据,而不会阻塞) 我不想将@async用于上述最简单的情况 谁知道,如何在非阻塞模式下从TCP套接字读取,当我可以确定某种方式时,读取缓冲区是否包含任何数据或否,和/或TCP客户端发出的下一次读取是否会阻塞整个客户端进程或否Asynchronous 如何在不阻塞的情况下读取套接字,asynchronous,socket.io,julia,Asynchronous,Socket.io,Julia,我在处理服务器时遇到问题,向我发送初始的“问候邮件头”(smtp服务器): 在发送任何命令和从服务器接收任何答案之前,我需要阅读此标题,但我不知道如何执行此操作,因为Julia似乎不可能从IO流读取而不阻塞:“读取”命令及其类似项没有任何NB选项,nb_available始终为0,尽管我确切地知道server send me头和我的读取缓冲区不能为空(并且在“nb_available”之后发出的“read”命令会立即向我提供数据,而不会阻塞) 我不想将@async用于上述最简单的情况 谁知道,如
在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并调用一些回调来从套接字读取一些数据,但这会导致(可能很短)轮询,如whileisblocked(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