大家好,又见面了,我是你们的朋友全栈君。
在udp通信中,sendto()函数需要在参数中指定接收方的地址/端口,而recvfrom()函数则在参数中存放发送方的地址/端口。相比之下,send()和recv()函数不需要这样做,但在调用send()之前,必须为套接字指定接收方的地址/端口(这样该函数才知道要把数据发往哪里)。在调用recv()之前,可以为套接字指定发送方的地址/端口,这样该函数就只接收指定发送方的数据;当然,若不指定,也可以接收任意地址的数据。(这些内容在之前关于UDP通信中connect()和bind()函数的文章中有详细介绍。)
这四个函数的使用相对简单,但在某个实例中,我遇到了一个小问题。实现的功能是:UDP服务器创建一个套接字接收客户端的连接,连接成功后,服务器再创建一个套接字与客户端进行数据交互,要求尽量使用connect()、recv()和send()函数。
UDP服务器代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys> #include <sys> #include <netinet> #include <arpa> #define BUFSZ 1024 #define PORT 6567 int main(void) { int srv_sd, cli_sd; int new_sd; int ret; struct sockaddr_in svr_addr, cli_addr; socklen_t addrlen = sizeof(struct sockaddr_in); char buf[BUFSZ] = {}; // 创建套接字 if ((srv_sd = socket(AF_INET, SOCK_DGRAM, 0))
UDP客户端代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys> #include <sys> #include <netinet> #include <arpa> #define BUFSZ 1024 #define PORT 6567 int main(int argc, char *argv[]) { int sd; struct sockaddr_in svr_addr, cli_addr; int ret; socklen_t addrlen = sizeof(struct sockaddr_in); char buf[BUFSZ] = {}; // 创建套接字 if ((sd = socket(AF_INET, SOCK_DGRAM, 0))
运行结果:
观察程序流程,可以得出:
客户端发起连接给服务器,服务器接收到后创建新的套接字并调用connect()函数为该套接字指定目标地址信息。这个目标地址信息虽然确实是客户端的,但客户端的目标地址却是服务器,那么服务器新的套接字的目标地址不是客户端而是服务器,因此服务器发出的数据还是自己收到。
程序的问题出现在客户端。客户端创建了套接字后,就立即为其指定目标(服务器)的地址信息,而这个目标地址信息并非作为接下来数据交互的地址。因此,应该把为客户端指定目标地址的操作放在服务器创建新的套接字后返回数据到客户端之后。但注意,客户端创建完套接字后不能马上使用connect()来指定目的地址信息,那么在发送数据给服务器时就需要使用sendto(),接收数据时则使用recvfrom()。流程图应改为:
客户端代码实现为:
int main(int argc, char *argv[]) { int sd; struct sockaddr_in svr_addr, cli_addr; int ret; socklen_t addrlen = sizeof(struct sockaddr_in); char buf[BUFSZ] = {}; // 创建套接字 if ((sd = socket(AF_INET, SOCK_DGRAM, 0))
运行结果:
结论:connect()、send()和recv()三个函数的搭配使用并不能说一定能代替sendto()和recvfrom(),具体使用还要依据代码场景。
发布者:全栈程序员栈长,转载请注明出处:https://www.php.cn/link/592f69eb8605faf19bb15d0b370cfac8 原文链接:https://www.php.cn/link/c8377ad2a50fb65de28b11cfc628d75c