我要好offer之 网络大总结
1. TCP协议的状态机
TCP一共定义了11种状态,这些状态可以使用 netstat 命令查看

2. TCP建立连接3次握手、释放连接4次握手

TCP包头有4个非常重要的东西:
(1) Sequence Number:包的序列号,用来解决 网路包乱序的问题
(2) Acknowledge Number:ACK确认号,用来实现 超时重传机制(不丢包)
(3) Window:滑动窗口,用来解决 拥塞控制的
(4) TCP flag:包的类型,主要是用来 操控 TCP状态机的
TCP建立连接:三次握手
主要是 初始化 Sequence Number的初始值
通信的双方要互相通知对方自己的初始化的Sequence Number,这个号作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序
SYN超时:server端接收到client发的SYN后 发送了 SYN-ACK之后,此时 client掉线,server端没有收到client回送的ACK,这时连接处于中间状态,既没成功,也没失败,这时,server端每隔一段时间会重发SYN-ACK,Linux下默认重发次数为5,时间间隔依次位1s、2s、4s、8s、16s,第5次发送之后需要等 32s才知道 第5次也超时了,所以,总共需要 1 + 2 + 4 + 8 + 16 + 32 = 2 ^ 6 - 1 = 63s,这时TCP才会彻底断开连接
SYN Flood攻击:人为发起多个连接,在client 收到 server发送的 SYN-ACK之后 恶意掉线,这时服务器默认需要等待63s才断开连接,攻击者就可以把服务器的syn连接的队列耗尽,让正常的连接请求得不到处理。 解决办法:调整TCP参数,减少默认的重试次数、增大SYN队列连接数
TCP释放连接:四次握手
TCP是全双工的,发送发和接收方都需要FIN和ACK
如果server和client同时断开连接,就会进入CLOSING状态,然后到达TIME_WAIT状态
TIME_WAIT状态
为什么有TIME_WAIT状态?
这个状态是主动执行关闭的话会经历的状态,在这个状态停留时间 是最长分节生命期(maximum segment liftime,MSL)的两倍,我们称为2MSL.MSL意思是任何一个IP数据报可能停留在网络中存活 的最长时间,这个时间是一个有限值,不同系统设置不同。RFC建议值是2min,而BSD的传统实现是30s.
TIME_WAIT状态存在有两个理由:
(1) 可靠地实现TCP全双工连接终止
TIME_WAIT确保有足够的时间让 对端接收到了ACK,如果被动关闭的一方 没有收到ACK,就会触发 被动端重发FIN,一来一去正好2个MSL
(2) 允许老的重复分组在网络中消失
假设A->B发送一个分节,中途由于路由器出现故障而缓存在路由器中,A超时重发之后,连接关闭。现在AB又同时使用相同的IP和端口并且 分节序列号也正好匹配的话,那么以前连接丢失的分组就会出现在新的连接而被处理,TIME_WAIT状态 不允许2MSL之内使用相同的端口连接,就不会出现老分组出现在新连接上了
关于TIME_WAIT数量太多?
如果服务器是HTTP服务器,那么设置一个HTTP的 KeepAlive(浏览器会重用一个TCP连接来处理多个HTTP请求)
3. 套接字socket编程


/* rio_readn -robustly read n bytes (unbuffered) */
int rio_readn(int fd, void* usrbuf, size_t n)
{
size_t nleft = n;
int nread = ;
char* bufp = (char*)usrbuf; while(nleft > ) {
nread = read(fd, bufp, nleft);
if (nread < ) {
if(errno == EINTR) { /* interrupted by sig handler return */
nread = ; /* and call read() again */
} else {
return -; /* errno set by read() */
}
} else if (nread == ) {
break; /* EOF */
}
nleft -= nread;
bufp += nread;
}
return (n - nleft); /* return >= 0 */
}
/* rio_writen -robustly write n bytes (unbuffered) */
int rio_writen(int fd, void* usrbuf, size_t n)
{
size_t nleft = n;
int nwrite = ;
char* bufp = (char*)usrbuf;
while(nleft > ) {
nwrite = write(fd, bufp, nleft);
if (nwrite <= ) {
if(errno == EINTR) { /* interrupted by sig handler return */
nwrite = ; /* and call write() again */
} else {
return -; /* errno set by write() */
}
}
nleft -= nwrite;
bufp += nwrite;
}
return (n - nleft);
}
4. 浏览器输入网址的背后
当你输入一个网址的时候,实际会发生什么?
5. Unix I/O模型 阻塞I/O和非阻塞I/O
Unix一共有5中I/O模型
(1) 阻塞式I/O:进程read系统调用,一直阻塞到 内核将数据准备好并成功返回。默认情况下,所有套接字调用都是阻塞的(read、write、connect、accept)
(2) 非阻塞式I/O:进程反复调用read(轮询),如果没有数据准备好,立即返回一个EWOULDBLOCK错误。fcntl函数将默认套接字转换为 non-blocking
(3) I/O多路复用:进程阻塞于select调用,等待可能多个套接字中的任一个变为可读
(4) 信号驱动式I/O:SIGIO
(5) 异步I/O:(POSIX aio_系列函数)




