TCPIP 网络编程-05-基于UDP的CS

在 《TCPIP 网络编程-02-套接字类型与协议设置》 中通过 示例地址:https://github.com/XBoom/network-ip.git 中的 apps/socket/03/学习了基于UDP的CS通信,可以发现

  1. Client 是不需要发起connect的,直接使用 sendto 进行发送
  2. Server 不需要 listen/accept,而是直接通过recvfrom进行数据接收

新增了两个函数 sendtorecvfrom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <sys/socket.h>

/**
* @brief 使用UDP套接字进行发送
* @param
* sock 用于传输数据的UDP套接字文件描述符
* buff 保存待传输数据的缓冲地址值
* nbytes 待传输的数据长度,以B为单位
* flags 可选参数、没有则为0
* to 存有目的地址信息的sockaddr解耦提变量的地址值
* addrlen 参数to的地址值结构体变量长度
* @return 成功返回传输的字节数,失败时返回-1
*/
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags,
struct sockaddr *to, socklen_t addrlen);


/**
* @brief 使用UDP套接字接收数据
* @param
* sock 用于接收数据的UDP套接字文件描述符
* buff 保存接收数据的缓冲地址值
* nbytes 可接收的最大字节数,故无法超过参数buff所指的缓冲大小
* flags 可选项参数,若没有则传入0
* from 存有发送端地址信息的sockaddr结构体变量的地址值
* addrlen 保存参数from的结构体变量长度的变量值
* @return 成功返回传输的字节数,失败时返回-1
*/
ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags,
struct sockaddr *from, socklen_t *addrlen);

写一个基于UDP的回声CS,示例地址:https://github.com/XBoom/network-ip.git 中的 apps/socket/07/。运行结果如下

1
2
3
4
5
6
7
[root]#./client 127.0.0.1 5555
12345
[07/client.c:28 main info] client send 12345 to 127.0.0.1
[07/client.c:36 main info] client recv 12345 from 127.0.0.1

[root]#./server 5555
[07/server.c:33 main info] recv message 12345 from 127.0.0.1

从上面可以看出,**CS都不需要连接,**那么客户端地址又是如何分配的,答案是在 sendto的时候,首次调用 sendto 的时候会自动给套接字分配 IP 与端口,然后一直沿用到套接字关闭。

所以

  1. 客户端其实可以使用 connect 当然此处的作用就不是连接,而是分配地址(TCP 也是在这个时候分配的地址);

  2. 又因为套接字有了地址之后,就可以不用 sendto 而直接使用 write 进行发送;

  3. 而且CS均只需要一个套接字(即只需要一个套接字就能和多个主机通信)

image-20240105211959767

所以最后将示例 7 修改为 示例8:https://github.com/XBoom/network-ip.git 中的 apps/socket/08/,效果一致。通过 connect 进行地址分配,通过 read/write 进行消息发送接收。运行结果如下:

1
2
3
4
5
6
[root]#./server 5555
[08/server.c:33 main info] recv message 12345 from 127.0.0.1

[root]#./client 127.0.0.1 5555
12345
[08/client.c:36 main info] recv server response:12345

TIPS:

sendto 函数主要分为三个阶段

  • 向 UDP 套接字注册 IP 地址与端口
  • 传输数据
  • 删除 UDP 套接字中注册的 IP 地址与套接字

sendto 函数每次调用都执行上述三个阶段,将未注册 IP 地址与端口的称为未连接的 UDP 套接字。用于向不同的目标发送数据

相反,通过 connect 将 IP 地址与端口注册到 UDP 套接字,称为 已连接的 UDP 套接字。用于向同一个目标发送数据

参考文档

  1. 《TCPIP 网络编程》