【微软技术栈】C#.NET 使用套接字通过 TCP 发送和接收数据

本文内容

  1. 创建 IP 终结点
  2. 创建 Socket 客户端
  3. 创建 Socket 服务器
  4. 运行示例客户端和服务器

必须先使用协议和网络地址信息初始化套接字,然后才能使用套接字与远程设备进行通信。 Socket 类的构造函数包含的参数可以指定地址系列、套接字类型,以及套接字用于建立连接的协议类型。 将客户端套接字连接到服务器套接字时,客户端将使用 IPEndPoint 对象来指定服务器的网络地址。

1、创建 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 地址。

Internet 编号分配机构 (IANA) 定义公共服务的端口号。 有关详细信息,请参阅 IANA:服务名称和传输协议端口号注册表。 其他服务可具有 1,024 到 65,535 范围内的注册端口号。 以下代码将 host.contoso.com 的 IP 地址与端口号组合,为连接创建远程终结点。

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

确定远程设备的地址并选择要用于连接的端口后,应用可以建立与远程设备的连接。

2、创建 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,此操作会关闭发送和接收操作。

3、创建 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 向客户端发送确认。

4、运行示例客户端和服务器

首先启动服务器应用程序,然后启动客户端应用程序。

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...
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉特思米(gitusme)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值