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;
  • 接收的报文数: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
posted @ 2022-07-05 16:39  番茄玛丽  阅读(444)  评论(0编辑  收藏  举报