目录
广播
什么是广播?(了解)
广播发送流程
广播接收流程
组播
什么是组播?
组播地址
组播结构体
组播发送流程
组播接收
本地套接字通信
什么是本地套接字通信?
特性
核心代码
程序实例
服务端
客户端
网络编程中的广播是一种通信方式,用于向网络中的多个主机发送消息或数据。它被广泛应用于局域网(LAN)或广域网(WAN)环境中,使得一台主机能够向整个网络中的其他主机发送消息,而不需要逐个发送给每个目标主机。
广播可以被看作是一种单向通信模式,其中发送方将消息广播到网络上的所有主机,而接收方则可以选择是否接收该消息。这使得广播非常适用于一些场景,如发送实时事件通知、传递系统状态更新或进行服务发现等。
在网络编程中,广播通常使用IP协议的特定地址来实现,例如IPv4中的广播地址(通常为255.255.255.255)或IPv6中的多播地址。发送方使用广播地址作为目标地址来发送消息,而接收方可以通过监听广播地址来接收消息。
广播通常使用UDP(用户数据报协议)来发送消息,因为UDP是一种无连接的协议,它不需要在发送前建立连接,这使得广播更加高效。然而,也可以使用TCP(传输控制协议)来进行广播,尽管这需要建立连接并可能带来一些额外的开销。
在实际的网络编程中,广播需要考虑一些安全性和网络规模的问题。由于广播消息可以发送给整个网络,可能存在滥用和安全风险。因此,在实现广播功能时需要进行适当的安全措施,例如对广播消息进行身份验证或加密,以确保只有授权的接收方可以接收和处理广播消息。
总结起来,网络编程中的广播是一种向网络中的多个主机发送消息或数据的通信方式。它利用特定的广播地址和UDP或TCP协议来实现,可以用于实时事件通知、系统状态更新和服务发现等场景。
int on =1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&on,sizeof(on));
//设置属性代码
完整代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
if(argc<2)
{
printf("please input addr and port\n");
return -1;
}
//1.创建数据报套接子
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
//设置发送广播权限
int op = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &op, sizeof(op));
//填充结构体:广播ip和接受方端口
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_addr.s_addr = inet_addr(argv[1]);
char buf[128];
while (1)
{
fgets(buf, sizeof(buf), stdin);
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr, sizeof(addr));
}
close(sockfd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
if(argc<2)
{
printf("please input addr and port\n");
return -1;
}
//1.创建数据报套接子
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
//填充结构体:广播ip和接受方端口
struct sockaddr_in addr,caddr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t len=sizeof(caddr);
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
{
perror("bind err.");
return -1;
}
char buf[128];
while (1)
{
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&caddr,&len);
printf("ip=%s port=%d :%s\n",inet_ntoa(caddr.sin_addr),\
ntohs(caddr.sin_port),buf);
}
close(sockfd);
return 0;
}
组播(Multicast)是一种网络通信方式,用于将数据从一个发送者传输给一组特定的接收者。在组播通信中,发送者只需将数据发送到一个特定的组播组地址,而不需要知道接收者的具体地址。这样,所有加入该组播组的接收者都可以接收到相同的数据。
组播通信适用于需要同时将相同数据发送给多个接收者的场景,例如实时视频流、音频流、多媒体广播、在线会议等。相比单播(Unicast)一对一通信和广播(Broadcast)一对所有通信,组播可以减少网络带宽的使用,因为数据只需发送一次,而不是复制多份发送。
在组播通信中,路由器在网络中负责处理组播数据的传递。它们使用一种称为组播路由协议(Multicast Routing Protocol)的协议来确定数据应传递到哪些接收者。常见的组播路由协议包括多协议标签交换(Multiprotocol Label Switching, MPLS)和协议无关组播(Protocol Independent Multicast, PIM)。
不分网络地址和主机地址,第1字节的前4位固定为1110 。是D类IP
224.0.0.1-239.255.255.255
#include
#include
#include
struct ip_mreq
{
struct in_addr imr_multiaddr; /* 指定多播组IP */
struct in_addr imr_interface; /* 本地网卡地址,通常指定为 INADDR_ANY--0.0.0.0 */
};
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq)); // 初始化 mreq 结构体为 0
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1"); // 设置多播组 IP 地址
mreq.imr_interface.s_addr = INADDR_ANY; // 设置本地网卡地址为任意地址
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
// 设置套接字选项,加入指定的多播组
// 参数说明:
// - sockfd: 套接字描述符
// - IPPROTO_IP: 指定 IP 协议
// - IP_ADD_MEMBERSHIP: 加入多播组的选项
// - &mreq: 指向 ip_mreq 结构体的指针,其中包含要加入的多播组 IP 和本地网卡地址
// - sizeof(mreq): ip_mreq 结构体的大小
//发送端
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
if(argc<2)
{
printf("please input addr and port\n");
return -1;
}
int socked=socket(AF_INET,SOCK_DGRAM,0);
if(socked<0)
{
perror("socket err.");
exit(-1);
}
//绑定结构体
struct sockaddr_in saddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(atoi(argv[2]));//输入端口是字符串,这里得转换一下
saddr.sin_addr.s_addr=inet_addr(argv[1]);//组播ip
char buf[128];
while (1)
{
fgets(buf,sizeof(buf),stdin);
sendto(socked,buf,sizeof(buf),0,(struct sockaddr*)&saddr,sizeof(saddr));
}
close(socked);
return 0;
}
加入多播组的核心代码
//接收端
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
if(argc<2)
{
printf("please input addr and port\n");
return -1;
}
//创建套接字
int socked=socket(AF_INET,SOCK_DGRAM,0);
if(socked<0)
{
perror("socket err.");
exit(-1);
}
//新增操作,将主机IP放到多播组
struct ip_mreq mreq;//多播结构体
mreq.imr_multiaddr.s_addr=inet_addr(argv[1]);//地址
mreq.imr_interface.s_addr=inet_addr("0.0.0.0");
//添加多播组权限
setsockopt(socked,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
//绑定结构体
struct sockaddr_in saddr,caddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(atoi(argv[2]));//端口
saddr.sin_addr.s_addr=inet_addr(argv[1]);//地址
socklen_t len=sizeof(caddr);//提前计算出结构体得长度
//绑定结构体
if(bind(socked,(struct sockaddr*)&saddr,sizeof(saddr))<0)//出现问题
{
perror("bind err.");
return -1;
}
char buf[128];
while (1)
{
//接收客户端发来代码
recvfrom(socked,buf,sizeof(buf),0,(struct sockaddr*)&caddr,&len);
//inet_ntoa从机器到人 ntohs网络字节序到主机
printf("ip =%s port=%d:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buf);
}
close(socked);
return 0;
}
代码结果
本地通信套接字(Local Communication Socket)是一种用于在同一台计算机上进行进程间通信的机制。它允许不同的进程通过在内核中创建的特殊文件描述符来进行相互通信。
本地通信套接字在操作系统中以文件的形式存在,通常称为"Unix域套接字"或"本地域套接字"。与网络套接字不同,本地通信套接字不涉及网络协议栈,而是直接通过内核中的特殊通信机制进行数据传输。
#include
#include
unix_socket = socket(AF_UNIX, type, 0);
// 创建一个 Unix 域套接字
// 参数说明:
// - AF_UNIX: 指定使用 Unix 域协议
// - type: 指定套接字的类型,如 SOCK_STREAM、SOCK_DGRAM 等
// - 0: 在创建套接字时不指定额外选项
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* 本地路径 */
};
struct sockaddr_un myaddr;
bzero(&myaddr, sizeof(myaddr));
myaddr.sun_family = AF_UNIX;
strcpy(myaddr.sun_path, "mysocket"); // 可以指定路径
注意:客户端和服务器是相互依赖的,需要先运行服务器程序,然后再运行客户端程序以建立连接并进行通信。
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
//1.创建本读通信套接字
int sockfd=socket(AF_UNIX,SOCK_STREAM,0);//这里选用了流式套接字
if (sockfd<0)
{
perror("socker err.");
return -1;
}
//2.填充本地通信套接字
struct sockaddr_un saddr;
saddr.sun_family=AF_UNIX;
strcpy(saddr.sun_path,"./test");
unlink("./test");//删除本地套接字
//3.绑定本地套接字
if(bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr))<0)
{
perror("bind err");
return -1;
}
//4.开启监听
if(listen(sockfd,5)<0)
{
perror("listen err.");
return -1;
}
//5.接收连接
int acceptfd=accept(sockfd,NULL,NULL);//不关心发送者是谁,这里填NULL
if(accept<0)
{
perror("accept err.");
return -1;
}
//6.接收
char buf[128];
while (1)
{
int ret=recv(acceptfd,buf,sizeof(buf),0);
if(ret<0)
{
perror("recv err.");
}else if (ret == 0)//在三次握手时出现了
{
printf("client exit.\n");
break;
}else
{
printf("buf:%s\n",buf);
}
}
close(sockfd);
close(acceptfd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
//1.创建本读通信套接字
int sockfd=socket(AF_UNIX,SOCK_STREAM,0);//这里选用了流式套接字
if (sockfd<0)
{
perror("socker err.");
return -1;
}
//2.填充本地通信套接字
struct sockaddr_un saddr;
saddr.sun_family=AF_UNIX;
strcpy(saddr.sun_path,"./test");
//3.建立链接
if(connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr))<0)
{
perror("connect err.");
return -1;
}
char buf[128];
while (1)
{
fgets(buf,sizeof(buf),stdin);
send(sockfd,buf,sizeof(buf),0);//发送信息
}
close(sockfd);//关闭套接字
return 0;
}
结果