Skip to content

Instantly share code, notes, and snippets.

@ichiroku11
Last active February 12, 2017 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ichiroku11/75b9166702e07c5945f8ce91b5670a09 to your computer and use it in GitHub Desktop.
Save ichiroku11/75b9166702e07c5945f8ce91b5670a09 to your computer and use it in GitHub Desktop.
.NETでUDP(UdpClient)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace Udp.ConsoleApp {
// オブジェクトとバイト配列の変換
public class ObjectConverter<TObject> {
private readonly IFormatter _formatter;
public ObjectConverter(IFormatter formatter = null) {
_formatter = formatter ?? new BinaryFormatter();
}
// オブジェクト=>バイト配列
public byte[] ToByteArray(TObject obj) {
using (var stream = new MemoryStream()) {
_formatter.Serialize(stream, obj);
return stream.ToArray();
}
}
// バイト配列=>オブジェクト
public TObject FromByteArray(byte[] bytes) {
using (var stream = new MemoryStream(bytes)) {
return (TObject)_formatter.Deserialize(stream);
}
}
}
// クライアント
public class Client<TRequest, TResponse> {
// 送信先のエンドポイント
private readonly IPEndPoint _endpoint;
public Client(IPEndPoint endpoint) {
_endpoint = endpoint;
}
// クライアントを実行する
// リクエストを送信してレスポンスを受信する
public async Task<TResponse> SendAsync(TRequest request) {
// UdpClientを作成するときにはエンドポイントを指定しない
using (var client = new UdpClient()) {
// 1. リクエストを送信
// (送信先のエンドポイントを指定して)
Console.WriteLine($"Client send {nameof(request)}: {request}");
var requestBytes = new ObjectConverter<TRequest>().ToByteArray(request);
await client.SendAsync(requestBytes, requestBytes.Length, _endpoint);
// 2. レスポンスを受信
var result = await client.ReceiveAsync();
// ここで受信した結果のリモートエンドポイントが送信先かをチェックした方がいい気がする
var responseBytes = result.Buffer;
var response = new ObjectConverter<TResponse>().FromByteArray(responseBytes);
Console.WriteLine($"Client receive {nameof(response)}: {response}");
return response;
}
}
}
// サーバ
public class Server<TRequest, TResponse> {
// リクエストを受信するエンドポイント
private readonly IPEndPoint _endpoint;
public Server(IPEndPoint endpoint) {
_endpoint = endpoint;
}
// サーバを実行する
public async Task RunAsync(Func<TRequest, TResponse> processor) {
// リクエストを受信するエンドポイントを指定してUdpClientを作成
using (var client = new UdpClient(_endpoint)) {
while (true) {
// 1. リクエストを受信
var result = await client.ReceiveAsync();
var requestBytes = result.Buffer;
var request = new ObjectConverter<TRequest>().FromByteArray(requestBytes);
Console.WriteLine($"Server receive {nameof(request)}: {request}");
var sender = Task.Run(async () => {
// 2. リクエストからレスポンスを作成
var response = processor(request);
// 3. リクエストの送信元にレスポンスを送信
Console.WriteLine($"Server send {nameof(response)}: {response}");
var responseBytes = new ObjectConverter<TResponse>().ToByteArray(response);
await client.SendAsync(responseBytes, responseBytes.Length, result.RemoteEndPoint);
});
// Taskの管理やエラー処理は省略
}
}
}
}
class Program {
// サーバの作成
public static Server<string, string> Server(IPEndPoint endpoint)
=> new Server<string, string>(endpoint);
// クライアントの作成
public static Client<string, string> Client(IPEndPoint endpoint)
=> new Client<string, string>(endpoint);
// 文字列を並びを反対にする
private static string Reverse(string original)
=> new string(original.Reverse().ToArray());
static void Main(string[] args) {
var endpoint = new IPEndPoint(IPAddress.Loopback, 54321);
// サーバを実行
var server = Task.Run(() => Server(endpoint).RunAsync(Reverse));
// クライアントを実行
Task.WaitAll(
Client(endpoint).SendAsync("あいうえお"),
Client(endpoint).SendAsync("かきくけこ"));
// サーバのTaskをきれいに終了するにはどうしたらいいのか...
}
}
// 実行結果
/*
Client send request: あいうえお
Server receive request: あいうえお
Client send request: かきくけこ
Server receive request: かきくけこ
Server send response: おえういあ
Server send response: こけくきか
Client receive response: おえういあ
Client receive response: こけくきか
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment