UDP的recvfrom会返回一个完整的数据报

1.问题

在阅读Luanti服务器网络部分的代码时,发现未使用tcp连接,而是基于udp实现的可靠连接,读到如下代码,m_udpSocket.Receive后,就直接判断,若received_size < BASE_HEADER_SIZE就认为是错误了。基于本人之前很少些UDP程序,写的是TCP的,就有疑惑,这里如何保证收到的收据包肯定大于BASE_HEADER_SIZE?

cpp 复制代码
		// Call Receive() to wait for incoming data
		Address sender;
		s32 received_size = m_connection->m_udpSocket.Receive(sender,
			*packetdata, packetdata.getSize());
		if (received_size < 0)
			return;

		if ((received_size < BASE_HEADER_SIZE) ||
			(readU32(&packetdata[0]) != m_connection->GetProtocolID())) {
			LOG(derr_con << m_connection->getDesc()
				<< "Receive(): Invalid incoming packet, "
				<< "size: " << received_size
				<< ", protocol: "
				<< ((received_size >= 4) ? readU32(&packetdata[0]) : -1)
				<< std::endl);
			return;
		}

		session_t peer_id = readPeerId(*packetdata);
		u8 channelnum = readChannel(*packetdata);

		if (channelnum > CHANNEL_COUNT - 1) {
			LOG(derr_con << m_connection->getDesc()
				<< "Receive(): Invalid channel " << (u32)channelnum << std::endl);
			return;
		}

2. 寻找答案

  1. UDP 套接字(SOCK_DGRAM)

    数据报边界:UDP 是面向消息的协议,每次 recvfrom 会返回一个完整的数据报(即对端 sendto 发送的单个数据块)。

  2. TCP 套接字(SOCK_STREAM)

    字节流特性:TCP 无消息边界,recvfrom 返回的数据量由内核缓冲区中的可用数据和接收缓冲区大小决定。

MSDN上的描述:

For stream-oriented sockets such as those of type SOCK_STREAM, a call

to recvfrom returns as much information as is currently available---up

to the size of the buffer specified. If the socket has been configured

for inline reception of OOB data (socket option SO_OOBINLINE) and OOB

data is yet unread, only OOB data will be returned. The application

can use the ioctlsocket or WSAIoctl SIOCATMARK command to determine

whether any more OOB data remains to be read. The from and fromlen

parameters are ignored for connection-oriented sockets.

For message-oriented sockets, data is extracted from the first

enqueued message, up to the size of the buffer specified. If the

datagram or message is larger than the buffer specified, the buffer is

filled with the first part of the datagram, and recvfrom generates the

error WSAEMSGSIZE. For unreliable protocols (for example, UDP) the

excess data is lost. For UDP if the packet received contains no data

(empty), the return value from the recvfrom function function is zero.

MSDN译文:

  • 面向流的套接字(如 SOCK_STREAM 类型)相关

    对面向流的套接字调用 recvfrom 时,会返回当前可用的、最多达到指定缓冲区大小的信息量。如果套接字已配置为内联接收带外(OOB)数据(套接字选项 SO_OOBINLINE)且存在未读的带外数据,则仅返回带外数据。应用程序可以使用 ioctlsocket 或 WSAIoctl 的 SIOCATMARK 命令来确定是否还有更多带外数据有待读取。对于面向连接的套接字,from 和 fromlen 参数会被忽略。

  • 面向消息的套接字(数据提取方面)相关

    对于面向消息的套接字,数据从第一个排队的消息中提取,最多提取到指定缓冲区大小的数据量。如果数据报或消息大于指定的缓冲区,则缓冲区将填充数据报的部分内容,剩下的则丢弃,并且 recvfrom 会生成 WSAEMSGSIZE 错误。对于不可靠协议(例如 UDP),多余的数据会丢失。对于 UDP,如果接收到的数据包不包含数据(为空),recvfrom 函数的返回值是零。

相关推荐
全栈工程师修炼指南19 小时前
Nginx | stream content 阶段:UDP 协议四层反向代理浅析与实践
运维·网络·网络协议·nginx·udp
cur1es20 小时前
【UDP的报文结构】
网络·网络协议·udp·md5
cheems95271 天前
【javaEE】全方位拆解 UDP 协议
网络·网络协议·udp
wenzhangli72 天前
OoderAgent SDK(0.6.6) UDP通讯与协议测试深度解析
网络·网络协议·udp
Trouvaille ~3 天前
【Linux】UDP Socket编程实战(一):Echo Server从零到一
linux·运维·服务器·网络·c++·websocket·udp
郝亚军3 天前
ubuntu启一个udp server,由一个client访问
linux·ubuntu·udp
Trouvaille ~3 天前
【Linux】UDP Socket编程实战(二):网络字典与回调设计
linux·运维·服务器·网络·c++·udp·操作系统
Trouvaille ~3 天前
【Linux】UDP Socket编程实战(三):多线程聊天室与线程安全
linux·服务器·网络·c++·安全·udp·socket
Trouvaille ~3 天前
【Linux】UDP Socket编程实战(四):地址转换函数深度解析
linux·服务器·网络·c++·udp·socket·地址转换函数
中议视控3 天前
浅谈Modbus,CRC,kNX,DMX512,KNZ,TCP/UDP等协议算法在可编程网络中央控制系统主机中的重要性
网络·tcp/ip·udp