10日目です。UDP周りについてやっていきます。
サーバ(UDP)
use std::net::UdpSocket; use std::thread; fn main() { let server_socket = UdpSocket::bind("127.0.0.1:12345") .expect("Could not bind socket"); loop { let mut buf = [0u8; 1024]; // クロージャの中に移動されるからクローンする。 let client_socket = server_socket.try_clone().expect("failed to clone socket"); match server_socket.recv_from(&mut buf) { Ok((_, src)) => { thread::spawn(move || { println!("handling data from {}", src); client_socket.send_to(&buf, src).expect("failed to send response"); }); }, Err(e) => { eprintln!("could not recieve a datagram: {}", e); } } } }
UDPの場合はTCPとは異なりlisten
やaccept
のようなものはありません。server_socket
としてサーバーソケットで待ち受け、データを受信したら別スレッドでclient_socket
を利用し受信元にそのまま送り返すといった処理の流れになります。UDPサーバーのくせにクライアントソケット?と思うかもしれませんが、サーバーソケット、クライアントソケットという用語については
ソケットプログラミング HOWTO — Python 3.7.2 ドキュメントが詳しいです。
loopの中にあるsocket.try_clone()
でsocket
と同じアドレス、ポートに対してバインドされたソケットを返却していますが、これはthread::spawn()
に渡すクロージャに対してソケットの所有権が移動してしまうからです。
buf
のサイズとして1024を指定していますが、この値は想定する受信データによって適当に決定します。今回の場合は1024バイトを超えるデータを受信した場合は1025バイト目以降のデータは破棄されます。
クライアント(UDP)
use std::net::UdpSocket; use std::{str, io}; use std::time::Duration; fn main() { let socket = UdpSocket::bind("127.0.0.1:54321").expect("failed to bind socket"); socket.set_read_timeout(Some(Duration::from_secs(2))).unwrap(); socket.set_write_timeout(Some(Duration::from_secs(2))).unwrap(); loop { let mut input = String::new(); io::stdin().read_line(&mut input).unwrap(); socket.send_to(input.as_bytes(), "127.0.0.1:12345").expect("failed to send data"); let mut buffer = [0u8; 1024]; socket.recv_from(&mut buffer).expect("failed to receive"); print!("{}", str::from_utf8(&buffer).expect("failed to convert to String")); } }
UDPはTCPのようにコネクションを張らないので、送受信用のソケットを作成したら宛先(127.0.0.1:12345) に対してデータを送りつけるだけです。