julia:网络和流(完结)

网络和流


Julia提供了一个丰富的接口来处理诸如终端、管道和TCP套接字等流I/O对象。这个接口虽然在系统级别上是异步的,但它是以同步的方式呈现给程序员的,通常不需要考虑底层的异步操作,这是通过大量使用Julia协作线程(Coroutine)功能来实现的。

基础流 I/O


所有Julia stream都暴露了read和write方法,将stream作为它们的第一个参数,如:

julia> write(stdout, "Hello World");  # suppress return value 11 with ;
Hello World
julia> read(stdin, Char)

'\n': ASCII/Unicode U+000a (category Cc: Other, control)

在这里,Enter被再次按下,这样Julia就可以读取换行符了。现在,正如您从这个例子中可以看到的,写以数据写作为它的第二个参数,而read则将要读取的数据类型作为第二个参数。

例如,要读取一个简单的字节数组,我们可以这样做:

julia> x = zeros(UInt8, 4)
4-element Array{UInt8,1}:
 0x00
 0x00
 0x00
 0x00

julia> read!(stdin, x)
abcd
4-element Array{UInt8,1}:
 0x61
 0x62
 0x63
 0x64

但是,由于这有点麻烦,所以提供了几种方便的方法。例如,我们可以将上面的内容写成:

julia> read(stdin, 4)
abcd
4-element Array{UInt8,1}:
 0x61
 0x62
 0x63
 0x64

或者如果我们想读整句话的话:

julia> readline(stdin)
abcd
"abcd"

请注意,根据您的终端设置,TTY可能是行缓冲的,因此在将数据发送给Julia之前可能需要一个额外的Enter。

要读取stdin中的每一行,可以使用每一行:

for line in eachline(stdin)
    print("Found $line")
end

或者,如果您想按字符阅读,请阅读:

while !eof(stdin)
    x = read(stdin, Char)
    println("Found: $x")
end

文本I/O


请注意,上面提到的写入方法对二进制流进行操作。特别地,值不被转换成任何规范文本表示,而是按如下方式写成:

julia> write(stdout, 0x61);  # suppress return value 1 with ;
a

注意,a被写函数写到stdout,返回的值是1(因为0x61是一个字节)。

对于文本I/o,根据需要使用print或Show方法(请参阅这两种方法的文档,详细讨论它们之间的差异):

julia> print(stdout, 0x61)
97

有关如何为自定义类型实现显示方法的更多信息,请参见自定义漂亮打印。

IO输出上下文属性


有时候io输出可以从将上下文信息传递到显示方法的能力中获益。ioContext对象提供了将任意元数据与io对象关联的框架。例如,:Compact=>true向io对象添加了一个提示参数,被调用的Show方法应该打印一个较短的输出(如果适用的话)。参见ioContext文档中的公共属性列表。

处理文件


与许多其他环境一样,Julia有一个OPEN函数,它接受一个文件名,并返回一个iostream对象,您可以使用该对象从文件中读取和写入内容。例如,如果我们有一个文件hello.txt,其内容是Hello,world!:

julia> f = open("hello.txt")
IOStream(<file hello.txt>)

julia> readlines(f)
1-element Array{String,1}:
 "Hello, World!"

如果您想要写入一个文件,您可以使用写(“w”)标志打开它:

julia> f = open("hello.txt","w")
IOStream(<file hello.txt>)

julia> write(f,"Hello again.")
12

如果此时检查hello.txt的内容,就会注意到它是空的;实际上还没有写到磁盘。这是因为在写到磁盘之前,iostream必须关闭:

julia> close(f)

再次检查hello.txt将显示其内容已经更改。

打开一个文件,对它的内容做一些事情,然后再次关闭它是一种非常常见的模式。为了使这更容易,存在另一个OPEN调用,它将函数作为其第一个参数,文件名作为其第二个参数,打开该文件,以该文件作为参数调用该函数,然后再次关闭它。例如,给定一个函数:

function read_and_capitalize(f::IOStream)
    return uppercase(read(f, String))
end

你可以打调用:

julia> open(read_and_capitalize, "hello.txt")
"HELLO AGAIN."

若要打开Helo.txt,请在其上调用Read和Syb,关闭Helo.txt并返回大写内容。

