网编 day06
- [14. UDP通信](#14. UDP通信)
- [15. 超时检测](#15. 超时检测)
- [16. 广播组播](#16. 广播组播)
- [17. 网络协议头分析](#17. 网络协议头分析)
14. UDP通信
流程
服务器
- 创建套接字------socket
- 指定网络信息
- 绑定套接字------bind
- 收发消息------recvfrom/sendto
客户端
- 创建套接字------socket
- 指定服务器网络信息
- 收发消息------recvfrom/sendto
- 关闭套接字------close
函数接口
接收
c
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
参数:
struct sockaddr *src_addr
发送端的网络信息
socklen_t *addrlen
发送端网络信息结构体大小
返回值:成功返回接收的字节大小,失败返回-1
发送
c
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送数据
参数:
const struct sockaddr *dest_addr
socklen_t addrlen
15. 超时检测
函数本身的参数
c
struct timeval tm = {2, 0};
sel = select(max + 1, &tempfds, NULL, NULL, &tm);
if (sel == 0)
{
printf("time out ......\n");
continue;
}
setsockopt属性设置
协议层:SOL_SOCKET
(应用层)
选项名称 | 说明 | 数据类型 |
---|---|---|
SO_RCVTIMEO | 接收超时 | struct timeval |
SO_SNDTIMEO | 发送超时 | struct timeval |
alarm定时器
c
int ret = alarm(5); // 定时5s
printf("ret = %d\n", ret); // 第一次返回0
sleep(2); // 睡眠2s
ret = alarm(7); // 重新定时7s
printf("ret = %d\n", ret); // 返回上次闹钟剩余时间3s
for(int i = 1; i > -1; i++)
{
printf("i = %d\n", i); // 打印到第7s,闹钟响,发送SIGALRM结束进程
sleep(1);
}
c
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
功能:对接收的指定信号处理
参数:
int signum
:信号
const struct sigaction *act
:新信号属性结构体
struct sigaction *oldact
:原信号属性结构体,可以为NULL
返回值:成功返回0,失败返回-1,更新errno
补充:
c
struct sigaction
{
void (*sa_handler)(int); // 信号处理函数
void (*sa_sigaction)(int, siginfo_t *, void *); // 信号处理函数
sigset_t sa_mask;
int sa_flags; // 信号属性;SA_RESTART自重启属性
void (*sa_restorer)(void);
}
// 设置信号属性
struct sigaction act;
sigaction(SIGALRM, NULL, &act); // 获取原信号属性
act.sa_handler = handler; // 修改属性
sigaction(SIGALRM, &act, NULL); // 设置修改的属性
16. 广播组播
广播
理论
- 单播:数据包的接收方只有一个
- 广播:同时发给局域网中所有主机
- 只有用户数据报套接字(UDP协议)才能广播
- 一般设计成局域网搜索协议
- 广播地址
1. 以192.168.1.0网段为例,最大的主机地址192.168.1.255代表该网段的广播地址
2. 发送到该地址的数据包被所有主机接收
广播发送流程
- socket 创建用户数据报套接字
- setsockopt 缺省创建的套接字不允许广播数据包,需要设置属性
c
int on = 1;
setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- 填充结构体信息
ip:广播地址 port:和接收方一致 - 发送数据:sendto
广播接收流程
- socket 创建用户数据报套接字
- 填充结构体,绑定IP地址和端口
- bind 帮i的那个网络信息
- recvfrom等待接收数据
组播
理论
- 过多的广播会大量占用网络带宽,造成广播风暴,影响正常通信
- 组播是一个人发送,加入到多播组内的人接收
- 多播方式既可以发给多个主机,又能避免像广播一样带来过多负担
组播地址
不分网络地址和主机地址,第1字节的前4位固定为1110。分为D类IP
224.0.0.1------239.255.255.255
224.0.0.0------224.0.0.255:预留的组播地址(永久组播地址),地址224.0.0.0保留不做分配
224.0.1.0------224.0.1.255:公用组播地址
224.0.2.0------238.255.255.255:用户可用的组播地址,全网范围有效
239.0.0.0------239.255.255.255:本地管理组播地址,仅在特定的本地范围有效
组播发送端
- 创建用户数据报套接字
- 接收方地址指定为组播地址
- 指定端口信息
- 发送数据
组播接收端
- 创建数据报套接字
- 加入多播组,打开权限(setsockopt)
- 绑定IP地址(加入组的组IP或0.0.0.0)和端口
- 等待数据接收
c
struct ip_mreq
{
struct in_addr imr_multiaddr; /* 指定多播组IP */
struct in_addr imr_interface; /* 本地网卡地址,通常指定为 INADDR_ANY--0.0.0.0*/};
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
17. 网络协议头分析
数据的封装与传递
