.NET Core 实战 [No.301~303] 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 个精彩案例》 -- 周家安 著