Last active
March 2, 2021 05:24
-
-
Save ichiroku11/1c70dc3d2766e45af665a8e829910800 to your computer and use it in GitHub Desktop.
.NETでTCP(TcpClientとTcpListener)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Sockets; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Tcp.ConsoleApp { | |
// クライアント | |
public class Client<TRequest, TResponse> { | |
// 接続先のエンドポイント | |
private readonly IPEndPoint _endpoint; | |
public Client(IPEndPoint endpoint) { | |
_endpoint = endpoint; | |
} | |
// サーバにリクエストを送信してレスポンスを受信する | |
public async Task<TResponse> Send(TRequest request) { | |
using (var client = new TcpClient()) { | |
// 1. サーバに接続 | |
await client.ConnectAsync(_endpoint.Address, _endpoint.Port); | |
using (var stream = client.GetStream()) { | |
// 2. サーバにリクエストを送信する | |
Console.WriteLine($"Client send: {request}"); | |
stream.WriteObject(request); | |
// 3. サーバからレスポンスを受信する | |
var response = stream.ReadObject<TResponse>(); | |
Console.WriteLine($"Client received: {response}"); | |
return response; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Tcp.ConsoleApp { | |
// メッセージ | |
[Serializable] | |
public class Message { | |
public int Id { get; set; } | |
public string Content { get; set; } | |
public override string ToString() { | |
return $@"{{ {nameof(Id)} = {Id}, {nameof(Content)} = ""{Content}"" }}"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Runtime.Serialization; | |
using System.Runtime.Serialization.Formatters.Binary; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Tcp.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); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Tcp.ConsoleApp { | |
class Program { | |
static void Main(string[] args) { | |
// サーバが接続を待つエンドポイント | |
// であり | |
// クライアントが接続するサーバのエンドポイント | |
var endpoint = new IPEndPoint(IPAddress.Loopback, 54321); | |
// サーバ | |
var server = new Server<Message, Message>( | |
endpoint, | |
// リクエストからレスポンスを作る処理 | |
request => new Message { | |
Id = request.Id, | |
// メッセージの文字列を逆順にする | |
Content = new string(request.Content.Reverse().ToArray()), | |
}); | |
// 接続を待機 | |
var task = Task.Run(() => server.Listen()); | |
// クライアント | |
Task.WaitAll( | |
// リクエストを送信してレスポンスを受信 | |
new Client<Message, Message>(endpoint).Send(new Message { Id = 10, Content = "あいうえお" }), | |
new Client<Message, Message>(endpoint).Send(new Message { Id = 20, Content = "かきくけこ" }), | |
new Client<Message, Message>(endpoint).Send(new Message { Id = 30, Content = "さしすせそ" }) | |
); | |
// サーバを終了 | |
server.Close(); | |
// サーバの終了処理、Taskの管理、エラー処理あたりが微妙 | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Sockets; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Tcp.ConsoleApp { | |
// サーバ | |
public class Server<TRequest, TResponse> { | |
// 接続を待つエンドポイント | |
private readonly IPEndPoint _endpoint; | |
// リクエストからレスポンスを作成する処理 | |
private readonly Func<TRequest, TResponse> _processor; | |
// TCPリスナー | |
private readonly TcpListener _listener; | |
public Server(IPEndPoint endpoint, Func<TRequest, TResponse> processor) { | |
_endpoint = endpoint; | |
_processor = processor; | |
_listener = new TcpListener(_endpoint); | |
} | |
// クライアントからリクエストを受信してレスポンスを送信する | |
private void Receive(TcpClient client) { | |
using (client) | |
using (var stream = client.GetStream()) { | |
// 3. クライアントからリクエストを受信する | |
var request = stream.ReadObject<TRequest>(); | |
// 4. リクエストを処理してレスポンスを作る | |
var response = _processor(request); | |
// 5. クライアントにレスポンスを送信する | |
stream.WriteObject(response); | |
} | |
} | |
// 接続を待つ | |
public async Task Listen() { | |
Console.WriteLine($"Server listen:"); | |
// 1. クライアントからの接続を待つ | |
_listener.Start(); | |
while (true) { | |
// 2. クライアントからの接続を受け入れる | |
var client = await _listener.AcceptTcpClientAsync(); | |
Console.WriteLine($"Server accepted:"); | |
var task = Task.Run(() => Receive(client)); | |
// Taskの管理やエラー処理は省略 | |
} | |
} | |
// 終了する | |
public void Close() { | |
_listener.Stop(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace Tcp.ConsoleApp { | |
public static class StreamExtensions { | |
// オブジェクトの読み込み | |
public static TObject ReadObject<TObject>(this Stream stream) { | |
using (var reader = new BinaryReader(stream, Encoding.UTF8, true)) { | |
// 長さを読み込んでから、バイト配列を読み込む | |
var length = reader.ReadInt32(); | |
var bytes = reader.ReadBytes(length); | |
var converter = new ObjectConverter<TObject>(); | |
return converter.FromByteArray(bytes); | |
} | |
} | |
// オブジェクトの書き込み | |
public static void WriteObject<TObject>(this Stream stream, TObject obj) { | |
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true)) { | |
var converter = new ObjectConverter<TObject>(); | |
var bytes = converter.ToByteArray(obj); | |
// 長さを書き込んでからバイト配列を書き込む | |
writer.Write(bytes.Length); | |
writer.Write(bytes); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment