3.UDP通信
1.UDP协议的特点:
不需要链接, 不可靠传输协议,速度快实时性强,传输数据量小。
2.发送数据端实现的步骤如下:
1. 创建套接字(socket) SOCK_STREAM--TCP, SOCK_DGRAM--UDP
2. 发送数据(sendto)
3.接收数据端的实现步骤如下:
- 创建套接字(socket)
- 绑定端口地址(bind)
- 接收数据(recvfrom)阻塞
Linux提供的函数接口如下:
发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 参数:int sockfd套接字描述符, const void *buf,--要发送的数据 size_t len数据长度 int flags-标志设置为0 const struct sockaddr *dest_addr----数据要发送到的地址, socklen_t addrlen---dest_addr长度 返回值:成功发送的字节数, 失败-1
接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 参数:int sockfd套接字描述符, const void *buf,--要存储接收的数据 size_t len数据长度--buf空间大小 socklen_t addrlen---dest_addr长度//地址长度 int flags-标志设置为0 struct sockaddr *src_addr;---存储发送方的地址端口 socklen_t *addrlen----src_addr指针所指向的空间大小 返回值:成功发送的字节数, 失败-1
发送端的实现代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> //#include < #include <netinet/in.h> #include <arpa/inet.h> int main(void) { //1.创建套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket fail"); exit(1); } //2.发送数据到指定的地址端口 char buffer[128]="hello world"; struct sockaddr_in toaddr; memset(&toaddr, 0, sizeof(toaddr)); toaddr.sin_family = AF_INET; toaddr.sin_port = htons(6666); toaddr.sin_addr.s_addr = inet_addr("192.168.1.240"); size_t size = sendto(sockfd, buffer, strlen(buffer),0, (struct sockaddr*)&toaddr, sizeof(toaddr)); if(size != strlen(buffer) ) { perror("sendto fail"); exit(1); } return 0; }
接收端的实现代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> //#include < #include <netinet/in.h> #include <arpa/inet.h> int main(void) { //1.创建套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket fail"); exit(1); } //2.绑定 struct sockaddr_in toaddr; memset(&toaddr, 0, sizeof(toaddr)); toaddr.sin_family = AF_INET; toaddr.sin_port = htons(6666); toaddr.sin_addr.s_addr = htonl(INADDR_ANY); int ret = bind(sockfd, (struct sockaddr*)&toaddr, sizeof(toaddr)); if(ret < 0) { perror("bind fail"); exit(1); } //3.接收数据 char buffer[128]={0}; struct sockaddr_in saddr; socklen_t len = sizeof(saddr); size_t size = recvfrom(sockfd, buffer, sizeof(buffer),0, (struct sockaddr*)&saddr,&len); if(size < 0 ) { perror("recvfrom fail"); exit(1); } printf("%s\n", buffer); return 0; }
2.套接字的设置 setsockopt
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen); 参数:int sockfd --要设置的套接字 int level --设置级别选择(SOL_SOCKET, IPPROTO_IP) int optname --要与第二参数对应 const void *optval --根据第三个参数后面的数据类型 socklen_t optlen---第四个参数的空间的大小 返回值:成功0, 失败-1
3.设置端口复用 只有最后绑定端口的那个基础讷航才可以接收到端口的数据
int op = 1; int opt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op)); if(opt < 0) { perror("setsockopt fail"); exit(1); }
4.UDP实现广播通信
步骤如下:
在linux首先要通过setsockopt来开启关闭广播(发送端)
int op = 1; int opt = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));
发送广播的流程:
(1)创建套接字(SOCK_DGRAM)
(2)开启广播
(3)发送数据到广播地址(假设是192.168.1.255)
#include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #define BROADCAST_ADDR "192.168.1.255" #define PORT 6666 int main(void) { //1.创建套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket fail"); exit(1); } //开启广播 int op =1; int ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&op, sizeof(op)); if(ret < 0) { perror("开启广播失败"); exit(1); } //2.发送数据到指定的地址端口 char buffer[128]="hello world"; struct sockaddr_in toaddr; memset(&toaddr, 0, sizeof(toaddr)); toaddr.sin_family = AF_INET; toaddr.sin_port = htons(PORT); toaddr.sin_addr.s_addr = inet_addr(BROADCAST_ADDR); size_t size = sendto(sockfd, buffer, strlen(buffer),0, (struct sockaddr*)&toaddr, sizeof(toaddr)); if(size != strlen(buffer) ) { perror("sendto fail"); exit(1); } return 0; }
数据接收端:
(4)创建套接字(socket)
(5)绑定端口地址(bind)
(6)接收数据(recvfrom)阻塞
5.UDP实现组播
组播(多播):只有超级用户才有权限发送组播信息 组播地址 224.0.0.0---239.255.255.255
实现步骤:
发送端:
(1) 创建udp套接字
(2) 发送数据到组播地址
接收端
(1) 创建udp套接字
(2) 绑定地址端口
(3) 加入组播/ 退出组播
要通过setsockopt设置套接字添加到组播组
struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */组播地址 struct in_addr imr_interface; /* local IP address of interface */本地网卡 } mreq; 初始化mreq mreq.imr_multiaddr = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
(4) 接收数据
例子:添加组播数组 struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.100"); mreq.imr_interface.s_addr = htonl(INADDR_ANY); ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
UDP组播发送端的代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> //#include < #include <netinet/in.h> #include <arpa/inet.h> int main(void) { //1.创建套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket fail"); exit(1); } //2.发送数据到指定的地址端口 char buffer[128]="hello world"; struct sockaddr_in toaddr; memset(&toaddr, 0, sizeof(toaddr)); toaddr.sin_family = AF_INET; toaddr.sin_port = htons(6666); toaddr.sin_addr.s_addr = inet_addr("224.0.0.100"); size_t size = sendto(sockfd, buffer, strlen(buffer),0, (struct sockaddr*)&toaddr, sizeof(toaddr)); if(size != strlen(buffer) ) { perror("sendto fail"); exit(1); } return 0; }
接收端的代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> //#include < #include <netinet/in.h> #include <arpa/inet.h> int main(void) { //1.创建套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket fail"); exit(1); } //设置端口复用 int op = 1; int opt = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op)); if(opt < 0) { perror("setsockopt fail"); exit(1); } //2.绑定 struct sockaddr_in toaddr; memset(&toaddr, 0, sizeof(toaddr)); toaddr.sin_family = AF_INET; toaddr.sin_port = htons(6666); toaddr.sin_addr.s_addr = htonl(INADDR_ANY); int ret = bind(sockfd, (struct sockaddr*)&toaddr, sizeof(toaddr)); if(ret < 0) { perror("bind fail"); exit(1); } //加入到组播组 //struct sockaddr_in s; //s.sin_addr.s_addr = inet_addr("192.168.1.51";) struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.100"); mreq.imr_interface.s_addr = htonl(INADDR_ANY); ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); //3.接收数据 char buffer[128]={0}; struct sockaddr_in saddr; socklen_t len = sizeof(saddr); size_t size = recvfrom(sockfd, buffer, sizeof(buffer),0, (struct sockaddr*)&saddr,&len); if(size < 0 ) { perror("recvfrom fail"); exit(1); } printf("%s\n", buffer); return 0; }
PS:哪里写错了请指正,互相学习。