TCP状态转换图

这篇具有很好参考价值的文章主要介绍了TCP状态转换图。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TCP状态转换图
TCP状态转换图,tcp/ip,网络,服务器

了解TCP状态转换图可以帮助开发人员查找问题.
说明: 上图中粗线表示主动方, 虚线表示被动方, 细线部分表示一些特殊情况, 了解即可, 不必深入研究.
对于建立连接的过程客户端属于主动方, 服务端属于被动接受方(图的上半部分)
而对于关闭(图的下半部分), 服务端和客户端都可以先进行关闭.
处于ESTABLISHED状态的时候就可以收发数据了, 双方在通信过程当中一直处于ESTABLISHED状态, 数据传输期间没有状态的变化.
TIME_WAIT状态一定是出现在主动关闭的一方.
主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。

使用netstat -anp可以查看连接状态

注:数据传输的时候带了一个字节的数据, 所以server发送给client的ACK=x+2

为什么需要2MSL?
原因之一: 让四次挥手的过程更可靠, 确保最后一个发送给对方的ACK到达;
若对方没有收到ACK应答, 对方会再次发送FIN请求关闭, 此时在2MS时间内被动关闭方仍然可以发送ACK给对方.

原因之二: 为了保证在2MS时间内, 不能启动相同的SOCKET-PAIR.
TIME_WAIT一定是出现在主动关闭的一方, 也就是说2MS是针对主动关 闭一方来说的;由于TCP有可能存在丢包重传, 丢包重传若发给了已经断 开连接之后相同的socket-pair(该连接是新建的, 与原来的socket-pair完 全相同, 双方使用的是相同的IP和端口), 这样会对之后的连接造成困扰, 严重可能引起程序异常.

如何避免问题2呢??
	--很多操作系统实现的时候, 只要端口被占用, 服务就不能启动.

测试: 启动服务端和客户端, 然后先关闭服务端, 再次启动服务端, 此时服务端报错: bind error: Address already in use; 若是先关闭的客户端, 再关闭的服务端, 此时启动服务端就不会报这个错误.

socket-pair的概念: 客户端与服务端连接其实是一个连接对, 可以通过使用netstat -anp | grep 端口号 进行查看.

端口复用
解决端口复用的问题: bind error: Address already in use, 发生这种情况是在服务端主动关闭连接以后, 接着立刻启动就会报这种错误.

setsockopt函数
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int));
函数说明可参看<<UNIX环境高级编程>>
由于错误是bind函数报出来的, 该函数调用要放在bind之前, socket之后调用.

半关闭状态
半关闭的概念:
如果一方close, 另一方没有close, 则认为是半关闭状态, 处于半关闭状态的 时候, 可以接收数据, 但是不能发送数据. 相当于把文件描述符的写缓冲区 操作关闭了.
注意: 半关闭一定是出现在主动关闭的一方.

shutdown函数
长连接和端连接的概念:
连接建立之后一直不关闭为长连接;
连接收发数据完毕之后就关闭为短连接;

shutdown和close的区别:
shutdown能够把文件描述符上的读或者写操作关闭, 而close关闭文件描述 符只是将连接的引用计数的值减1, 当减到0就真正关闭文件描述符了.
如: 调用dup函数或者dup2函数可以复制一个文件描述符, close其中一个并 不影响另一个文件描述符, 而shutdown就不同了, 一旦shutdown了其中一 个文件描述符, 对所有的文件描述符都有影响 .

心跳包
如何检查与对方的网络连接是否正常??
一般心跳包用于长连接.
方法1
keepAlive = 1;
setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
由于不能实时的检测网络情况, 一般不用这种方法
方法2: 在应用程序中自己定义心跳包, 使用灵活, 能实时把控.

到此为止, 概念相关的东西就讲完毕了.

高并发服务器模型–select

继续研究高并发服务器的问题.
多路IO技术: select, 同时监听多个文件描述符, 将监控的操作交给内核去处理,

