目录
1、UDP广播通信
单播:数据包发送方式只有一个接受方
广播:同时发给局域网中的所有主机
只有用户数据报套接字(使用UDP协议)才能广播
以192.168.63.0网段为例:..***.255 代表该网段的广播地址。发送给该地址的数据包被所有主机接收
实现广播的过程(UDP协议)
广播发送端: ----> 添加广播属性
1、建立套接字
2、设置该套接字允许进行广播(将广播属性添加进去),填充服务端的结构体
3、将数据发送到广播地址中(sendto(buf,192.168.x.x))
4、关闭
接收端(服务器): ----> 绑定所有主机(INADDR_ANY)
1、建立套接字
2、填充服务端的结构体,绑定广播地址和端口号(struct sockaddr_in serveraddr,serveraddr.sin_addr.s_addr = htonl(INADDR_ANY)))(需要设置端口复用) 3、创建结构体存放客户端IP和端口,接收数据
4、关闭
//2、将广播属性添加到套接字中 int on = 1; setsockopt(socketfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)); ownaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY代表本机所有地址 常用方法
广播的测试代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define GUANG_IP "192.168.5.255" //---> 你所在局域网的广播地址
#define GUANG_PORT 60000
//udp广播server.c
int main(int argc,char** argv)
{
//如果手动输入IP和地址
// if(argc != 3)
// {
// perror("./a.out IP PORT");
// return -1;
// }
int ret = 0;
char buf[1024] = { 0 };
//1、创建一个套接字文件描述符
int socketfd = socket(AF_INET,SOCK_DGRAM,0);
if(socketfd == -1)
{
perror("socket fail");
return -1;
}
//设置端口复用
int optval = 1;
setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
//2、绑定广播IP和端口号
struct sockaddr_in ownaddr;
ownaddr.sin_family = AF_INET;
//ownaddr.sin_port = htons(atoi(argv[2])); //传参方式
ownaddr.sin_port = htons(GUANG_PORT); //宏定义方式
ownaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY代表本机所有地址 常用方法
ret = bind(socketfd,(struct sockaddr*)&ownaddr,sizeof(struct sockaddr_in));
if(ret == -1)
{
perror("bind fail");
return -1;
}
printf("绑定本机成功[%s][%d]\n",GUANG_IP,GUANG_PORT);
//定义接收结构体,获取IP和端口
struct sockaddr_in recv_addr;
int len = sizeof(struct sockaddr_in);
char *ip =NULL;
int port = 0;
//3、接收数据
while(1)
{
//清空缓冲区
bzero(buf,sizeof(buf));
//接收数据
ret = recvfrom(socketfd,buf,sizeof(buf),0,(struct sockaddr*)&recv_addr,&len);
//解析发送端的ip和地址
ip = inet_ntoa(recv_addr.sin_addr);
port = ntohs(recv_addr.sin_port);
printf("[%s][%d] 接收数据 buf:%s ret:%d\n",ip,port,buf,ret);
if(strcmp(buf,"exit") == 0)
{
break;
}
}
//4、关闭套接字
close(socketfd);
return 0;
}
//udp广播client.c
int main(int argc,char** argv)
{
//如果手动输入IP和地址
// if(argc != 3)
// {
// perror("./a.out IP PORT");
// return -1;
// }
int ret = 0;
char buf[1024] = { 0 };
//1、创建一个套接字文件描述符
int socketfd = socket(AF_INET,SOCK_DGRAM,0);
if(socketfd == -1)
{
perror("socket fail");
return -1;
}
//2、将广播属性添加到套接字中
int on = 1;
setsockopt(socketfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
//指定接收方
struct sockaddr_in send_addr;
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(GUANG_PORT);
send_addr.sin_addr.s_addr = inet_addr(GUANG_IP);
printf("绑定本机成功[%s][%d]\n",GUANG_IP,GUANG_PORT);
//3、发送数据
while(1)
{
//清空缓冲区
bzero(buf,sizeof(buf));
scanf("%s",buf);
ret = sendto(socketfd,buf,strlen(buf),0,(struct sockaddr*)&send_addr,sizeof(struct sockaddr_in));
printf("发送数据 ret=%d\n",ret);
if(strcmp(buf,"exit") == 0)
{
break;
}
}
//4、关闭套接字
close(socketfd);
return 0;
}
2、UDP组播通信
组播是介于单播与广播之间,在一个局域网内,将某些主机添加到组中,并设置一个组地址.我们 只需要将数据发送到组播地址即可,加入到该组的所有主机都能接收到数据
组播特点
1)需要给组播设置IP地址,该IP必须是D类地址
2)只有UDP才能设置组播
3、IP地址分类 IP地址 = 网络号 + 主机号
网络号:指的是不同的网络
主机号:指的是同一个网段下用来识别不同的主机。
那也就是说,主机号所占的位数越多,在该网段下的主机 数越多
A类地址 :保留给政府机构使用
A类IP地址就由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须 是“0”
A类地址范围 1.0.0.1 - 126.255.255.254
B类地址 :分配给中等规模的公司
B类IP地址就由2字节的网络地址和2字节主机地址组成,网络地址的最高位必须 是“10”
B类地址范围 128.0.0.1 - 191.255.255.254
C类地址 :分配给任何需要的人
C类IP地址就由3字节的网络地址和1字节主机地址组成,网络地址的最高位必须 是“110” 13 C类地址范围 192.0.0.1 - 223.255.255.254 //192.168.14.2
D类地址 :用于组播
D类地址范围 224.0.0.1 - 239.255.255.254 //224.0.0.10
E类地址 :用于实验
E类地址范围 240.0.0.1 - 255.255.255.254
特殊地址:
每一个字节都为0的地址(“0.0.0.0”)对应于当前主机;
INADDR_ANY -->代表当前主机所有的地址
127.0.0.1 回环地址 --》在当前主机内部自动形成闭环的网络 --》主要用于主机内部不同的应用程序通信
如果你已经确定当前客户端 和 服务器 都是在同一台主机上运行,那么可以使用这个地址
组播通信的过程
UDP组播发送端
1、建立套接字()
2、发送数据,往群聊(组播地址)中发送数据
3、关闭
UDP组播接收端
1、建立套接字
2.定义组播结构体
3、设置组播ip(初始化 组播结构体)
4.加入组播属性(也就是设置这个套接字 可以接收组播信息)
5、绑定IP地址和端口号
6、进群,加入群聊,将当前的IP地址设置到组播地址中
7、创建结构体存放客户端IP和端口,接收数据
8、关闭
UDP组播的测试代码如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define GROUP_IP "224.0.0.10" //组播地址224开头
#define GROUP_PORT 60000
#define MY_IP "192.168.5.184"
//udp组播server.c
int main()
{
int ret = 0;
//1.建立套接字
int socket_fd = socket(AF_INET,SOCK_DGRAM,0);
if(socket_fd < 0)
{
perror("socket fail");
return -1;
}
//2.定义组播结构体
struct ip_mreq vmreq;
//3、设置组播ip(初始化 组播结构体)
inet_pton(AF_INET,"224.0.0.10",&vmreq.imr_multiaddr); // 组播地址
inet_pton(AF_INET,"192.168.5.184",&vmreq.imr_interface); // 需要添加到组的ip
//4.加入组播属性(也就是设置这个套接字 可以接收组播信息)
setsockopt(socket_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&vmreq,sizeof(vmreq));
//5.绑定本机地址
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;//地址族
my_addr.sin_port = htons(GROUP_PORT);//端口号
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY代表本机所有地址 常用方法 注意
ret = bind(socket_fd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr_in));
if(ret < 0)
{
perror("bind fail");
return -1;
}
printf("绑定本机成功[%s][%d]\n",GROUP_IP,GROUP_PORT);
//6.接收数据
char buf[1024] = {0};
struct sockaddr_in recv_addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
char *ip = NULL;
int port = 0;
while(1)
{
bzero(buf,sizeof(buf));
ret = recvfrom(socket_fd,buf,sizeof(buf),0,(struct sockaddr *)&recv_addr,&addrlen);
ip = inet_ntoa(recv_addr.sin_addr);
port = ntohs(recv_addr.sin_port);
printf("[%s][%d]buf:%s ret:%d\n",ip,port,buf,ret);
}
//关闭套接字
close(socket_fd);
return 0;
}
//udp组播client.c
int main()
{
int ret = 0;
char buf[1024] = { 0 };
//1、建立套接字
int socket_fd = socket(AF_INET,SOCK_DGRAM,0);
if(socket_fd < 0)
{
perror("socket fail");
return -1;
}
//给组播地址发送数据
struct sockaddr_in send_addr;
send_addr.sin_family = AF_INET;//地址族
send_addr.sin_port = htons(GROUP_PORT);//端口号
send_addr.sin_addr.s_addr = inet_addr(GROUP_IP); //ip地址
while(1)
{
//清空缓存区
bzero(buf,sizeof(buf));
scanf("%s",buf);
ret = sendto(socket_fd,buf,strlen(buf),0,(struct sockaddr *)&send_addr,sizeof(struct sockaddr_in ));
printf("发送数据 ret:%d\n",ret);
}
//关闭套接字
close(socket_fd);
return 0;
}