目录
广播与组播(broadcast & multicast)
广播(udp)
理论
● 前面介绍的数据包发送方式只有一个接受方,称为单播
● 如果同时发给局域网中的所有主机,称为广播
● 只有用户数据报(使用UDP协议)套接字才能广播
● 一般被设计成局域网搜索协议
● 广播地址:局域网中主机号最大的一个 192.168.50.255
发送者(客户端)
- 创建数据报套接字
- 由于原本的套接字不允许广播,所以要设置广播属性
- 指定网络信息(接收者)
- 发送消息
- 关闭套接字
只看代码即可,注释不准
接收者(服务器)
- 创建数据报套接字
- 指定网络信息(接收者)
- 绑定套接字
- 接收消息
- 关闭套接字
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char buf[128] = {0};
int ret;
// 1.创建数据报套接字(socket)------------------》有手机
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err");
return -1;
}
printf("sockfd:%d\n", sockfd);
// 2.指定网络信息--------------------------------------》有号码
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_I
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = INADDR_ANY;
int len = sizeof(caddr);
// 3.绑定套接字(bind)------------------------------》绑定手机
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err");
return -1;
}
printf("bind okk\n");
// 4.接收、发送消息(recvfrom sendto)-------》收短信
while (1)
{
// 最后两个参数存放:发送消息的人的信息
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
if (ret < 0)
{
perror("recvfrom err");
return -1;
}
else
{
printf("ip:%s port:%d buf:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port), buf);
memset(buf, 0, sizeof(buf));
}
}
// 5.关闭套接字(close)----------------------------》接收完毕
close(sockfd);
return 0;
}
缺点
广播方式发给所有的主机,过多的广播会大量的占用网络带宽,造成广播风暴,影响正常的通信
广播风暴: 网络长时间被大量的广播数据包所占用,使正常的点对点通信无法正常进行,其外在表现为网络速度奇慢无比,甚至导致网络瘫痪
组(多)播(udp)
理论
● 单播方式只能发给一个接收方。
● 广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常的通信。
● 多播是一个人发送,加入到多播组的人接收数据。
● 多播方式既可以发给多个主机,又能避免像广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)
● D类:224.0.0.0-239.255.255.255
发送者(客户端)
- 创建数据报套接字
- 指定网络信息(接收者)
- 发送消息
- 关闭套接字
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
int ret;
char buf[128];
if (argc != 3)
{
printf("%s <ip> <port>\n", argv[0]);
return -1;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket err");
return -1;
}
printf("%d\n", sockfd);
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]);
while (1)
{
fgets(buf, sizeof(buf), stdin);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] == '\0';
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, sizeof(saddr));
}
close(sockfd);
return 0;
}
接收者(服务器)
- 创建数据报套接字
- 设置多播属性,将自己的IP加入到多播组中。
- 指定网络信息(接收者)
- 绑定套接字
- 接收消息
- 关闭套接字
本地套接字
特性
- socket同样可以用于本地间进程通信,创建套接字时使用本地协议AF_LOCAL或AF_UNIX
- 分为流式套接字和数据报套接字
- 和其他进程间通信相比使用方便、效率更高,常用于前后台进程通信。
流程(tcp为例)
客户端
- socket()
- struct sockaddr_un
- connect
- send
- close
服务器
- socket()
- struct sockaddr_un
- bind
- listen
- accept
- recv
- close