数据类型fd_set: 文件描述符集合–本质是位图(关于集合可联想一个信号集sigset_t)
int select(int nfds, fd_set * readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
函数介绍: 委托内核监控该文件描述符对应的读,写或者错误事件的发生.
参数说明:
nfds: 最大的文件描述符+1
readfds: 读集合, 是一个传入传出参数
传入: 指的是告诉内核哪些文件描述符需要监控
传出: 指的是内核告诉应用程序哪些文件描述符发生了变化
writefds: 写文件描述符集合(传入传出参数)
execptfds: 异常文件描述符集合(传入传出参数)
timeout:
NULL–表示永久阻塞, 直到有事件发生
0 --表示不阻塞, 立刻返回, 不管是否有监控的事件发生
>0–到指定事件或者有事件发生了就返回

返回值: 成功返回发生变化的文件描述符的个数
失败返回-1, 并设置errno值.

/usr/include/x86_64-linux-gnu/sys/select.h和
/usr/include/x86_64-linux-gnu/bits/select.h
从上面的文件中可以看出, 这几个宏本质上还是位操作.

void FD_CLR(int fd, fd_set *set);
将fd从set集合中清除.
int FD_ISSET(int fd, fd_set *set);
功能描述: 判断fd是否在集合中
返回值: 如果fd在set集合中, 返回1, 否则返回0.
void FD_SET(int fd, fd_set *set);
将fd设置到set集合中.
void FD_ZERO(fd_set *set);
初始化set集合.

调用select函数其实就是委托内核帮我们去检测哪些文件描述符有可读数据,可写,错误发生;

代码思路:

代码的具体实现: 编写代码并进行测试.

可以使用发生事件的总数进行控制, 减少循环次数
调用select函数涉及到了用户空间和内核空间的数值交互过程.
事件一共包括两部分, 一类是新连接事件, 一类是有数据可读的事件

问题分析: select函数的readfds是一个传出传入参数

测试和总结select用法

关于select的思考:
问题: 如果有效的文件描述符比较少, 会使循环的次数太多.
解决办法: 可以将有效的文件描述符放到一个数组当中, 这样遍历效率就高了.

select优点:
1 一个进程可以支持多个客户端
2 select支持跨平台
select缺点:
1 代码编写困难
2 会涉及到用户区到内核区的来回拷贝
3 当客户端多个连接, 但少数活跃的情况, select效率较低
例如: 作为极端的一种情况, 3-1023文件描述符全部打开, 但是只有1023有发送数据, select就显得效率低下
4 最大支持1024个客户端连接
select最大支持1024个客户端连接不是有文件描述符表最多可以支持1024个文件描述符限制的, 而是由FD_SETSIZE=1024限制的.

FD_SETSIZE=1024 fd_set使用了该宏, 当然可以修改内核, 然后再重新编译内核, 一般不建议这么做.

作业:
编写代码, 让select监控标准输入, 监控网络, 如果标准输入有数据就写入网络, 如果网络有数据就读出网络数据, 然后打印到标准输出.
注意: select不仅可以监控socket文件描述符, 也可以监视标准输入.

预习内容:
poll epoll epoll反应堆

POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准.

关于fd_set类型的底层定义:
/usr/include/x86_64-linux-gnu/sys/select.h和
/usr/include/x86_64-linux-gnu/bits/select.h
在/usr/include/x86_64-linux-gnu/sys/select.h文件中:

__NFDBITS计算出来的值是: 8*8=64

上面是在头文件中一步一步跟踪的定义, 最简单的方法就是使用预处理将头文件和宏全部替换掉, 直接就可以看到最终的定义了.
如: gcc -E select.c -o select.i
打开select.i后
typedef struct
{
__fd_mask __fds_bits[1024 / (8 * (int) sizeof (__fd_mask))];
} fd_set;
进一步转换后:
typedef struct
{
long int __fds_bits[1024/(8*8))];
//long int __fds_bits[16];
}
这个数组一共占用: 8 * 16 * 8 = 1024, 也就是说fd_set这个文件描述符表中一共有1024个bit位, 每个bit位只有0和1两种值, 1表示有, 0表示没有.文章来源地址https://www.toymoban.com/news/detail-616119.html

