recvfrom代码块分析
recvfrom-CSDN博客看一段代码:void UdpFuc::slot_start() { char pBuf[1500]; int ret 0; memset((char *)pBuf, \0, 1500); int sockAddrSize sizeof (struct sockaddr_in); while(1) { ret recvfrom(m_recvSocket, (char*)pBuf, sizeof(pBuf), 0, (struct sockaddr *)m_recvSockAddr, (socklen_t*)sockAddrSize); // 处理代码 if(ret0) { QByteArray bdp((const char*)pBuf, ret); emit sign_bdp(bdp); } } }char pBuf[1500];memset((char *)pBuf, \0, 1500);可以直接写sizeof(pBuf)吗数组场景下sizeof是编译期常量pBuf是数组不是指针sizeof(pBuf)在编译期就等于 1500没有运行时开销。编译器直接生成常量。ret recvfrom(m_recvSocket, (char*)pBuf, sizeof(pBuf), 0, (struct sockaddr *)m_recvSockAddr, (socklen_t*)sockAddrSize);m_recvSocket : 套接字文件描述符pBuf : 接收数据的缓冲区sizeof(pBuf)缓冲区大小0 : 接收标志m_recvSockAddr : 输出参数存放发送方的地址信息参数方向含义src_addr纯输出内核把发送方地址写进这块内存addrlen输入 输出传入src_addr缓冲区有多大返回内核实际写了多少字节src_addr缓冲区是什么src_addr不是内核分配的一块内存给你而是你调用者自己准备一块内存把地址传给内核让内核往里填数据。看这段代码struct sockaddr_in cliAddr; // ← ① 这就是缓冲区 socklen_t addrLen sizeof(cliAddr); // ← ② 缓冲区大小 recvfrom(sockfd, buf, len, 0, (struct sockaddr *)cliAddr, // ← ③ 把缓冲区地址传给内核 addrLen);三个概念对应概念在这段代码里说明缓冲区cliAddr这个变量本身一块16 字节的栈内存IPv4指针cliAddr强转成(struct sockaddr *)告诉内核往这块内存写缓冲区大小addrLen sizeof(cliAddr)告诉内核最多写 16 字节内核做的事把发送方的IP 端口写进cliAddr指向的那 16 字节里。你做的事调用结束后从cliAddr.sin_addr/cliAddr.sin_port读出来。为什么地址长度要用指针因为内核写完还要告诉你实际写了多少IPv4 是 16IPv6 是 28所以需要回传。回到上面的程序问题 sockAddrSize位置错误int sockAddrSize sizeof(struct sockaddr_in); // 放在 while 外面 ... ret recvfrom(..., (socklen_t*)sockAddrSize);sockAddrSize是一个输入输出参数调用前告诉内核m_recvSockAddr缓冲区大小调用后内核写回实际地址长度问题每次recvfrom都会修改它。虽然对 IPv4 来说通常仍是 16 字节但这是个规范用法错误应该每次循环重置while (1) { socklen_t sockAddrSize sizeof(m_recvSockAddr); // 每次重置 ret recvfrom(..., (struct sockaddr *)m_recvSockAddr, sockAddrSize); ... }另外int转socklen_t*的强制转换也不规范直接声明为socklen_t更好。