【perl】windowsから日本語をサーバに送信する

Perl

Windows上のPerlから、Ubuntuに日本語入りの文字列を送受信しました。

環境

●サーバ 
 VMware Ubuntu 22.04 ※perl 5.34 インストール済
 IP 192.168.19.129
●クライアント 
 Windows11 HOME ※perl 5.34 でPATHを通してあります
 IP 192.168.19.1

準備

①サーバには(Ubuntu) responce_server.pl を配置
②クライアント(windows)request_client.pl を配置

  

#サーバプログラム responce_server.pl
#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::INET;

# サーバーのIPアドレスとポート番号
my $server_ip = '192.168.19.129';
my $server_port = 12346;

# サーバーを起動してクライアントからの接続を待機
my $server_socket = IO::Socket::INET->new(
    LocalAddr => $server_ip,
    LocalPort => $server_port,
    Proto     => 'tcp',
    Listen    => SOMAXCONN,
    ReuseAddr => 1,
) or die "Error in socket creation: $!\n";

print "Server started, waiting for clients...\n";

# Ctrl+Cで終了するためのシグナルハンドラ
$SIG{INT} = sub {
    print "\nCtrl+C detected. Exiting...\n";
    close($server_socket);
    exit;
};

while (1) {
    my $client_socket = $server_socket->accept();

    while ($client_socket) {
        print "Client connected\n";
        my $client_address = $client_socket->peerhost();

        while (my $message = <$client_socket>) {
            chomp $message;
            last if $message eq 'exit';

            print "Received message ( $client_address > $message )\n";

            # 受け取ったメッセージをクライアントに返信
            print $client_socket "受信済み ( $client_address > $message ) \n";
            print "next message wait\n";
        }
        
        shutdown($client_socket, 2);
        close($client_socket);
        print "Client disconnected\n";

        # 次のクライアント接続を待機
        $client_socket = $server_socket->accept();
    }
}

close($server_socket);
print "\n サーバが停止しました.\n";
# クライアント request_client.pl 
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use Encode;

# サーバーのIPアドレスとポート番号
my $server_ip = '192.168.19.129';
my $server_port = 12346;

# サーバーに接続
my $client_socket = IO::Socket::INET->new(
    PeerAddr => $server_ip,
    PeerPort => $server_port,
    Proto    => 'tcp',
) or die "Error in socket creation: $!\n";


print "message >";
my $message_to_server = <STDIN>;
chomp($message_to_server);
    
#入力 shift-jis 表示 shift-jis ファイル UTF-8
print "Client > " .  $message_to_server."\n";
    
# サーバーにメッセージを送信
if ($^O eq 'MSWin32') {
	print $client_socket shiftjis_to_utf8($message_to_server)."\n";
} else {
	print $client_socket $message_to_server."\n";
}

# サーバーからの応答を受信
my $response = <$client_socket>;
# Windowsの場合、Shift-JISにエンコードしてから表示
if ($^O eq 'MSWin32') {
	$response = utf8_to_shiftjis($response);
} else {
	# $response = encode('utf8', $response);
}

print "Server Responce > $response\n";
close($client_socket);

sub utf8_to_shiftjis {
    my ($utf_string) = @_;
    return encode('cp932', decode('utf-8', $utf_string));
}
sub shiftjis_to_utf8 {
    my ($jis_string) = @_;
    return encode('utf-8', decode('cp932', $jis_string));
}

実行

①サーバの起動
 サーバ上で
  $ > perl responce_server.pl
だけで実行できます。
②クライアントの起動
 クライアント上で
  c:\??\ > perl request_client.pl
で実行できます。
 下は実行した様子です。

 実行するとmessage を入力できます。
 日本語が文字化けしないで表示されています。

 Server Request は、ServerからのRequestを表示しています。
 文字化けしないで値が返ってくることを確認しました。

 サーバプログラムはwhileループを使って実行していたので、シグナルハンドラを使って割り込みで強制終了させることができるようにしました。

注意(サーバプログラムの実行に失敗する方へ)

 サーバプログラムを繰り返し実行していると、実行時に
   Error in socket creaton: Address already in use
と表示され、実行ができなくなることがありますが、
   以前のプロセスが生きており、同じポート番号を開くことができないですよ
というエラーです。
 数分待っていればポートが解放されますが、
   ポート番号を変えて実行するか、生きているプロセスを強制終了する
ことで解決できます。

 ●プロセスの強制終了方法(Ubuntu)
  ターミナルから次のコマンドを入力して終了させます。
   $ > PS
PID TTY TIME CMD
50650 pts/2 00:00:00 bash
60551 pts/2 00:00:00 perl <- perl と書いてあるのが犯人です
60602 pts/2 00:00:00 ps
$ > kill -9 60551 <- プロセス番号でkillします

何度もお世話になりました。