目录
一.自带超时参数的函数
1.1 select函数
1.2 poll函数的自带超时检测参数
二、不带超时检测参数的函数
三、通过信号完成时间的设置
四、更新下载源
五、wireshark使用
5.1. 安装
5.2. wireshark 抓包
5.2.1 wireshark与对应的OSI七层模型
编辑5.2.2 包头分析
5.2.3 ip头
5.2.4udp头
5.2.5tcp头
六、三次握手 四次挥手
6.1三次握手
6.2四次挥手
七、面试总结
一.自带超时参数的函数
1.1 select函数
1、select函数的第五个参数,就是设置的时间
2、当时间到达后,该函数就会接触阻塞
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
and
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
#include<myhead.h>
int main(int argc, const char *argv[])
{
//1、定义检测容器
fd_set readfds;
//2、清空内容
FD_ZERO(&readfds);
//3、将文件描述符放入集合中
FD_SET(0, &readfds);
//4、定义超时时间变量
struct timeval tv = {5, 0};
while(1)
{
tv.tv_sec = 5;
tv.tv_usec = 0;
int res = select(1, &readfds, NULL, NULL, &tv);
if(res == -1)
{
perror("select error");
return -1;
}else if(res == 0)
{
printf("time out\n");
return -1;
}
//判断
if(FD_ISSET(0, &readfds))
{
int num = 0;
scanf("%d", &num);
printf("触发键盘输入:%d\n", num);
}
}
return 0;
}
1.2 poll函数的自带超时检测参数
1、poll函数的第三个参数,是以毫秒为单位的超时时间
2、当时间到达后,会接触阻塞,进而做相关事情
3、是一个整型变量,值传递
#include<myhead.h>
int main(int argc, const char *argv[])
{
//1、定义文件描述符集合
struct pollfd pfd;
pfd.fd = 0; //表示检测的是0号文件描述符
pfd.events = POLLIN; //表示检测读事件
//2、调用函数
while(1)
{
int res = poll(&pfd, 1, 5000);
if(res == -1)
{
perror("poll error");
return -1;
}else if(res == 0)
{
printf("time out\n");
return -1;
}
//判断
if(pfd.revents == POLLIN)
{
int num = 0;
scanf("%d", &num);
printf("触发键盘输入:%d\n", num);
}
}
return 0;
}
二、不带超时检测参数的函数
1> 对于套接字通信时,可以使用setsockopt函数,对应用层的SO_RCVTIMEO进行设置
2> 如果时间已经到达,那么对于的函数会返回-1,并将错误码置为成EAGAIN
#include<myhead.h>
#define SER_IP "192.168.125.113"
#define SER_PORT 8888
#include<errno.h>
int main(int argc, const char *argv[])
{
//1、创建用于连接的套接字文件描述符
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
perror("socket error");
return -1;
}
//3\、设置地址能够快速重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
//2、绑定ip和端口号
//2.1 准备地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //ip地址
//2.2 绑定工作
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) ==-1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3、将套接字设置成被动监听状态
if(listen(sfd, 128)==-1)
{
perror("listen error");
return -1;
}
printf("listen success\n");
//设置接受超时时间
struct timeval tv = {5, 0};
if(setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))==-1)
{
perror("setsockopt error");
return -1;
}
//4、阻塞等待客户端的连接
//4.1 定义用于接受客户端信息的容器
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
int newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
if(newfd == -1)
{
//判断是否因为超时而解除的阻塞
if(errno == EAGAIN)
{
printf("time out\n");
return -1;
}
perror("accept error");
return -1;
}
printf("[%s:%d]:发来连接请求\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
return 0;
}
三、通过信号完成时间的设置
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:设置一个定时器,在时间到达后,会发射一个SIGALRM的信号
参数:以秒为单位的时间, 如果参数设置成0,表示取消该定时器
返回值:如果该定时器之前没有定时器,则返回0,如果该定时器之前有定时器,会返回上一个定时器剩余的秒数,并更新上一个定时器为该定时器
#include<myhead.h>
//定义信号处理函数
void handler(int signo)
{
if(signo == SIGALRM)
{
printf("系统已经随机为您出一张牌\n");
alarm(5);
}
}
int main(int argc, const char *argv[])
{
char ch; //用户选择的牌
//将SIGALRM信号捕获到自定义函数中
if(signal(SIGALRM, handler) == SIG_ERR)
{
perror("signal error");
return -1;
}
while(1)
{
alarm(5); //给出5秒考虑时间
printf("请出牌>>>");
scanf("%c", &ch);
getchar();
printf("您出的牌为:%c\n", ch);
}
return 0;
}
四、更新下载源
cd /etc/apt/
sudo cp sources.list sources.list.save 将原镜像备份
sudo vim sources.list 将原镜像修改成阿里源/清华源,如所述
4.1清华源
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
4.2阿里源
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
上述操作完毕后,保存退出,执行下列
sudo apt-get update:
五、wireshark使用
5.1. 安装
wireshark的官方下载网站:www.wireshark.org/
5.2. wireshark 抓包
开始界面
- wireshark是捕获机器上的某一块网卡的网络包,当你的机器上有多块网卡的时候,你需要选择一个网卡。
- 双击需要的网卡,开始抓包
5.2.1 wireshark与对应的OSI七层模型
服务器和客户端的代码不能都运行在ubuntu,因为wireshark抓的是流经真实网卡的数据包。
若将服务器客户端都运行在ubuntu,数据直接经过虚拟网卡通信,而不会经过真实网卡。
5.2.2 包头分析
以太网头
以太网中封装了源mac地址以及目的mac地址,还有ip类型,以太网又称之为mac头
0X0800 只接收发往本机的mac的ip类型的数据帧
0X0806 只接收发往本机的ARP类型的数据帧
0x8035 只接受发往本机的RARP类型的数据帧
0X0003 接收发往本机的MAC所有类型:ip,arp,rarp数据帧,接收从本机发出去的数据帧,
混杂模式打开的情况下,会接收到非发往本地的MAC数据帧
5.2.3 ip头
IP头中需要掌握用于拆包的部分:id flags fregment_offset
两个IP地址:源IP与目的IP地址。
TTL:time to live, 指定数据帧可以最多经过几个路由器。当数据帧被目标方接收后,TTL清除为0.
Linux TTL:64 Winodws:TTL 128
5.2.4udp头
5.2.5tcp头
Seq:序列号,占4个字节,用于给数据段进行编号的。所有非应答包的数据段,都有seq。
Ack:应答号,用于应答非应答包(握手包,挥手包,数据包)。告诉对方下一次从这个seq编号发送数据包。
SYN:握手包,连接的时候产生的包
FIN:挥手包,断开连接产生的包
PSH:数据包,传输数据时候产生的包
ACK:应答包
PSH Ack = Seq+len;
SYN FIN Ack = Seq+1;
六、三次握手 四次挥手
6.1三次握手
三次握手的发起方,肯定是客户端
- 第一次握手:客户端发送SYN包(SYN=1, seq=0)给服务器,并进入SYN_SENT状态,等待服务器返回确认包。
- 第二次握手:服务器接收到SYN包,确认客户端的SYN,发送ACK包(ACK=1 , ack=1),同时发送一个SYN包(SYN=1, seq=0),并进入SYN_RCVD状态。
- 第三次握手:客户端接收到服务器的SYN包,以及ACK包,进入establish状态,同时向服务器发送ACK包(ACK=1, ack=1)。此时三次握手包发送完毕,服务器也进入establish状态
6.2四次挥手
四次挥手的发起方可能是服务器,也可能是客户端
- 第一次挥手,主动关闭方发送一个FIN包(FIN=1, seq = u)给被动方,进入FIN_WAIT_1状态;
- 第二次挥手:被动方接收到FIN包,给主动方发送一个ACK包(ACK=1, ack=u+1);并进入CLOKSE_WAIT状态。主动方接受到ACK包后,进入FIN_WAIT_2状态。如果有数据没有发送完毕,则继续发送,直到发送完毕为止;
- 第三次挥手:被动方发送一个FIN包(FIN=1, seq=w),进入LAST_ACK状态.
- 第四次挥手:主动关闭方收到FIN包,回复一个ACK包(ACK=1, ack=w+1)。被动关闭方收到主动关闭方的ACK后关闭连接。