RingLibuv の用法

RingLibuv の用法です。

注釈

RingLibuv の用法は ring/extensions/ringlibuv フォルダを参照してください。

ライブラリのウェブサイトからの情報: http://libuv.org/

Libuv は非同期 I/O に主眼を置いたマルチプラットフォーム対応ライブラリです。

特筆すべき機能

  • epoll, kqueue, IOCP, イベントポートによる完全機能のイベントループへの対応。

  • 非同期 TCP および UDP ソケット

  • 非同期 DNS 解決

  • 非同期ファイル、およびファイルシステム操作

  • ファイルシステムのイベント

  • TTY 制御による ANSI エスケープコード

  • Unix ドメインソケットまたは名前つきパイプ (Windows) による IPC ソケット共有

  • 子プロセス

  • スレッドプール

  • シグナル処理

  • 高分解能クロック

  • スレッド処理と同期基本命令

RingLibuv によるはじめてのアプリケーション

用例:

load "libuv.ring"

func main

        myloop = new_uv_loop_t()
        uv_loop_init(myloop)
        ? "Now quitting"
        uv_run(myloop, UV_RUN_DEFAULT)
        uv_loop_close(myloop)
        destroy_uv_loop_t(myloop)

実行結果:

Now quitting

イベントループ

用例:

load "libuv.ring"

counter = 0
idler = NULL

func main
        idler = new_uv_idle_t()
        uv_idle_init(uv_default_loop(), idler)
        uv_idle_start(idler, "wait()")
        ? "Idling..."
        uv_run(uv_default_loop(), UV_RUN_DEFAULT);
        uv_loop_close(uv_default_loop());
        destroy_uv_idle_t(idler)

func wait
        counter++
        if counter >= 100000
                uv_idle_stop(idler)
        ok

実行結果:

Idling...

サーバーの用例

用例:

load "libuv.ring"

? "Testing RingLibuv - Server Side"

DEFAULT_PORT    = 13370
DEFAULT_BACKLOG = 1024

addr    = new_sockaddr_in()
server  = NULL
client  = NULL
myloop  = NULL

func main
        myloop = uv_default_loop()
        server = new_uv_tcp_t()
        uv_tcp_init(myloop, server)
        uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
        uv_tcp_bind(server, addr, 0)
        r = uv_listen(server, DEFAULT_BACKLOG, "newconnection()")
        if r
                ? "Listen error " + uv_strerror(r)
                return 1
        ok
        uv_run(myloop, UV_RUN_DEFAULT)
        destroy_uv_tcp_t(server)
        destroy_uv_sockaddr_in(addr)

func newconnection
        ? "New Connection"
        aPara   = uv_Eventpara(server,:connect)
        nStatus = aPara[2]
        if nStatus < 0
                ? "New connection error : " + nStatus
                return
        ok
        client = new_uv_tcp_t()
        uv_tcp_init(myloop, client)
        if uv_accept(server, client) = 0
                        uv_read_start(client, uv_myalloccallback(), "echo_read()")
        ok

func echo_read
        aPara = uv_Eventpara(client,:read)
        nRead = aPara[2]
        buf   = aPara[3]
        if nRead > 0
                req = new_uv_write_t()
                        wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread)
                uv_write(req, client, wrbuf, 1, "echo_write()")
                ? uv_buf2str(wrbuf)
                message = "message from the server to the client"
                buf = new_uv_buf_t()
                set_uv_buf_t_len(buf,len(message))
                set_uv_buf_t_base(buf,varptr("message",:char))
                uv_write(req, client, buf, 1, "echo_write()")
        ok

func echo_write
        aPara = uv_Eventpara(client,:read)
        req   = aPara[1]

実行結果:

クライアントを実行すると、“New Connection”メッセージが表示されます。

そして “hello from the client” メッセージが表示されます。

Testing RingLibuv - Server Side
New Connection
hello from the client

クライアントの用例

用例:

load "libuv.ring"

? "Testing RingLibuv - Client Side"

DEFAULT_PORT    = 13370
DEFAULT_BACKLOG = 1024

addr    = new_sockaddr_in()
connect = NULL
buffer  = null
socket  = null

func main
        myloop  = uv_default_loop()
        Socket  = new_uv_tcp_t()
        connect = new_uv_connect_t()
        uv_tcp_init(myloop, Socket)
        uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
        uv_tcp_connect(connect,Socket, addr, "connect()")
        uv_run(myloop, UV_RUN_DEFAULT)
        destroy_uv_tcp_t(socket)
        destroy_uv_connect_t(connect)

func connect
        ? "Client: Start Connection"
        aPara   = uv_Eventpara(connect,:connect)
        req     = aPara[1]
        nStatus = aPara[2]
        if nStatus = -1
                ? "Error : on_write_end "
                return
        ok
        buf = new_uv_buf_t()
        message = "hello from the client"
        set_uv_buf_t_len(buf,len(message))
        set_uv_buf_t_base(buf,varptr("message",:char))
        tcp       = get_uv_connect_t_handle(req)
        write_req = new_uv_write_t()
        buf_count = 1
        uv_write(write_req, tcp, buf, buf_count, "on_write_end()")

func on_write_end
                uv_read_start(socket, uv_myalloccallback(), "echo_read()")

func echo_read
        aPara = uv_Eventpara(socket,:read)
        nRead = aPara[2]
        buf   = aPara[3]
        if nRead > 0
                        wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread);
                ? uv_buf2str(wrbuf)
        ok

実行結果:

サーバーの後にクライアントを実行します。

Testing RingLibuv - Client Side
Client: Start Connection
hello from the client
message from the server to the client

クラスによるサーバーの用例

用例:

load "libuv.ring"
load "objectslib.ring"

