C#でソケット通信
職場でC#を使うのと、
ソケット通信に興味があるのでちょっと練習してみた。
server側
using System;
public class Server
{
public static void Main()
{
string ipString = "127.0.0.1";
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse(ipString);
int port = 2001;
System.Net.Sockets.TcpListener listener =
new System.Net.Sockets.TcpListener(ipAdd, port);
listener.Start();
Console.WriteLine("Listenを開始しました({0}:{1})。",
((System.Net.IPEndPoint)listener.LocalEndpoint).Address,
((System.Net.IPEndPoint)listener.LocalEndpoint).Port);
System.Net.Sockets.TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("クライアント({0}:{1})と接続しました。",
((System.Net.IPEndPoint)client.Client.RemoteEndPoint).Address,
((System.Net.IPEndPoint)client.Client.RemoteEndPoint).Port);
System.Net.Sockets.NetworkStream ns = client.GetStream();
ns.ReadTimeout = 10000;
ns.WriteTimeout = 10000;
System.Text.Encoding enc = System.Text.Encoding.UTF8;
bool disconnected = false;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] resBytes = new byte[256];
int resSize = 0;
do
{
resSize = ns.Read(resBytes, 0, resBytes.Length);
if (resSize == 0)
{
disconnected = true;
Console.WriteLine("クライアントが切断しました。");
break;
}
ms.Write(resBytes, 0, resSize);
} while (ns.DataAvailable || resBytes[resSize - 1] != '\n');
string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length);
ms.Close();
resMsg = resMsg.TrimEnd('\n');
Console.WriteLine(resMsg);
if (!disconnected)
{
string sendMsg = resMsg.Length.ToString();
byte[] sendBytes = enc.GetBytes(sendMsg + '\n');
ns.Write(sendBytes, 0, sendBytes.Length);
Console.WriteLine(sendMsg);
}
ns.Close();
client.Close();
Console.WriteLine("クライアントとの接続を閉じました。");
listener.Stop();
Console.WriteLine("Listenerを閉じました。");
Console.ReadLine();
}
}
clinent側
using System;
public class Client
{
public static void Main()
{
Console.WriteLine("入力してください");
string sendMsg = Console.ReadLine();
if (sendMsg == null || sendMsg.Length == 0)
{
return;
}
string ipOrHost = "127.0.0.1";
int port = 2001;
System.Net.Sockets.TcpClient tcp =
new System.Net.Sockets.TcpClient(ipOrHost, port);
Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})。",
((System.Net.IPEndPoint)tcp.Client.RemoteEndPoint).Address,
((System.Net.IPEndPoint)tcp.Client.RemoteEndPoint).Port,
((System.Net.IPEndPoint)tcp.Client.LocalEndPoint).Address,
((System.Net.IPEndPoint)tcp.Client.LocalEndPoint).Port);
System.Net.Sockets.NetworkStream ns = tcp.GetStream();
ns.ReadTimeout = 10000;
ns.WriteTimeout = 10000;
System.Text.Encoding enc = System.Text.Encoding.UTF8;
byte[] sendBytes = enc.GetBytes(sendMsg + '\n');
ns.Write(sendBytes, 0, sendBytes.Length);
Console.WriteLine(sendMsg);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] resBytes = new byte[256];
int resSize = 0;
do
{
resSize = ns.Read(resBytes, 0, resBytes.Length);
if (resSize == 0)
{
Console.WriteLine("サーバーが切断しました。");
break;
}
ms.Write(resBytes, 0, resSize);
} while (ns.DataAvailable || resBytes[resSize - 1] != '\n');
string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length);
ms.Close();
resMsg = resMsg.TrimEnd('\n');
Console.WriteLine(resMsg);
ns.Close();
tcp.Close();
Console.WriteLine("切断しました。");
Console.ReadLine();
}
}
mcs client.cs
mcs server.cs
実行
サーバの実行
$ mono server.exe
Listenを開始しました(127.0.0.1:2001)。
クライアントの実行
$ mono client.exe
入力してください
hello world
サーバの反応
クライアント(127.0.0.1:32924)と接続しました。
hello world
11
クライアントとの接続を閉じました。
Listenerを閉じました。
まとめ
TCP通信というのは、IPアドレスとポートの組み合わせ。
だからlocalhost上でポートさえ違えば、通信ができる。
今回は
・サーバ
IP 127.0.0.1
ポート 2001
・クライアント
IP 127.0.0.1
ポート 32924
で通信を行った。
なお、クライアントのポートは通信毎に自動で割り振られる。
netstatでポートがLISTENしているかどうかを調べてみる
$ netstat -anpt
tcp 0 0 127.0.0.1:2001 0.0.0.0:* LISTEN 14145/mono
monoというプロセスが、
2001ポートを使って通信していることがわかる。
-aオプション
LISTEN状態も含むすべてのソケットを表示する。
-nオプション
IPアドレス・ポート番号をそのまま表示する。
これがない場合、ドメイン名として表示されたり、ssh・httpdとか表示されたりする。
-pオプション
通信しているプロセスを表示する。