Unreal Engine:Socket源码解析
一、文件结构
二、SocketTypes.h
1. Socket类型定义
2. 连接状态
3. [ 枚举] socket 接收标志 ESocketReceiveFlags
- None = 0:返回输入队列中当前可用的尽可能多的数据,达到接收缓冲区的指定大小。
- Peek = 2: 将接收到的数据复制到缓冲区中,而不将其从输入队列中移除。
- WaitAll = 0x100:阻塞接收调用,直到提供的缓冲区已满、连接已关闭、请求已取消或发生错误。
4. [ 枚举] socket 等待条件 ESocketWaitConditions
- WaitForRead
- WaitForWrite
- WaitForReadOrWrite
5. [ 枚举] socket 关闭模式 ESocketShutdownMode
- Read,Write,ReadWrite
6. [枚举] 转换时间戳 ETimestampTranslation
LocalTimestamp:转换为本地时间戳
TimeDelta:当前平台时间与时间戳的差值
7. [结构体] FRecvMulti
存储持久状态和数据包缓冲区/数据,用于接收FSocket::RecvMulti数据包。
为了优化性能,在套接字的生命周期内只使用该结构的一个实例。
包括:
- 当前接收的报文列表:TUniquePtr<FRecvData[]> Packets;
- 其中FRecvData结构体包括:
- 包的源地址:TSharedPtr<FInternetAddr> Source;
- 指向包数据的指针:const uint8* Data;
- 指向读取字节数的内部指针:const uint32* BytesReadPtr;
- 其中FRecvData结构体包括:
- 接收的报文数:int32 NumPackets;
- 支持的最大报文数:const int32 MaxNumPackets;
- 支持的最大数据包大小:const int32 MaxPacketSize;
- 检索指定数据包的信息: GetPacket(int32 PacketIdx, FReceivedPacketView& OutPacket)
- 获取平台指定时间戳:GetPacketTimestamp(int32 PacketIdx, FPacketTimestamp& OutTimestamp)
- 获取当前接收的数据包数量:GetNumPackets()
- 获取当前实例的总内存消耗:CountBytes(FArchive& Ar)
三、Sockets.h
class FSocket
protected:
- const ESocketType SocketType; //传输协议:None、UDP、TCP
- FString SocketDescription; //调试说明
- FName SocketProtocol; //创建套接字使用的协议名
public:
- 关闭读/写:Shutdown(ESocketShutdownMode Mode)
- 关闭套接字:Close()
- 绑定套接字到网络字节序:Bind(const FInternetAddr& Addr)
- 连接到网络字节序:Connect(const FInternetAddr& Addr)
- 监听:Listen(int32 MaxBackLog) //MaxBackLog:拒绝连接之前排队的连接数
- 等待挂起的连接:WaitForPendingConnection(bool& bHasPendingConnection, const FTimespan& WaitTime) //bHasPendingConnection:是否被挂起 WaitTime:等待连接的最大时间
- 确认是否有挂起的连接:HasPendingConnection(bool& bHasPendingConnection)
- 确认是否有挂起的数据:HasPendingData(uint32& PendingDataSize)
- 接收一个挂起的连接:FSocket* Accept(const FString& InSocketDescription) / FSocket* Accept(FInternetAddr& OutAddr, const FString& InSocketDescription)
- 发送缓冲区到一个网络字节序:SendTo(const uint8* Data, int32 Count, int32& BytesSent, const FInternetAddr& Destination);
- 发送缓冲区到一个已连接的套接字:Send(const uint8* Data, int32 Count, int32& BytesSent)
- 读取数据块并收集源地址:RecvFrom(uint8* Data, int32 BufferSize, int32& BytesRead, FInternetAddr& Source, ESocketReceiveFlags::Type Flags = ESocketReceiveFlags::None)
- 从已连接的套接字读取数据块:Recv(uint8* Data, int32 BufferSize, int32& BytesRead, ESocketReceiveFlags::Type Flags = ESocketReceiveFlags::None)
- 阻塞,直到满足特定条件:Wait(ESocketWaitConditions::Type Condition, FTimespan WaitTime)
- 获取连接状态:GetConnectionState()
- 读取并返回套接字绑定地址:GetAddress(FInternetAddr& OutAddr)
- 获取套接字连接端地址:GetPeerAddress(FInternetAddr& OutAddr)
- 设置为非阻塞模式:SetNonBlocking(bool bIsNonBlocking = true)
- 设置为广播模式(仅限UDP):SetBroadcast(bool bAllowBroadcast = true)
- 将此套接字设置为TCP_NODELAY模式(仅TCP):SetNoDelay(bool bIsNoDelay = true)
- 读取套接字绑定的端口:GetPortNo()
- 获取套接字绑定的协议类型:GetSocketType()
- GetDescription()
- GetProtocol()
- ...
四、IPAddress.h
class FInternetAddr
public:
- 比较完成端口:CompareEndpoints(const FInternetAddr& InAddr)
- 设置IP地址和获取:SetIp()、GetIp()
- 设置端口号和获取:SetPort()、GetPort()
- IP地址转为字符串:ToString(bool bAppendPort) //bAppendPort:是否加入端口信息
- 比较IP地址 :==
- 是否合法地址:IsValid()
- 克隆一个相同结构:TSharedRef<FInternetAddr> Clone()
- ...
五、AddressInfoTypes.h
[枚举] EAddressInfoFlags : uint16
- AllResults = 1 << 0 //返回所有地址
- NoResolveHost = 1 << 1 //不要使用字符串(AI_NUMERICHOST)的DNS解析,这使得地址解析是非阻塞的,要求主机名已经是IP地址的形式
- NoResolveService = 1 << 2 //不要解析服务名称(要求服务参数为nullptr或基于数字表示的字符串)。 这也是非阻塞的。
- OnlyUsableAddresses = 1 << 3 //只返回此机器上的适配器可以使用的地址(AI_ADDRCONFIG)
- BindableAddress = 1 << 4 //返回可绑定地址(AI_PASSIVE)。 只有当hostname参数为空时才有效
- CanonicalName = 1 << 5 //在结果列表中包含主机的规范名称
- FQDomainName = 1 << 6 //在结果列表中包含主机的完全限定域名
- AllowV4MappedAddresses = 1 << 7 //支持IPv4映射IPv6地址
- AllResultsWithMapping = AllowV4MappedAddresses | AllResults //获取所有地址,但返回V4映射的IPv6地址
- Default = 0 //平台提示标志的默认值(通常只有0)
[结构体] FAddressInfoResultData
[结构体] FAddressInfoResult
六、SocketSubsystem.h
ISocketSubsystem
- 获取单例套接字子系统:ISocketSubsystem* Get(const FName& SubsystemName=NAME_None)
- 关闭所有已注册的子系统:ShutdownAllSystems()
- 初始化套接字库:Init(FString& Error)
- 平台特定套接字清理:Shutdown()
- 创建套接字:FSocket* CreateSocket(const FName& SocketType, const FString& SocketDescription, bool bForceUDP = false)
- 使用给定协议名创建套接字:FSocket* CreateSocket(const FName& SocketType, const FString& SocketDescription, const FName& ProtocolName)
- 创建一个unique_ptr指向的套接字,将自动调用DestroySocket:CreateUniqueSocket(const FName& SocketType, const FString& SocketDescription, bool bForceUDP = false) / CreateUniqueSocket(const FName& SocketType, const FString& SocketDescription, const FName& ProtocolName)
- 清理套接字:DestroySocket(FSocket* Socket)
- 保存解析后地址:FResolveInfoCached* CreateResolveInfoCached(TSharedPtr<FInternetAddr> Addr)
- 获取给定主机名地址信息:GetAddressInfo
- GetAddressInfo的异步变体:GetAddressInfoAsync