? "Testing RingLibuv - Server Side - Using Classes"

open_object(:MyServer)

class MyServer from ObjectControllerParent

        DEFAULT_PORT    = 13370
        DEFAULT_BACKLOG = 1024

        addr    = new_sockaddr_in()
        server  = NULL
        client  = NULL
        myloop  = NULL

        func start
                myloop = uv_default_loop()
                server = new_uv_tcp_t()
                uv_tcp_init(myloop, server)
                uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
                uv_tcp_bind(server, addr, 0)
                r = uv_listen(server, DEFAULT_BACKLOG, Method(:newconnection) )
                if r
                        ? "Listen error " + uv_strerror(r)
                        return 1
                ok
                uv_run(myloop, UV_RUN_DEFAULT)
                destroy_uv_tcp_t(server)
                destroy_uv_sockaddr_in(addr)

        func newconnection
                ? "New Connection"
                aPara   = uv_Eventpara(server,:connect)
                nStatus = aPara[2]
                if nStatus < 0
                        ? "New connection error : " + nStatus
                        return
                ok
                client = new_uv_tcp_t()
                uv_tcp_init(myloop, client)
                if uv_accept(server, client) = 0
                                uv_read_start(client, uv_myalloccallback(),
                                                        Method(:echo_read))
                ok

        func echo_read
                aPara = uv_Eventpara(client,:read)
                nRead = aPara[2]
                buf   = aPara[3]
                if nRead > 0
                        req = new_uv_write_t()
                                wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread)
                        uv_write(req, client, wrbuf, 1, Method(:echo_write))
                        ? uv_buf2str(wrbuf)
                        message = "message from the server to the client"
                        buf = new_uv_buf_t()
                        set_uv_buf_t_len(buf,len(message))
                        set_uv_buf_t_base(buf,varptr("message",:char))
                        uv_write(req, client, buf, 1, Method(:echo_write))
                ok

        func echo_write
                aPara = uv_Eventpara(client,:read)
                req   = aPara[1]

実行結果:

クライアントを実行すると、“New Connection”メッセージが表示されます。

そして“hello from the client”メッセージが表示されます。

Testing RingLibuv - Server Side - Using Classes
New Connection
hello from the client

クラスによるクライアントの用例

用例:

load "libuv.ring"
load "objectslib.ring"

? "Testing RingLibuv - Client Side - Using Classes"

open_object(:MyClient)

Class MyClient from ObjectControllerParent

        DEFAULT_PORT    = 13370
        DEFAULT_BACKLOG = 1024

        addr    = new_sockaddr_in()
        connect = NULL
        buffer  = null
        socket  = null

        func start
                myloop  = uv_default_loop()
                Socket  = new_uv_tcp_t()
                connect = new_uv_connect_t()
                uv_tcp_init(myloop, Socket)
                uv_ip4_addr("127.0.0.1", DEFAULT_PORT, addr)
                uv_tcp_connect(connect,Socket, addr, Method(:connect))
                uv_run(myloop, UV_RUN_DEFAULT)
                destroy_uv_tcp_t(socket)
                destroy_uv_connect_t(connect)

        func connect
                ? "Client: Start Connection"
                aPara   = uv_Eventpara(connect,:connect)
                req     = aPara[1]
                nStatus = aPara[2]
                if nStatus = -1
                        ? "Error : on_write_end "
                        return
                ok
                buf = new_uv_buf_t()
                message = "hello from the client"
                set_uv_buf_t_len(buf,len(message))
                set_uv_buf_t_base(buf,varptr("message",:char))
                tcp       = get_uv_connect_t_handle(req)
                write_req = new_uv_write_t()
                buf_count = 1
                uv_write(write_req, tcp, buf, buf_count, Method(:on_write_end))

        func on_write_end
                        uv_read_start(socket, uv_myalloccallback(), Method(:echo_read))

        func echo_read
                aPara = uv_Eventpara(socket,:read)
                nRead = aPara[2]
                buf   = aPara[3]
                if nRead > 0
                                wrbuf = uv_buf_init(get_uv_buf_t_base(buf), nread);
                        ? uv_buf2str(wrbuf)
                ok

実行結果:

サーバーの後にクライアントを実行します。

Testing RingLibuv - Client Side - Using Classes
Client: Start Connection
hello from the client
message from the server to the client

スレッドの用例

用例:

load "libuv.ring"

? "Testing RingLibuv - Threads"

func main
        one_id = new_uv_thread_t()
        two_id = new_uv_thread_t()
        uv_thread_create(one_id, "one()")
        uv_thread_create(two_id, "two()")
        uv_thread_join(one_id)
        uv_thread_join(two_id)
        destroy_uv_thread_t(one_id)
        destroy_uv_thread_t(two_id)

func one
        ? "Message from the First Thread!"

func two
        ? "Message from the Second Thread!"

実行結果:

Testing RingLibuv - Threads
Message from the First Thread!
Message from the Second Thread!

スレッドの用例 - クラスの使用

用例:

load "libuv.ring"
load "objectslib.ring"

? "Testing RingLibuv - Threads - Using Classes"

open_object(:MyThreads)

class MyThreads from ObjectControllerParent

        func Start
                one_id = new_uv_thread_t()
                two_id = new_uv_thread_t()
                uv_thread_create(one_id, Method(:One))
                uv_thread_create(two_id, Method(:Two))
                uv_thread_join(one_id)
                uv_thread_join(two_id)
                destroy_uv_thread_t(one_id)
                destroy_uv_thread_t(two_id)

        func one
                ? "Message from the First Thread!"

        func Two
                ? "Message from the Second Thread!"

実行結果:

Testing RingLibuv - Threads - Using Classes
Message from the First Thread!
Message from the Second Thread!