使用套接字通过 TCP 发送和接收数据
必须先使用协议和网络地址信息初始化套接字,然后才能使用套接字与远程设备进行通信。 Socket 类的构造函数包含的参数可以指定地址系列、套接字类型,以及套接字用于建立连接的协议类型。 将客户端套接字连接到服务器套接字时,客户端将使用 IPEndPoint
对象来指定服务器的网络地址。
创建 IP 终结点
使用 System.Net.Sockets 时,将网络终结点表示为对象 IPEndPoint。 IPEndPoint
是使用 IPAddress 及其相应的端口号构造的。 在通过 Socket 发起对话之前,在应用和远程目标之间创建数据管道。
TCP/IP 使用一个网络地址和一个服务端口号来对唯一标识设备。 网络地址标识特定网络目标;端口号标识该设备要连接到的特定服务。 网络地址和服务端口的组合称为终结点,它在 .NET 中由 EndPoint 类表示。 会为每个受支持的地址系列定义 EndPoint
的后代;对于 IP 地址系列,类为 IPEndPoint。
Dns 类向使用 TCP/IP Internet 服务的应用提供域名服务。 GetHostEntryAsync 方法查询 DNS 服务器以将用户友好的域名(如“host.contoso.com”)映射到数字形式的 Internet 地址(如 192.168.1.1
)。 GetHostEntryAsync
返回一个 Task<IPHostEntry>
,其在等待时包含所请求名称的地址和别名的列表。 在大多数情况下,可以使用 AddressList 数组中返回的第一个地址。 下面的代码获取一个包含服务器 host.contoso.com
的 IP 地址的 IPAddress。
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
提示
出于手动测试和调试目的,通常可将 GetHostEntryAsync 方法与 Dns.GetHostName() 值生成的主机名配合使用,将 localhost 名称解析为 IP 地址。 请思考以下代码片段:
var hostName = Dns.GetHostName();
IPHostEntry localhost = await Dns.GetHostEntryAsync(hostName);
// This is the IP address of the local machine
IPAddress localIpAddress = localhost.AddressList[0];
Internet 编号分配机构 (IANA) 定义公共服务的端口号。 有关详细信息,请参阅 IANA:服务名称和传输协议端口号注册表。 其他服务可具有 1,024 到 65,535 范围内的注册端口号。 以下代码将 host.contoso.com
的 IP 地址与端口号组合,为连接创建远程终结点。
IPEndPoint ipEndPoint = new(ipAddress, 11_000);
确定远程设备的地址并选择要用于连接的端口后,应用可以建立与远程设备的连接。
创建 Socket
客户端
创建 endPoint
对象后,创建客户端套接字以连接到服务器。 连接套接字后,它可以从服务器套接字连接发送和接收数据。
using Socket client = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
await client.ConnectAsync(ipEndPoint);
while (true)
{
// Send message.
var message = "Hi friends 👋!<|EOM|>";
var messageBytes = Encoding.UTF8.GetBytes(message);
_ = await client.SendAsync(messageBytes, SocketFlags.None);
Console.WriteLine($"Socket client sent message: \"{message}\"");
// Receive ack.
var buffer = new byte[1_024];
var received = await client.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
if (response == "<|ACK|>")
{
Console.WriteLine(
$"Socket client received acknowledgment: \"{response}\"");
break;
}
// Sample output:
// Socket client sent message: "Hi friends 👋!<|EOM|>"
// Socket client received acknowledgment: "<|ACK|>"
}
client.Shutdown(SocketShutdown.Both);
上述 C# 代码:
使用给定的
endPoint
实例地址系列 SocketType.Stream 和 ProtocolType.Tcp 实例化新的Socket
对象。使用
endPoint
实例作为自变量调用 Socket.ConnectAsync 方法。在
while
循环中:- 使用 Socket.SendAsync 对消息进行编码并向服务器发送消息。
- 将发送的消息写入控制台。
- 使用 Socket.ReceiveAsync 初始化缓冲区以从服务器接收数据。
- 当
response
得到确认后,它将写入控制台并退出循环。
最后,
client
套接字调用 Socket.Shutdown 给定的 SocketShutdown.Both,此操作会关闭发送和接收操作。
创建 Socket
服务器
若要创建服务器套接字,endPoint
对象可以侦听任何 IP 地址上的传入连接,但必须指定端口号。 创建套接字后,服务器可以接受传入连接并与客户端通信。
using Socket listener = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(100);
var handler = await listener.AcceptAsync();
while (true)
{
// Receive message.
var buffer = new byte[1_024];
var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
var eom = "<|EOM|>";
if (response.IndexOf(eom) > -1 /* is end of message */)
{
Console.WriteLine(
$"Socket server received message: \"{response.Replace(eom, "")}\"");
var ackMessage = "<|ACK|>";
var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
await handler.SendAsync(echoBytes, 0);
Console.WriteLine(
$"Socket server sent acknowledgment: \"{ackMessage}\"");
break;
}
// Sample output:
// Socket server received message: "Hi friends 👋!"
// Socket server sent acknowledgment: "<|ACK|>"
}
上述 C# 代码:
使用给定的
endPoint
实例地址系列 SocketType.Stream 和 ProtocolType.Tcp 实例化新的Socket
对象。listener
以endPoint
实例作为参数调用 Socket.Bind 方法,以将套接字与网络地址相关联。调用 Socket.Listen() 方法以侦听传入连接。
listener
调用 Socket.AcceptAsync 方法以接受handler
套接字上的传入连接。在
while
循环中:- 调用 Socket.ReceiveAsync 以从客户端接收数据。
- 收到数据后,会对其进行解码,然后写入控制台。
- 如果
response
消息以<|EOM|>
结尾,则使用 Socket.SendAsync 向客户端发送确认。
运行示例客户端和服务器
首先启动服务器应用程序,然后启动客户端应用程序。
dotnet run --project socket-server
Socket server starting...
Found: 172.23.64.1 available on port 9000.
Socket server received message: "Hi friends 👋!"
Socket server sent acknowledgment: "<|ACK|>"
Press ENTER to continue...
客户端应用程序将向服务器发送一条消息,服务器将通过确认进行响应。
dotnet run --project socket-client
Socket client starting...
Found: 172.23.64.1 available on port 9000.
Socket client sent message: "Hi friends 👋!<|EOM|>"
Socket client received acknowledgment: "<|ACK|>"
Press ENTER to continue...