Skip to content

.NET Core 实战 [No.301~303] Socket 通信

🏷️ 《.NET Core 实战》

本节主要讲了基于 Socket 的网络通信。 Socket 支持很多网络协议,本节讲了一下几种通信方法:

  • 基于 TCP 协议的 Socket 通信
  • 封装了 TCP 协议的 TcpListenerTcpClient
  • 封装了 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}");

TcpListenerTcpClient

TcpListenerTcpClient 类是框架提供的封装类型,包装了基于 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 类封装了 SocketUDP 协议与通信相关的功能,使基于 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 个精彩案例》 -- 周家安 著