sendto的调用导致recvfrom返回

本文探讨了在使用UDP套接字时遇到的一个问题:当一个线程在recvfrom函数上等待接收数据时,如果另一个线程通过同一套接字发送数据,则recvfrom会返回-1。文章记录了这一现象并提出疑问。

创建一个UDP套接字,在套接字上调用recvfrom,线程等待在该函数上。

如果在另一个线程中,在同一套接字上调用sendto将导致recvfrom返回,返回值为-1。

具体原因不明,先记录一下。

 

<think>好的,我现在遇到了一个问题:recvfrom返回11,而模式是阻塞的。我需要弄清楚这是什么意思,以及如何解决它。让我先回忆一下recvfrom函数的相关知识。 首先,recvfrom是一个用于从套接字接收数据的系统调用,通常用于UDP套接字,因为它可以获取发送方的地址信息。当在阻塞模式下使用recvfrom时,如果没有数据到达,调用会一直阻塞,直到有数据可读。返回值大于0通常表示接收到的字节数。这里返回11,说明成功接收到了11字节的数据。那用户为什么会觉得有问题呢?可能他期望更多的数据或者数据内容有问题? 接下来,我需要考虑可能的情况。比如,发送方确实只发送了11个字节的数据,或者接收缓冲区被限制只能接收这么多。另外,检查套接字是否正确设置为阻塞模式,是否有可能被其他操作修改了标志位?比如是否在某个地方调用了fcntl设置了非阻塞标志?另外,数据截断的问题。如果接收缓冲区的大小小于发送的数据包大小,那么recvfrom会截断数据,多余的部分可能会被丢弃。这时候返回值会是缓冲区的大小,而用户可能需要扩大接收缓冲区。但这里返回的是11,可能用户设置的缓冲区足够大,所以实际接收了11字节。 也可能发送方发送的数据确实只有11字节,而用户误以为应该更多。这时候需要检查发送方的代码,确认发送的数据长度是否正确。比如,发送时是否正确地计算了数据长度,是否有数据被意外截断。 此外,还要考虑网络问题。比如,数据包在传输过程中是否被分片,或者中间设备限制了数据包的大小。不过对于UDP来说,如果数据包超过MTU,会在IP层分片,但接收端会重组装,只要所有分片都到达。不过如果分片丢失,可能导致整个UDP包被丢弃,但这里recvfrom返回了11,说明至少有一个数据包到达了,所以可能不是这个问题。 再考虑代码层面。用户是否正确处理了recvfrom返回值?比如,是否将接收到的数据正确拷贝到缓冲区,并处理了返回的长度。比如,如果用户分配了一个足够大的缓冲区,但实际接收到的数据只有11字节,那么应该只处理这11字节的数据,后面的数据可能是无效的。如果用户错误地处理了长度,比如当作固定长度处理,可能会引发问题。 举个例子,假设发送方发送了一个12字节的消息,但接收方只收到11字节,这可能吗?对于UDP来说,数据包是不可分割的,要么整个收到,要么丢失。所以如果recvfrom返回11,说明发送方确实发送了11字节的数据。因此,问题可能出在发送方没有发送足够的数据,或者接收方错误地处理了接收到的数据长度。 那么,解决方案可能包括:检查发送方的数据发送是否正确,确认发送的数据长度是否为11字节;检查接收方的缓冲区是否足够大,确保没有截断;确认套接字确实处于阻塞模式,没有意外地被设置为非阻塞;检查是否有其他错误发生,比如通过errno来判断recvfrom是否返回错误,但这里返回值是11,说明没有错误,因为错误时返回-1。 另外,用户可能需要打印接收到的数据内容,确认是否符合预期。比如,在接收后打印缓冲区的内容,或者记录日志,看看是否数据被正确接收。总结可能的解决步骤: 1.检查发送方代码,确认发送的数据长度是否正确。 2. 检查接收方缓冲区大小,确保足够容纳预期数据。 3.确认套接字处于阻塞模式,没有被设置为非阻塞。 4.打印接收到的数据内容,确认是否与发送的一致。 5.使用工具如Wireshark抓包,确认实际发送的数据包大小。 如果经过这些检查,发现发送的数据确实正确,那么recvfrom返回11是正常现象,可能用户的预期有误。否则,需要根据检查结果调整代码。 例如,接收方的代码可能如下: ```cchar buffer[1024]; ssize_t recv_len= recvfrom(sockfd,buffer, sizeof(buffer), 0,(struct sockaddr*)&src_addr, &addrlen); if (recv_len >0) {printf("Received %zd bytes: %.*s\n",recv_len,(int)recv_len, buffer); } ``` 这里要确保recv_len被正确处理,比如打印出来,或者处理数据时只使用前11字节。如果用户期望更多的数据,但发送方只发送了11字节,那么问题出在发送方。另外,套接字是否为阻塞模式可以通过检查是否设置了O_NONBLOCK标志。例如,在Linux下,可以使用fcntl检查: ```c int flags= fcntl(sockfd,F_GETFL, 0);if (flags &O_NONBLOCK) {printf("Socket isnon-blocking.\n"); } else{ printf("Socket is blocking.\n"); } ```如果发现套接字被设置为非阻塞,可能需要将其改回阻塞模式: ```cfcntl(sockfd, F_SETFL, flags& ~O_NONBLOCK);``` 但这种情况在用户明确设置阻塞模式的情况下应该不存在,除非其他地方修改了标志。 所以,用户应该检查这些方面,确认问题所在。</think>当`recvfrom`在阻塞模式下返回11时,表示成功接收了11字节的数据。以下是详细分析和解决方案: ### 原因分析 1. **正常数据接收**:返回值`11`表示从套接字缓冲区读取了11字节的数据,这是正常现象。 2. **UDP协议特性**:UDP是面向数据报的协议,每个`recvfrom`调用会读取一个完整的数据包。若返回值为11,说明发送方发送的数据包长度就是11字节。 3. **阻塞模式特性**:在阻塞模式下,`recvfrom`会一直等待直到数据到达,因此返回值不会因超时返回0(这是TCP的行为,UDP没有连接概念)。 ### 验证步骤 #### 1. 检查接收端代码 确认是否正确处理了返回值: ```c ssize_t recv_len = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &addrlen); if (recv_len == -1) { perror("recvfrom failed"); } else { printf("Received %zd bytes: %.*s\n", recv_len, (int)recv_len, buf); } ``` #### 2. 检查发送端代码 确认发送方实际发送的数据长度: ```c const char *msg = "hello world"; ssize_t send_len = sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); printf("Sent %zd bytes\n", send_len); // 应输出11 ``` #### 3. 检查套接字模式 验证套接字是否确实是阻塞模式(默认模式): ```c int flags = fcntl(sockfd, F_GETFL, 0); if (flags & O_NONBLOCK) { printf("非阻塞模式!需修改为阻塞模式\n"); fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK); } ``` ### 解决方案 1. **发送端修正**:若发送方数据不足11字节,修正发送逻辑。 2. **接收端验证**:在接收端打印数据内容,确认是否符合预期。 3. **网络抓包分析**:使用`tcpdump`或Wireshark抓包,直接观察UDP数据包长度。 ### 完整代码示例 接收端诊断代码: ```c #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> int main() { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(6000), .sin_addr.s_addr = INADDR_ANY }; bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); char buf[1024]; struct sockaddr_in src_addr; socklen_t addrlen = sizeof(src_addr); ssize_t recv_len = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&src_addr, &addrlen); if (recv_len == -1) { perror("recvfrom error"); } else { printf("Received %zd bytes: [%.*s]\n", recv_len, (int)recv_len, buf); printf("Hex dump:"); for (int i = 0; i < recv_len; i++) { printf(" %02X", buf[i]); } printf("\n"); } close(sockfd); return 0; } ``` ### 典型问题场景 - 发送方使用`sizeof(buf)`发送固定长度数据,但buf内容未初始化。 - 接收端缓冲区足够大,但发送方实际发送数据小于缓冲区大小。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值