到了这里,关于TCP状态转换图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Socket网络编程(TCP/IP)实现服务器/客户端通信。

    一.前言 回顾之前进程间通信(无名管道,有名管道,消息队列,共享内存,信号,信号量),都是在同一主机由内核来完成的通信。 那不同主机间该怎么通信呢? 可以使用Socket编程来实现。 Socket编程可以通过网络来实现实现不同主机之间的通讯。 二.Socket编程的网络模型如

    2024年02月08日
    浏览(84)
  • 《TCP/IP网络编程》阅读笔记--基于UDP的服务器端/客户端

    目录 1--TCP和UDP的主要区别 2--基于 UDP 的数据 I/O 函数 3--基于 UDP 的回声服务器端/客户端 4--UDP客户端Socket的地址分配 5--UDP存在数据边界 6--UDP已连接与未连接的设置 ① TCP 提供的是可靠数据传输服务,而 UDP 提供的是不可靠数据传输服务; ② UDP 在结构上比 TCP 更简洁,其不会

    2024年02月09日
    浏览(58)
  • Linux网络编程之TCP/IP实现高并发网络服务器设计指南

    目录 引言: 多进程服务器 例程分享: 多线程服务器  例程分享: I/O多路复用服务器 select 例程分享: poll 例程分享: epoll 例程分享: 总结建议         随着互联网的迅猛发展,服务器面临着越来越多的并发请求。如何设计一个能够高效处理大量并发请求的服务器成为

    2024年02月20日
    浏览(51)
  • 《TCP/IP网络编程》阅读笔记--基于Windows实现Hello Word服务器端和客户端

    目录 1--Hello Word服务器端 2--客户端 3--编译运行 3-1--编译服务器端 3-2--编译客户端 3-3--运行 运行结果:

    2024年02月10日
    浏览(62)
  • 判断服务器IP否被墙 是否被TCP阻断

    现在国内很多购买国外主机服务器的,但往往很多主机商的机子用的人多了,国内使用者用这些服务器做啥的都有,正儿八经的做外贸其实没多大事情,但往往有些人就是不遵守法律法规,长此以往用的人多了,这些国外的主机商提供的服务器ip就会遭到国内的封杀。 今天教

    2024年02月12日
    浏览(55)
  • Linux C/C++ 多线程TCP/UDP服务器 (监控系统状态)

    Linux环境中实现并发TCP/IP服务器。多线程在解决方案中提供了并发性。由于并发性,它允许多个客户端同时连接到服务器并与服务器交互。 Linux多线程编程概述 许多应用程序同时处理多项杂务。服务器应用程序处理并发客户端;交互式应用程序通常在处理后台计算时处理用户

    2024年02月07日
    浏览(40)
  • 【TCP/IP】多进程服务器的实现(进阶) - 多进程服务器模型及代码实现

             经过前面的铺垫,我们已经具备实现并发服务器的基础了,接下来让我们尝试将之前的单任务回声服务器改装成多任务并发模式吧!         在编写代码前,先让我们大致将多任务(回声)服务器的模型抽象一下,如下图所示:         当客户端请求服务(

    2024年02月08日
    浏览(149)
  • 网络字节序——TCP接口及其实现简单TCP服务器

    简单TCP服务器的实现 TCP区别于UDP在于要设置套接字为监控状态,即TCP是面向链接,因此TCP套接字需要设置为监听状态 socket函数原型 domain 表示协议族,常用的有 AF_INET (IPv4)和 AF_INET6 (IPv6)。 type 表示Socket类型,常用的有 SOCK_STREAM (TCP)和 SOCK_DGRAM (UDP)。 protocol 通常可

    2024年02月10日
    浏览(45)
  • TCP/IP客户端和服务器端建立通信过程

    使用Qt提供的类进行基于 TCP 的套接字通信需要用到两个类: QTcpServer 类用于监听客户端连接以及和客户端建立连接,在使用之前先介绍一下这个类提供的一些常用API函数: 构造函数 给监听的套接字设置监听 listen() 函数 在代码中 通过启动监听按钮 设置监听 参数: address :

    2024年02月07日
    浏览(60)
  • 【算法】状态之美,TCP/IP状态转换探索

    最近城市里甲流肆虐,口罩已经成为了出门必备的物品。小悦也不得不开始采取防护措施,上下班过程中,将口罩戴起来以保护自己不受病毒的侵害。 每天下班后,小悦总是喜欢投入到自己的兴趣爱好中,她热衷于翻阅与IT相关的资料,希望能够更深入地了解计算机科学。而

    2024年02月05日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包