プログラミング

RustでTCP/IP通信を使おう!

こんにちは、MSKです。
今回はRustを使用してTCP/IP通信を行いたいと思います。

動機と関連記事

以前にPythonでTCP/IP通信を試してみました。
今回は最近一番使用しているRustでTCP/IP通信を試してみました。

PythonでTCP/IP通信を使おう!PythonでTCP/IP通信を行います。 TCP/IPの概要を解説して、Pythonで実際の動きをみたいと思います。...

今回は簡単なプログラムを作成します。
サーバーはクライアントから接続されメッセージを受け取ると停止します。
クライアントはサーバーと接続し、メッセージを送信し、レスポンスを受け取ると通信を終了します。

RustでTCPサーバーを作成する

手順は以下になります。

  1. アドレスとポートを指定して、TCPリスナーを作成
  2. TCPストリームをブロッキングに設定(ノンブロッキングだとループ処理など書いて行数が増えるので・・・)
  3. acceptして接続を受け入れる状態にします
  4. 接続が行われたら、recv_lineでデータが送られてくるのを待ちます
  5. データを受信したら、レスポンスを作成しクライアントに送信します

ソースは以下になります。

use std::net::{TcpListener};
use std::io::{BufReader,BufRead,Write};

// アドレスとポートを指定
const SERVER_ADDRESS:&str = "127.0.0.1:8080";

fn main() {
    // TCPリスナーを作成
    let server = TcpListener::bind(SERVER_ADDRESS).expect("failed to start server");
    // ブロッキングに設定
    server.set_nonblocking(false).expect("out of service");
    println!("start server");
    // クライアントを待ち受ける
    if let Ok((client,address)) = server.accept() {
        println!("connect client:{}",address);
        // 次で所有権が移動してしまうためクローン
        let mut socket = client.try_clone().unwrap();
        // データ読み込みのため、BufReaderを使う
        let mut reader = BufReader::new(client);
        //メッセージを待ち受け
        let mut rcv_data = String::new();
        if let Ok(v) =  reader.read_line(&mut rcv_data) {
            if v > 0 {
                // 受信した内容を表示
                println!("server receive {}",rcv_data);
                // クライアントに返信
                let response = String::from(format!("client recv {}",rcv_data)).into_bytes();
                match socket.write_all(&response) {
                    Ok(()) => println!("client response success"),
                    Err(v) => println!("client response failed:{}",v),
                }
            }
        }
    }
    println!("stop server");
}

確認はPythonの時と同様に行います。

RustでTCPクライアントを作成する

次にクライアントを作成します。
手順は以下になります。

  1. 接続するサーバーのアドレスとポートを指定して、ソケットを作成
  2. ブロッキングに設定
  3. メッセージを作成して、サーバーにデータを送信します
  4. レスポンスをサーバーから受信するためにread_lineで待ち受けます

ソースは以下になります。

use std::net::{TcpStream};
use std::io::{BufReader,BufRead,Write};
// アドレスとポートを指定
const SERVER_ADDRESS:&str = "127.0.0.1:8080";

fn main() {
    // サーバーと接続
    let mut sock = TcpStream::connect(SERVER_ADDRESS).expect("failed to connect server");
    // ノンブロッキングに設定
    sock.set_nonblocking(false).expect("out of service");
    println!("connect server");
    // テストメッセージを送信
    let tx_mess = "Hello, TCP\r\n".as_bytes();

    // 実際に送信
    match sock.write_all(tx_mess) {
        Ok(()) => println!("send test message success"),
        Err(v) => println!("send test message failed:{}",v),
    }
    let mut recv_response = String::new();
    // データ読み込みのため、BufReaderを使う
    let mut reader = BufReader::new(sock);
    //サーバーからのレスポンスを待つ
    if let Ok(v) = reader.read_line(&mut recv_response) {
        if v > 0 {
            //レスポンスを表示
            println!("response:{}",recv_response);
        }
    }
}

動作確認のためにまず、1つ上で作ったサーバーを立ち上げます。
次にクライアント側を立ち上げます。

クライアント側から見るとサーバーと接続し、レスポンスを受信できると思います。
サーバーから見ると、acceptから返り、データを受信することが確認できると思います。

まとめ

今回はRustでTCP/IP通信を行ってみました。
Pythonでのプログラムも含め、ただの動作確認程度のものなのであまり面白くないサンプルですが、サーバーとクライアントの動きは確認できたと思います。

TCPサーバーとクライアントの機能を使ってもう少し面白い動きをするサンプルを作って記事にしたいと思います。

最後までご覧頂き、ありがとうございました。
「RustでTCP/IP通信を使おう!」でした。

ABOUT ME
MSK
九州在住の組み込み系エンジニアです。 2児の父親でもあります。 数学やプログラミングが趣味です。 最近Webプログラミングと曲面結び目理論にはまっています。