Ruby TCP Socket 생성 및 논블록 send/recv

ruby 클라이언트 소켓 생성 및 connect

require 'socket'

tcp_socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
tcp_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
sockaddr_server = Socket.sockaddr_in(9000, "127.0.0.1")

begin
    tcp_socket.connect(sockaddr_server)
end

윈도우 mkxp-z 3.1.3 버전에서 Socket#connect_nonblock 을 쓰려고 시도했으나, 지원하지 않는 메서드라고 에러를 띄웠다. 이러면 connect 시에는 블록되는 상황을 마주할 수밖에 없다. 매우 아쉬운 부분이다. 


ruby 논블록 send

begin
    tcp_socket.write_nonblock("안녕 client #{$count}")
rescue IO::WaitReadable => e # the socket is marked as nonblocking and the connection cannot be completed immediately
    print("WaitReadable")
end

1. plain (15 bytes)

tcp_socket.write_nonblock("안녕 client #{$count}")

0000   98 83 89 7b 5f 29 34 7d f6 a0 02 d0 08 00 45 00   ...{_)4}......E.
0010   00 37 aa a3 40 00 80 06 18 5d c0 a8 db 01 c0 a8   .7..@....]......
0020   db 6d e6 71 23 28 33 83 24 ab 08 40 22 ea 50 18   .m.q#(3.$..@".P.
0030   00 ff 58 99 00 00 ec 95 88 eb 85 95 20 63 6c 69   ..X......... cli
0040   65 6e 74 20 30                                    ent 0

2. utf-8 (15 bytes)

tcp_socket.write_nonblock("안녕 client #{$count}".encode("utf-8"))

0000   80 ca 4b 77 bf 16 98 83 89 7b 5f 29 08 00 45 00   ..Kw.....{_)..E.
0010   00 37 0a 0e 40 00 80 06 00 00 c0 a8 db 6d c0 a8   .7..@........m..
0020   db 01 23 28 e6 55 1f cb 89 df 1e 45 d1 ca 50 18   ..#(.U.....E..P.
0030   04 02 37 ea 00 00 ec 95 88 eb 85 95 20 63 6c 69   ..7......... cli
0040   65 6e 74 20 30                                    ent 0

3. utf-16 (24 bytes)

tcp_socket.write_nonblock("안녕 client #{$count}".encode("utf-16"))

0000   98 83 89 7b 5f 29 34 7d f6 a0 02 d0 08 00 45 00   ...{_)4}......E.
0010   00 40 ab 12 40 00 80 06 17 e5 c0 a8 db 01 c0 a8   .@..@...........
0020   db 6d e6 73 23 28 bb 93 42 1f 2a 2a d6 44 50 18   .m.s#(..B.**.DP.
0030   00 ff f6 a9 00 00 fe ff c5 48 b1 55 00 20 00 63   .........H.U. .c
0040   00 6c 00 69 00 65 00 6e 00 74 00 20 00 30         .l.i.e.n.t. .0


반면에 IO#write_nonblock 메서드는 사용할 수 있었다.
먼저 Socket 인스턴스를 만들고, 논블록 send 동작을 위해 위 메소드를 사용했다.

WireShark로 패킷 캡쳐를 했을 때 1번 plain과 2번 utf-8 버전을 보면 페이로드가 동일한 것을 보니, 기본적으로 루비 문자열은 utf-8로 인코딩을 하는 것을 알 수 있다.

ruby 논블록 recv

$str = String.new("", capacity: 4096)
begin
    tcp_socket.read_nonblock(4096, $str)
    print($str)
rescue IO::WaitReadable => e
    print("WaitReadable")
end

댓글