为了避免定义命名函数,您可以使用DO语法,它动态地创建一个匿名函数:

julia> open("hello.txt") do f
           uppercase(read(f, String))
       end
"HELLO AGAIN."

一个简单的TCP示例


让我们马上来看一个包含TCP套接字的简单例子。这个功能在一个标准的套接字包中,称为套接字。让我们先创建一个简单的服务器:

julia> using Sockets

julia> @async begin
           server = listen(2000)
           while true
               sock = accept(server)
               println("Hello World\n")
           end
       end
Task (runnable) @0x00007fd31dc11ae0

对于那些熟悉unix套接字api的人来说,方法名会比较熟悉,虽然它们的使用比原始unix套接字api稍微简单一些。在这种情况下,第一个侦听调用将创建一个服务器,等待指定端口(2000)上的传入连接。同样的功能也可以用来创建各种其他类型的服务器:

julia> listen(2000) # Listens on localhost:2000 (IPv4)
Base.TCPServer(active)

julia> listen(ip"127.0.0.1",2000) # Equivalent to the first
Base.TCPServer(active)

julia> listen(ip"::1",2000) # Listens on localhost:2000 (IPv6)
Base.TCPServer(active)

julia> listen(IPv4(0),2001) # Listens on port 2001 on all IPv4 interfaces
Base.TCPServer(active)

julia> listen(IPv6(0),2001) # Listens on port 2001 on all IPv6 interfaces
Base.TCPServer(active)

julia> listen("testsocket") # Listens on a UNIX domain socket
Base.PipeServer(active)

julia> listen("\\\\.\\pipe\\testsocket") # Listens on a Windows named pipe
Base.PipeServer(active)

请注意,上一次调用的返回类型是不同的。这是因为此服务器不监听TCP,而是侦听命名管道(Windows)或Unix域套接字。还请注意,Windows命名管道格式必须是特定的模式,因此名称前缀(.PIPE)唯一地标识文件类型。与接受和连接方法有关。接受方法检索到我们刚刚创建的服务器上连接的客户端的连接,而连接函数使用指定的方法连接到服务器。连接函数接受与侦听相同的参数,因此,假设环境(即主机、CWD等)是相同的,则应该能够将相同的参数传递给Conn。

julia> connect(2000)
TCPSocket(open, 0 bytes waiting)

julia> Hello World

正如我们所预期的那样,我们看到了“Hello world”打印。那么,让我们实际分析场景后面发生了什么。当我们调用CONNECT时,我们连接到刚才创建的服务器。同时,Accept函数返回到新创建的套接字的服务器端连接,并打印“hello world”以表示连接是成功的。

Julia的一个很大的优点是,由于API是同步公开的,即使I/O实际上是异步发生的,所以我们不必担心回调,甚至不需要确保服务器运行。当我们调用CONNECT当前任务时,等待连接被建立,然后才继续执行。在这个暂停中,服务器任务恢复执行(因为(连接请求现在可用),接受连接,打印消息并等待下一个客户端。读写工作以同样的方式进行。要查看这一点,请考虑以下简单的回显服务器:

julia> @async begin
           server = listen(2001)
           while true
               sock = accept(server)
               @async while isopen(sock)
                   write(sock, readline(sock, keep=true))
               end
           end
       end
Task (runnable) @0x00007fd31dc12e60

julia> clientside = connect(2001)
TCPSocket(RawFD(28) open, 0 bytes waiting)

julia> @async while isopen(clientside)
           write(stdout, readline(clientside, keep=true))
       end
Task (runnable) @0x00007fd31dc11870

julia> println(clientside,"Hello World from the Echo Server")
Hello World from the Echo Server

与其他流一样,请使用“关闭”断开套接字:

julia> close(clientside)

解析IP地址


没有遵循侦听方法的连接方法之一是CONNECT(主机:String,port),它将尝试连接到端口参数给出的端口上的主机参数。它允许您执行以下操作:

julia> connect("google.com", 80)
TCPSocket(RawFD(30) open, 0 bytes waiting)

此功能的基础是getaddrinfo,它将执行适当的地址解析:

julia> getaddrinfo("google.com")
ip"74.125.226.225"

完结于 2018-08-30 22:24

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值