6. 非阻塞I/O
套接字默认状态是阻塞的,可能阻塞的套接字调用可分为以下4类:
(1) 读操作:read、readv、recv、recvfrom、recvmsg
这些函数如果对 阻塞的套接字进行调用,如果该套接字的接收缓冲区中没有数据可读,该进程将投入睡眠(即阻塞),直到有数据可读时才唤醒
这些函数如果对 非阻塞套接字进行调用,如果该套接字的接收缓冲区中没有数据可读,相应调用立即返回一个 EWOULDBLOCK错误
(2) 写操作:write、writev、send、sendto、sendmsg
这些函数如果对 阻塞的套接字进行调用,如果该套接字的发送缓冲区中没有剩余空间可写,该进程将投入睡眠(即阻塞),直到有剩余空间可写时才唤醒
这些函数如果对 非阻塞套接字进行调用,如果该套接字的发送缓冲区中没有剩余空间可写,相应调用立即返回一个 EWOULDBLOCK错误
(3) accept函数
如果对 阻塞套接字进行调用,并且尚无新的连接到达,调用进程将投入睡眠
如果对 非阻塞套接字进行调用,并且尚无新的连接到达,accept调用会立即返回一个 EWOULDBLOCK错误
(4) connect函数
如果对 非阻塞套接字调用 connect函数,并且连接不能立即建立,那么连接的建立能照常发起,不过会返回一个 EINPROGRESS错误
int connect_nonb(int sockfd, const struct sockaddr* addr, socklen_t addrlen, int nsec)
{
int flags = fcntl(sockfd, F_GETFL, );
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); // fcntl设置非阻塞 int error = ;
int ret = connect(sockfd, addr, addrlen);
if (ret < ) {
if (errno != EINPROGRESS) { // 期望的错误是EINPROGRESS,表示连接建立已经启动但是 尚未完成,其他错误一律直接返回-1
return -;
}
} /* Do whatever we want while the connect is taking place. */
if (ret == ) { // 非阻塞connect返回0,表示连接建立完成
fcntl(sockfd, F_SETFL, flags); // 恢复套接字的文件标志并返回
if (error != ) { // 如果getsockopt返回的error变量非0,表示连接建立发生错误
close(sockfd);
errno = error;
return -;
}
return ;
} else { // 非阻塞connect,连接建立已经启动但是尚未完成,调用select等待套接字变为可读或可写
fd_set read_set;
fd_set write_set;
FD_ZERO(&read_set);
FD_SET(sockfd, &read_set);
write_set = read_set; struct timeval tval; // 设置select超时时间
tval.tv_sec = nsec;
tval.tv_usec = ;
ret = select(sockfd + , &read_set, &write_set, NULL, nsec ? &tval : NULL);
if (ret == ) { // select返回0,超时,关闭套接字
close(sockfd);
errno = ETIMEDOUT;
return -;
} // 如果描述符变为可读或可写,调用getsockopt获取套接字的待处理错误(SO_ERROR选项),如果连接成功建立,error值为0,如果连接建立发生错误,error = errno
if (FD_ISSET(sockfd, &read_set) || FD_ISSET(sockfd, &write_set)) {
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < ) {
return -;
}
} else {
err_quit("select error:sockfd not set");
}
}
}
7. I/O多路复用 select vs. epoll
当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里
(1) 进程打开的最大描述符数目
select中 一个进程打开的最大描述符数目由FD_SETSIZE设置,32位默认为1024个(硬编码)
epoll没有FD_SETSIZE的限制,它所支持的FD上限是最大可以打开文件的数目,1GB内存大约10W
(2) FD集合扫描
select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降
epoll每次调用只扫描 "活跃"的socket(一般情况下,任一时间只有部分的socket是"活跃"的),这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的
(3) 内核与用户空间的消息传递
无论是select,poll还是epoll都需要内核把FD消息通知给用户空间
select和poll直接采用 内存拷贝
epoll使用mmap内存共享,避免内存拷贝
for( ; ; )
{
nfds = epoll_wait(epfd, events, , );
for(i = ;i < nfds; ++i)
{
if(events[i].data.fd == listenfd) //有新的连接
{
connfd = accept(listenfd, (sockaddr *)&clientaddr, &clilen); //accept这个连接
ev.data.fd = connfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD, connfd, &ev); //将新的fd添加到epoll的监听队列中
} else if( events[i].events & EPOLLIN ) //接收到数据,读socket
{
n = read(sockfd, line, MAXLINE)) < //读
ev.data.ptr = md; //md为自定义类型,添加数据
ev.events = EPOLLOUT | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);//修改标识符,等待下一个循环时发送数据,异步处理的精髓
}
else if(events[i].events & EPOLLOUT) //有数据待发送,写socket
{
struct myepoll_data* md = (myepoll_data*)events[i].data.ptr; //取数据
sockfd = md->fd;
send(sockfd, md->ptr, strlen((char*)md->ptr), ); //发送数据
ev.data.fd = sockfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); //修改标识符,等待下一个循环时接收数据
}
else
{
//其他的处理
}
}
}
我要好offer之 网络大总结的更多相关文章
- 我要好offer之 二叉树大总结
一. 二叉树定义 二叉树具有天然的递归特性,凡是二叉树相关题,首先应该联想到递归 struct BinTreeNode { BinTreeNode* left; BinTreeNode* right; ...
- 我要好offer之 搜索算法大总结
1. 二分搜索 详见笔者博文:二分搜索的那些事儿,非常全面 2. 矩阵二分搜索 (1) 矩阵每行递增,且下一行第一个元素大于上一个最后一个元素 (2) 矩阵每行递增,且每列也递增 3. DFS 深度优 ...
- 我要好offer之 C++大总结
0. Google C++编程规范 英文版:http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml 中文版:http://zh-g ...
- 我要好offer之 链表大总结
单链表是一种递归结构,可以将单链表看作特殊的二叉树(我把它叫做一叉树) 单链表的定义: /** * Definition for singly-linked list. * struct ListNo ...
- 我要好offer之 系统基础大总结
1. APUE Unix环境高级编程 (1) Unix基础知识: 内核->系统调用->shell和库函数->应用软件 (2) 文件I/O:read函数返回值.进程的文件描述符表.文件 ...
- 我要好offer之 概率题大总结
1. 利用等概率Rand5生成等概率Rand3 Rand5生成等概率Rand3 这个题目可以扩展为:利用等概率RandM生成等概率RandN (M > N) 这里,我们首先明白一个简单的知识点: ...
- 我要好offer之 排序算法大总结
1. 插入排序 (1) 直接插入排序 void StraightInsertionSort(std::vector<int>& num) { || num.size() == ) ...
- 我要好offer之 字符串相关大总结
1. str*系列手写代码 a. 一定要注意末尾'\0'的处理,切记切记 b. 一定要对输入做有效性判断,多用断言就是了 int Strlen(const char* str) { assert(st ...
- Virtual Private Cloud 专有网络 软件定义网络的方式 私有网络 大流量视频、直播类业务
私有网络 VPC_云上网络空间_自定义网络 - 腾讯云 https://cloud.tencent.com/product/vpc 私有网络 VPC 简介 私有网络(Virtual Private C ...
随机推荐
- 题解 P1379 【八数码难题】
传送门 用STL中的queue,map,string写了个广搜,用一个string保存状态(见代码)注:STL比较慢,可以做一些优化(或者开O2) #include<iostream> # ...
- Python——流程控制语句
if语句 条件进行判断,满足,则执行里面 的内容:不满足,则执行if循环下面的语句 基本语法: if 判断条件: 满足后执行语句 1 如果:女人的年龄>30岁,那么:叫阿姨 age_of_gir ...
- 01_4_SERVLET声明周期
01_4_SERVLET声明周期 1. Servlet的生命周期 生命全过程 加载ClassLoader 实例化 new //客户端第一次请求的时候,只new一次 初始化init(ServletCon ...
- OpenCV3.42+VS2017配置+模块计算机类型“X86”与目标计算机类型“x64”冲突”的问题解决
目录 OpenCV3.42+VS2017配置 Visual Studio 2017 第三方依赖设置,附加依赖项和附加库目录 "fatal error LNK1112: 模块计算机类型&quo ...
- FFT快速傅里叶变化
纪念人生第一次FFT 前排感谢iamzky,讲解非常详细 #include<iostream> #include<cstdio> #include<cmath> u ...
- 【线性基】bzoj2322: [BeiJing2011]梦想封印
线性基的思维题+图常见套路 Description 渐渐地,Magic Land上的人们对那座岛屿上的各种现象有了深入的了解. 为了分析一种奇特的称为梦想封印(Fantasy Seal)的特技,需要引 ...
- hive sql 学习笔记
1.coalesce 语法: COALESCE ( expression [ ,...n ] ) 参数: expression 任何类型的表达式. 返回类型: 返回数据类型优先级最高的 express ...
- paper:synthesizable finit state machine design techniques using the new systemverilog 3.0 enhancements之fsm summary
主要是1.不要用1段式写FSM 2.不要用状态编码写one-hot FSM ,要用索引编码写one-hot FSM.
- LeetCode(238) Product of Array Except Self
题目 Given an array of n integers where n > 1, nums, return an array output such that output[i] is ...
- jsp页面上传多个name值到后台
平常利用表单提交的一般都是一个文本框对应一个name,而在后台都是利用request.getParameter(String name);这段代码返回的是一个String类型的参数:而当我们页面上有多 ...
