C#网络编程(Socket编程)

文章目录

  • 0、写在前面的话
  • [1、Socket 介绍](#1、Socket 介绍)
    • [1.1 Socket是什么](#1.1 Socket是什么)
    • [1.2 Socket在网络中的位置](#1.2 Socket在网络中的位置)
  • [2、C# 中的Socket参数](# 中的Socket参数)
    • [2.1 超时控制参数](#2.1 超时控制参数)
    • [2.2 缓冲区参数](#2.2 缓冲区参数)
    • [2.3 UDP专用参数](#2.3 UDP专用参数)
  • [3、C# 中的Socket API](# 中的Socket API)
    • [3.1 Socket(构造函数)](#3.1 Socket(构造函数))
      • [3.1.1 SocketType](#3.1.1 SocketType)
      • [3.1.2 ProtocolType](#3.1.2 ProtocolType)
      • [3.1.3 AddressFamily](#3.1.3 AddressFamily)
    • [3.2 Bind()](#3.2 Bind())
    • [3.3 Connect()](#3.3 Connect())
    • [3.4 Listen() (TCP)](#3.4 Listen() (TCP))
    • [3.5 Accept() (TCP)](#3.5 Accept() (TCP))
    • [3.6 Receive() 与 Send()](#3.6 Receive() 与 Send())
    • [3.7 ReceiveFrom()与SendTo()](#3.7 ReceiveFrom()与SendTo())
    • [3.8 Shutdown()和Close()](#3.8 Shutdown()和Close())
  • [4、IPAddress 和 IPEndPoint](#4、IPAddress 和 IPEndPoint)
    • [4.1 IPAddress](#4.1 IPAddress)
    • [4.2 IPEndPoint](#4.2 IPEndPoint)

0、写在前面的话

我创建的Unity、C#交流群,有兴趣可加入大家一起学习:952914223

1、Socket 介绍

1.1 Socket是什么

Socket的英文原意是"插座",的意思,通常在计算机编程中称作套接字,是对对于TCP/IP的封装,我们可以将Socket联想成是由两个Socket对象搭建的成的一根通信管道,管道的两端是这两个Socket对象,而这根管道的连接的是两台主机的应用进程(通过IP地址和端口号确定进程)

1.2 Socket在网络中的位置

2、C# 中的Socket参数

2.1 超时控制参数

  1. ReceiveTimeout:接收超时
csharp 复制代码
socket.ReceiveTimeout = 5000; // 5秒(单位:毫秒)
// 超时抛出SocketException,ErrorCode为10060 (TimedOut)
  1. SendTimeout:发送超时
csharp 复制代码
socket.SendTimeout = 3000; // 3秒
// 影响Send/SendTo操作
  1. BeginConnect:连接超时
csharp 复制代码
// 通过Connect方法的异步版本实现
socket.BeginConnect(remoteEP, null, null);
if(!socket.Connected) {
    // 自定义超时逻辑
}

2.2 缓冲区参数

  1. ReceiveBufferSize:接收缓冲区大小
csharp 复制代码
socket.ReceiveBufferSize = 65536; // 64KB
// 影响内核网络栈的接收缓冲区
  1. SendBufferSize:发送缓冲区大小
csharp 复制代码
socket.SendBufferSize = 32768; // 32KB
// 影响内核网络栈的发送缓冲区

2.3 UDP专用参数

  1. EnableBroadcast:启用广播
csharp 复制代码
udpSocket.EnableBroadcast = true;
// 允许发送到广播地址(如255.255.255.255)
  1. 多播设置
csharp 复制代码
// 加入多播组
udpSocket.SetSocketOption(SocketOptionLevel.IP,
                        SocketOptionName.AddMembership,
                        new MulticastOption(IPAddress.Parse("224.0.0.1")));

// 设置多播TTL
udpSocket.SetSocketOption(SocketOptionLevel.IP,
                        SocketOptionName.MulticastTimeToLive,
                        2); // 最多跨越2个路由器

3、C# 中的Socket API

3.1 Socket(构造函数)

csharp 复制代码
public Socket(SocketInformation socketInformation);
public Socket(SocketType socketType, ProtocolType protocolType);
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);

常见的 Socket 对象创建实例:

csharp 复制代码
// 监控 ip4 地址,套接字类型为 TCP ,协议类型为 TCP
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

3.1.1 SocketType

指定 Socket 类的实例表示的套接字类型。

SocketType 对应的ProtocolType 描述
Unknown Unknown 指定未知的 Socket 类型
Stream(使用字节流) Tcp 支持可靠、双向、基于连接的字节流
Dgram(使用数据报) Udp 面向无连接
Raw Icmp、lgmp 支持对基础传输协议的访问
Rdm 支持无连接、面向消息、以可靠方式发送的消息,
Seqpacket 在网络上提供排序字节流的面向连接且可靠的双向传输

3.1.2 ProtocolType

表示协议类型,是一个 enum 类型。

其中枚举重复值,常见用途:

  • 为旧值提供别名
  • 向后兼容
  • 提供更清晰的命名选择
枚举值 协议说明
Unknown -1 未知协议类型
Unspecified 0 未指定的协议
IP 0 Internet 协议 (IP) - 原始 IP 数据包
IPv6HopByHopOptions 0 IPv6 逐跳选项头
Icmp 1 Internet 控制消息协议 (ICMP)
Igmp 2 Internet 组管理协议 (IGMP)
Ggp 3 网关到网关协议 (GGP)
IPv4 4 IPv4 协议
Tcp 6 传输控制协议 (TCP)
Pup 12 PARC 通用数据包协议 (PUP)
Udp 17 用户数据报协议 (UDP)
Idp 22 Internet 数据报协议 (IDP)
IPv6 41 IPv6 协议
IPv6RoutingHeader 43 IPv6 路由头
IPv6FragmentHeader 44 IPv6 分片头
IPSecEncapsulatingSecurityPayload 50 IPv6 封装安全负载 (ESP) 头
IPSecAuthenticationHeader 51 IPv6 认证头 (AH)
IcmpV6 58 ICMP for IPv6
IPv6NoNextHeader 59 IPv6 无下一个头
IPv6DestinationOptions 60 IPv6 目的选项头
ND 77 Net Disk 协议 (非正式)
Raw 255 原始 IP 数据包
Ipx 1000 Internet 数据包交换协议 (IPX)
Spx 1256 顺序数据包交换协议 (SPX)
SpxII 1257 SPX 版本 2

3.1.3 AddressFamily

表示使用的网络寻址方案

枚举值 协议说明 使用场景
Unknown -1 未知地址族 保留值
Unspecified 0 未指定的地址族 通用情况
Unix 1 Unix本地通信 Unix域Socket
InterNetwork 2 IPv4地址族 最常用的IPv4网络
ImpLink 3 ARPANET IMP地址 历史遗留
Pup 4 PUP协议地址 Xerox PUP网络
Chaos 5 MIT CHAOS协议 历史遗留
NS 6 Xerox NS协议 Xerox网络系统
Ipx 6 IPX/SPX地址 Novell网络
Iso 7 ISO协议 OSI协议族
Osi 7 OSI协议 同Iso
Ecma 8 ECMA协议 欧洲计算机制造商协会
DataKit 9 Datakit协议 AT&T Datakit
Ccitt 10 CCITT协议 TU-T协议
Sna 11 IBM SNA地址 IBM系统网络架构
DecNet 12 DECnet地址 Digital Equipment Corporation网络
DataLink 13 直接数据链路接口 数据链路层访问
Lat 14 LAT地址 Local Area Transport
HyperChannel 15 NSC Hyperchannel Network Systems Corporation
AppleTalk 16 AppleTalk地址 Apple网络协议
NetBios 17 NetBios地址 Windows网络基本输入输出系统
VoiceView 18 VoiceView地址 VoiceView音频协议
FireFox 19 FireFox协议 非标准协议
Banyan 21 Banyan VINES Banyan虚拟网络系统
Atm 22 本机ATM服务 异步传输模式
InterNetworkV6 23 IPv6地址族 IPv6网络
Cluster 24 Microsoft Wolfpack Microsoft集群服务
Ieee12844 25 IEEE 1284.4工作组 打印机共享协议
Irda 26 IrDA地址 红外数据协会
NetworkDesigners 28 Network Designers OSI网关 网络设计者协议
Max 29 最大地址族 保留值

3.2 Bind()

绑定本地IP和端口,你将在在本地创建 IPEndPoint 对象,拥有此 ip:post 的访问权限。目的是绑定本地机器的某个端口,所有经过此端口的数据就归你管了。

csharp 复制代码
public void Bind (System.Net.EndPoint localEP);

使用实例:

csharp 复制代码
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress iP = IPAddress.Parse("127.0.0.1");

serverSocket.Bind(new IPEndPoint(iP, 2300))

3.3 Connect()

与远程主机建立连接。Connect() 有四个重载方法,不必关注,只需知道,必需提供 IP 和 Post 两个值。

csharp 复制代码
IPAddress iP = IPAddress.Parse("127.0.0.1");
IPEndPoint iPEndPoint = new IPEndPoint(iP, 2300);
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);        //创建与远程主机的连接
serverSocket.Connect(iPEndPoint);

3.4 Listen() (TCP)

监控所有发送到此主机的、特定端口的连接请求。服务端使用,客户端不需要。

csharp 复制代码
public void Listen (int backlog);

使用 Bind() 后,使用 Listen() 方法进行监控,backlog 参数指定可排队等待接受的传入连接的数量,即挂起的连接队列的最大长度。

3.5 Accept() (TCP)

Accept() 以同步方式监听套接字,在连接请求队列中提取第一个挂起的连接请求,然后创建并返回一个新的 Socket 对象。

csharp 复制代码
//创建终结点(EndPoint)
IPAddress ip = IPAddress.Any;             
IPEndPoint ipe = new IPEndPoint(ip, 8000);

//创建 socket 并开始监听
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(ipe);
serverSocket.Listen(10);//开始监听

//接受到client连接,为此连接建立新的socket,并接受信息
Socket temp = serverSocket.Accept();//为新建连接创建新的socket

注意的是,每次建立连接是一个 Accept() 对象,如果你要进行 服务器-客户端互相通讯,应使用同一个 Accept() 对象。每个 Accept 对象都是 从客户端请求建立开始的,期间只要使用同一个 Accept 对象,都可以进行数据传输。

3.6 Receive() 与 Send()

  • Receive() :接收信息
csharp 复制代码
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
bytes = socket.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息
recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
  • Send() :发送信息
csharp 复制代码
string str = "hello";
byte[] a = Encoding.UTF8.GetBytes(str);
send = socket.Send(a, 0);

3.7 ReceiveFrom()与SendTo()

  • ReceiveFrom()
特性 Receive ReceiveFrom
连接要求 需要已建立连接 (面向连接) 无需预先连接 (无连接)
适用协议 TCP UDP
来源获取 无法获取发送方信息 可获取发送方的端点信息
方法签名 int Receive(byte[] buffer) int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP)
典型用途 可靠数据流传输 数据报接收,特别是需要回复的场景
  • SendTo()
特性 Send SendTo
连接要求 需要已建立连接 (面向连接) 无需预先连接 (无连接)
适用协议 TCP UDP
目标指定 在Connect时指定目标 每次发送时指定目标
性能 略高 (连接已建立) 略低 (每次需解析地址)
可靠性 高 (TCP保证送达和顺序) 低 (UDP不保证送达和顺序)
方法签名 Send(byte[] buffer) SendTo(byte[] buffer, EndPoint remoteEP)

3.8 Shutdown()和Close()

释放资源,有 Accept 释放和 Socket 的释放。

  • Shutdown()
    1. 向对方发送FIN包,启动TCP的正常关闭握手流程
    2. 非破坏性操作,Socket对象仍然有效
    3. 允许完成正在进行的数据传输
    4. 遵循TCP协议的四次挥手过程
    5. 对方应用会收到EOF(Receive返回0)
csharp 复制代码
public void Shutdown (System.Net.Sockets.SocketShutdown how);

SocketShutdown:

描述
Send 禁止对此发送Socket
Receive 禁用对此接收Socket
Both 禁用发送和接收对此Socket
  • Close()
    1. 破坏性操作,Socket对象不再可用
    2. 可能丢失发送/接收缓冲区中的数据
    3. 对方可能收到ConnectionReset错误
    4. 立即释放系统资源
  • 最佳实践
csharp 复制代码
void SafeClose(Socket socket)
{
    try
    {
        // 1. 先优雅关闭通信通道
        if(socket.Connected)
        {
            socket.Shutdown(SocketShutdown.Both);
        }
        
        // 2. 设置linger选项确保数据发送
        socket.LingerState = new LingerOption(true, 5); // 等待5秒
        
        // 3. 最终释放资源
        socket.Close();
    }
    catch(Exception ex)
    {
        // 记录日志
        Debug.WriteLine($"关闭Socket异常: {ex.Message}");
        
        // 确保资源释放
        socket?.Close(); 
    }
}

4、IPAddress 和 IPEndPoint

4.1 IPAddress

用来处理IP地址、转换IP地址

IPAddress.Parse() 方法可以把以小数点隔分的十进制 IP 表示转化成 IPAddress 类。

csharp 复制代码
IPAddress ip = IPAddress.Parse("127.0.0.1");//把ip地址字符串转换为IPAddress类型的实例

IPAddress提供4个只读字段:

  • Any 用于代表本地系统可用的任何IP地址
  • Broadcase用于代表本地网络的IP广播地址
  • Loopback用于代表系统的回送地址
  • None用于代表系统上没有网络接口

4.2 IPEndPoint

表示IPAddress对象与端口的绑定

csharp 复制代码
IPAddress ip = IPAddress.Any;              //把ip地址字符串转换为IPAddress类型的实例
IPEndPoint ipe = new IPEndPoint(ip, 8000);//用指定的端口和ip初始化IPEndPoint类的新实例
相关推荐
仙人掌_lz1 分钟前
详解如何复现DeepSeek R1:从零开始利用Python构建
开发语言·python·ai·llm·deepseek
小宁学技术5 分钟前
MATLAB在哪些特定领域比Python更有优势?
开发语言·python·matlab
23级二本计科10 分钟前
C++ Json-Rpc框架-3项目实现(2)
服务器·开发语言·c++·rpc
向宇it13 分钟前
【blender小技巧】Blender导出带贴图的FBX模型,并在unity中提取材质模型使用
开发语言·unity·c#·游戏引擎·blender·材质·贴图
奋进的小暄22 分钟前
贪心算法(18)(java)距离相等的条形码
java·开发语言·贪心算法
Hanson8535 分钟前
系统性能优化总结与思考-第一部分
java·开发语言
EverestVIP1 小时前
qt中,父类中有Q_OBJECT,子类中还需要加Q_OBJECT吗
开发语言·qt
x-cmd1 小时前
x-cmd install | jellex - 用 Python 语法在终端里玩转 JSON 数据!
开发语言·python·json·命令行终端
江沉晚呤时1 小时前
CAP 定理与 BASE 定理在 .NET Core 中的应用
java·服务器·开发语言·前端·.netcore
未定义.2211 小时前
Java设计模式实战:装饰模式在星巴克咖啡系统中的应用
java·开发语言·设计模式·软件工程