佳佳的博客
Menu
首页
《.NET Core 实战》 [No.301~303] Socket 通信
Posted by
佳佳
on 2020-03-29
IT
C#
.NET Core
《.NET Core 实战》
读书笔记
<!-- # 《.NET Core 实战》 [No.301~303] Socket 通信 --> <!-- dotnet-core-socket --> 本节主要讲了基于 *Socket* 的网络通信。 *Socket* 支持很多网络协议,本节讲了一下几种通信方法: - 基于 *TCP* 协议的 *Socket* 通信 - 封装了 *TCP* 协议的 `TcpListener` 和 `TcpClient` 类 - 封装了 *UDP* 协议的 `UdpClient` 类 ## 简单的 *TCP* 通信 **TCP** 是基于连接的通信协议,*Socket* 可以视为两个终结点(*EndPoint*)之间用于对话的标识。 一般来说服务端至少需要两个 *Socket* 实例来完成通信工作: - 一个 *Socket* 实例绑定服务器主机的地址和端口,然后监听客户端的连接。当收到客户端的连接后,会产生另一个 *Socket* 实例。 - 这个新产生的实例主要负责双方的通信,即在服务器和客户端之间发送和接受数据。 在客户端主机上,通常只需要一个 *Socket* 实例,该 *Socket* 实例首先要向服务器发起连接请求,连接成功后就可以与服务器通信了。 ### 服务器端 ```csharp // 创建用于监听的 Socket 实例 Socket server = new Socket(SocketType.Stream, ProtocolType.Tcp); // 本地监听地址(本地回环地址(IP:127.0.0.1),端口号 6000) IPEndPoint localSrv = new IPEndPoint(IPAddress.Loopback, 6000); // 绑定本地端点 server.Bind(localSrv); // 开始监听(backlog 参数用于指定队列中等待的连接数) server.Listen(10); // 等待客户端连接 // 一旦接收到客户端连接,就会创建一个新的 Socket 实例 Socket client = server.Accept(); // 发送消息 string message = "你好,我是服务器。"; byte[] data = Encoding.UTF8.GetBytes(message); // 发送数据长度 client.Send(BitConverter.GetBytes(data.Length)); // 发送数据正文 client.Send(data); // 释放资源 client.Close(); server.Close(); ``` ### 客户端 ```csharp // 创建 Socket 实例(客户端一般只需要一个 Socket 实例即可完成通信) Socket client = new Socket(SocketType.Stream, ProtocolType.Tcp); // 连接服务器 client.Connect(IPAddress.Loopback, 6000); // 读取数据长度 byte[] data = new byte[sizeof(int)]; int dataLen = 0; int n = client.Receive(data); if (n == data.Length) { dataLen = BitConverter.ToInt32(data); } // 读取数据内容 data = new byte[dataLen]; client.Receive(data); string msg = Encoding.UTF8.GetString(data); Console.WriteLine($"\n客户端收到服务器的消息:\n{msg}"); ``` ## *TcpListener* 和 *TcpClient* `TcpListener` 和 `TcpClient` 类是框架提供的封装类型,包装了基于 *TCP* 协议的 *Socket* 通信,使网络编程更简单。 `TcpListener` 类负责两件事: - 开启和监听来自客户端的连接请求 - 接受连接,并产生一个新的 `TcpClient` 实例 `TcpClient` 仅用于发送或接收消息。 ### 服务器端 ```csharp // 创建 TcpListener 实例 TcpListener server = new TcpListener(IPAddress.Any, 1261); // 开始监听 server.Start(); // 等待客户端的连接 TcpClient client = server.AcceptTcpClient(); // 读取从客户端发来的消息 using (NetworkStream stream = client.GetStream()) { List<byte> data = new List<byte>(); byte[] buffer = new byte[256]; int n = 0; // 每次读取 256 个字节,直到消息结束 while ((n = stream.Read(buffer)) != 0) { data.AddRange(buffer.Take(n)); } // 转换为字符串 string msg = Encoding.UTF8.GetString(data.ToArray()); Console.WriteLine($"\n来自客户端的消息:\n{msg}"); } server.Stop(); ``` ### 客户端 ```csharp // 创建 TcpClient 实例 TcpClient client = new TcpClient(); // 向服务器发起连接请求 client.Connect(IPAddress.Parse("127.0.0.1"), 1261); // 向服务器发送消息 using (NetworkStream stream = client.GetStream()) { string msg = "佳佳的博客(www.liujiajia.me)"; byte[] data = Encoding.UTF8.GetBytes(msg); stream.Write(data); } // 释放资源 client.Close(); ``` ## *UdpClient* `UdpClient` 类封装了 *Socket* 上 *UDP* 协议与通信相关的功能,使基于 *UDP* 协议的通信编程更简单。 *UDP* 协议是**无连接的、无序的**,因此只需要单个 `UdpClient` 实例即可完成通信。在收发之前无需建立连接,直接调用 *Send* 方法就可以将数据发送到指定主机的特定端口。接收方同样无需建立连接,直接调用 *Receive* 方法接受远程主机发来的消息。 ### 服务器端 ```csharp // 实例化 UdpClient 对象 UdpClient server = new UdpClient(9000); while (true) { UdpReceiveResult result = await server.ReceiveAsync(); string msg = Encoding.UTF8.GetString(result.Buffer); // 如果消息是 end 则退出 if (msg.ToLower() == "end") { break; } // 否则显示收到的消息 string host = result.RemoteEndPoint.Address.MapToIPv4().ToString(); Console.WriteLine($"来自 {host} : {msg}"); } // 释放资源 server.Close(); ``` ### 客户端 ```csharp // 创建 UdpClient 实例 UdpClient client = new UdpClient(); // 服务器主机名 string serverHost = "127.0.0.1"; // 服务器端口号 int serverPort = 9000; // 循环读取用户输入的消息并发送 while (true) { Console.Write("请输入消息内容:"); string msg = Console.ReadLine(); byte[] data = Encoding.UTF8.GetBytes(msg); client.Send(data, data.Length, serverHost, serverPort); // 如果是 end 则退出 if (msg.ToLower() == "end") { break; } } // 释放资源 client.Close(); ``` ### 执行结果   --- > 购买本书 => [《.NET Core实战:手把手教你掌握380个精彩案例》][10] -- *周家安* 著 --- [10]:https://union-click.jd.com/jdc?e=&p=AyIGZRhaEwAQBFUZXBIyEgRSEl0QCxc3EUQDS10iXhBeGlcJDBkNXg9JHU4YDk5ER1xOGRNLGEEcVV8BXURFUFdfC0RVU1JRUy1OVxUBFQ5THlIQMm1AEkRdb11GZyNTK0BBZwYIbylWcHILWStaJQITBlYbXB0LFQJlK1sSMkBpja3tzaejG4Gx1MCKhTdUK1sRCxQBVxtTEQIQBlwrXBULIloNXwZBXUReEStrJQEiN2UbaxYyUGlUG1kUBhcGUBILQgUXDlMeUkBVRlUBS10XBkIABhkJRzIQBlQfUg%3D%3D (《.NET Core实战:手把手教你掌握380个精彩案例》)
版权声明:原创文章,未经允许不得转载。
https://www.liujiajia.me/2020/3/29/dotnet-core-socket
“Buy me a nongfu spring”
« 《.NET Core 实战》 [No.304~305] Http 编程
《.NET Core 实战》 [No.267~283] 序列化 »
昵称
*
电子邮箱
*
回复内容
*
(回复审核后才会显示)
提交
目录
AUTHOR
刘佳佳
江苏 - 苏州
软件工程师
梦嘉集团