Julia 提供了一个丰富的接口处理终端、管道、tcp套接字等等I/O流对象。
接口在系统层的实现是异步的,开发者以同步的方式调用该接口、一般无需关注底层异步实现。 接口实现主要基于Julia支持的协程(coroutine)功能。
所有 Julia 流都至少提供一个 read
和一个 write
方法,且第一个参数都是流对象,例如:
julia> write(STDOUT,"Hello World") |
Hello World |
julia> read(STDIN,Char) |
'\n' |
write
方法的第二个参数是将要写入的数据,read
方法的第二个参数是即将读入的数据类型。例如,要读入一个简单的字节数组,我们可以:
julia> x = zeros(Uint8,4) |
4-element Uint8 Array: |
0x00 |
0x00 |
0x00 |
0x00 |
julia> read(STDIN,x) |
abcd |
4-element Uint8 Array: |
0x61 |
0x62 |
0x63 |
0x64 |
julia> readbytes(STDIN,4) |
abcd |
4-element Uint8 Array: |
0x61 |
0x62 |
0x63 |
0x64 |
julia> readline(STDIN) |
abcd |
"abcd\n" |
注意上面提到的写方法是对二进制流进行操作的。特别是,值不会被转换成任何规范的文本表示,而是会被写成如下:
julia> write(STDOUT,0x61) |
a |
julia> print(STDOUT,0x61) |
97 |
让我们直接用一个简单的 Tcp Sockets 的示例来说明。我们首先需要创建一个简单地服务器:
julia> @async begin |
server = listen(2000) |
while true |
sock = accept(server) |
println("Hello World\n") |
end |
end |
Task |
julia> |
julia> listen(2000) # Listens on localhost:2000 (IPv4) |
TcpServer(active) |
julia> listen(ip"127.0.0.1",2000) # Equivalent to the first |
TcpServer(active) |
julia> listen(ip"::1",2000) # Listens on localhost:2000 (IPv6) |
TcpServer(active) |
julia> listen(IPv4(0),2001) # Listens on port 2001 on all IPv4 interfaces |
TcpServer(active) |
julia> listen(IPv6(0),2001) # Listens on port 2001 on all IPv6 interfaces |
TcpServer(active) |
julia> listen("testsocket") # Listens on a domain socket/named pipe |
PipeServer(active) |
他们的不同之处非常微小,并且与他们的接收和连接方法有关系。
接受方法会检索一个到客户端的连接,连接到我们刚刚创建的服务器端,而连接到服务器的函数使用的是特定的方法。连接方法和监听方法的参数是一样的,所以使用的环境(比如主机,cwd 等等)能够传递和监听方法相同的参数来建立一个连接。所以让我们来尝试一下(前提是已经创建好上面的服务器):
julia> connect(2000) |
TcpSocket(open, 0 bytes waiting) |
julia> Hello World |
正如我们预期的那样,我们会看到 “Hello World” 被打印出来了。所以我让我们分析一下在后台发生了什么。当我们调用连接函数时,我们连接到了我们刚刚创建的服务器。
同时,接收方法返回一个服务器端的连接到最新创建的套接字上,然后打印 “Hello World” 来表明连接成功了。
Julia 的一个强大功能是尽管 I/O 实际上是异步发生的,但 API 仍然是同步的,我们甚至不必担心回调或服务器是否继续正常运行。
当我们调用连接时,当前任务会等待连接建立,并且在连接建立之后,当前任务才会继续执行。在暂停期间,服务器任务会恢复执行(因为现在一个连接请求可用),接受这个连接,打印出信息并且等待下一个客户端。读和写的工作是相同的。为了更好地理解,请看以下一个简单的 echo 服务器:
julia> @async begin |
server = listen(2001) |
while true |
sock = accept(server) |
@async while true |
write(sock,readline(sock)) |
end |
end |
end |
Task |
julia> clientside=connect(2001) |
TcpSocket(open, 0 bytes waiting) |
julia> @async while true |
write(STDOUT,readline(clientside)) |
end |
julia> println(clientside,"Hello World from the Echo Server") |
julia> Hello World from the Echo Server |
一种不伴随监听方法的 connect 函数为 connect(host::ASCIIString,port),它会尝试去连接到主机端口参数给出的端口提供的主机参数给出的主机。它允许你如下操作:
julia> connect("google.com",80) |
TcpSocket(open, 0 bytes waiting) |
julia> getaddrinfo("google.com") |
IPv4(74.125.226.225) |