认识udp
udp:用户数据报协议
提供面向事务的简单不可靠信息传送服务;
udp不提供数据包分组、组装和不能对数据包进行排序。
udp位于传输层。
udp的可靠性由应用层负责。
常用的UDP端口号有:53(DNS)、69(TFTP)、161(SNMP);
使用UDP协议包括:TFTP、SNMP、NFS、DNS、BOOTP。
udp编程接口
#include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int socket(int domain, int type, int protocol); int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); uint16_t htons(uint16_t hostshort); in_addr_t inet_addr(const char *cp); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
udp编程方案
1:UDP单播,一方发送,一方接收
直接创建udp通信socket,使用sendto向指定的地址发送消息。
接收端也是创建udp通信socket,绑定ip和端口,用recvfrom进行接收。
2:UDP单播,使用多线程实现,可以发送和接收,双方通信。
以上实现的例子,无法实现双工通信。
可以采用多线程的方法,使双方可以同时发送和接收。
主线程实现发送,专门的线程实现接收和处理。
3:UDP单播,使用io多路复用实现,双方通信。
采用io多路复用select对端口进行监听,可读时触发接收,需要写时触发发送(标准输入加入select)。
4:组播,接收端加入到组中,可以给该组发消息,都能收到。
1:认识组播
理解: 加入一个组中,有ip和端口号,往组中对应的端口发消息,该组中所有监听了该端口的程序都可以收到消息。
注意:ip和端口号加入该组中,发送时往该组中对应的端口中发消息,组内监听该端口号的才能收到。
2:使用组播地址
需要使用组播地址 224.0.0.0 ---- 239.255.255.255如下:
1: 组播组可以是永久的也可以是临时的。组播组地址中,有一部分由官方分配的,称为永久组播组。永久组播组保持不变的是它的ip地址,组中的成员构成可以发生变化。永久组播组中成员的数量都可以是任意的,甚至可以为零。那些没有保留下来供永久组播组使用的ip组播地址,可以被临时组播组利用。
2: 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
3: 224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;
4: 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;
5: 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效
3:组播编程
1: 需要设置组播属性,进行发送:
struct in_addr opt; // 将组播地址初始化到这个结构体成员中 inet_pton(AF_INET, "239.0.1.10", &opt.s_addr); setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &opt, sizeof(opt));
2:加入到组播中,进行接收:
// 加入到多播组 struct ip_mreqn opt; // 要加入到哪个多播组, 通过组播地址来区分 inet_pton(AF_INET, "239.0.1.10", &opt.imr_multiaddr.s_addr); opt.imr_address.s_addr = INADDR_ANY; opt.imr_ifindex = if_nametoindex("ens33"); setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt)); struct ip_mreq zu = {0}; zu.imr_multiaddr.s_addr = inet_addr(argv[1]); //设置组播地址 zu.imr_interface.s_addr = inet_addr("0.0.0.0"); int ret = setsockopt(udp_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &zu, sizeof(zu));
5:广播,给XXX.XXX.XXX.255广播地址端口发消息,该网段所有监听了该端口的接收端都能实现接收。
1:认识dup广播
往某个网段,xxx端口发送消息,则该网段所有监听了该端口的都能收到消息。
查询网段,可以用ifconfig命令: broadcast 对应的字段
hlp@hlp:~/Documents/AT_command/linux_port$ ifconfig ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.11.144 netmask 255.255.255.0 broadcast 192.168.11.255 inet6 fe80::7aaf:9514:497c:6cdf prefixlen 64 scopeid 0x20<link> ether 00:0c:29:8a:a9:fa txqueuelen 1000 (Ethernet) RX packets 179772 bytes 98624983 (98.6 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 231502 bytes 81310878 (81.3 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 299314 bytes 20306394 (20.3 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 299314 bytes 20306394 (20.3 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2:udp广播编程
发送端,需要设置广播模式,然后往广播地址中发消息:
nt on = 1;
int ret = setsockopt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
接收端正常接收就好。