网络:TCP连接都是用TCP协议沟通的吗?

本文详细介绍了TCP连接的三次握手过程,包括服务端如何通过静默丢包拒绝连接。客户端在SYN包未收到响应时会进行重试,遵循指数退避原则,每次重试间隔呈指数增长。当多次重试失败后,客户端将放弃连接尝试。此外,文章还提到了在端口未监听时telnet连接失败的问题及其解决方案,涉及iptables、xinetd和telnetd的配置。
摘要由CSDN通过智能技术生成

TCP连接都是用TCP协议沟通的吗?

一般来说,TCP连接是标准的TCP三次握手完成的:

  • 客户端发送SYN
  • 服务端收到SYN之后,回复SYN + ACK
  • 客户端收到SYN + ACK后,回复ACK

这里面SYN会在两端各发送一次,表示“我准备好了,可以开始连接了”。ACK也是两端各发送了一次,表示“我知道你准备好了,我们开始通信把”。

那既然是4个报文,为什么是三次发送呢?显然,服务端的SYN和ACK是合并在一起发送的,就节省了一次发送。这个在英文里叫 Piggybacking,就是背着走,搭顺风车的意思。

如果服务端不想接受这次握手,它会怎么做呢?可能有这么几种情况:

  1. 不搭理这次连接,当做什么都没有收到,什么都没有发生
  2. 给予回复,明确拒绝

第一种情况,因为服务端做了“静默丢包”,也就是虽然收到了SYN,但是它直接丢弃了,也不给客户端回复任何消息。这也导致了一个问题,就是客户端无法分清楚这个SYN到底是以下哪种情况?

  • 在网络上丢失了,服务端收不到,自然不会有回复
  • 对端收到了但是没有回,就是“静默丢包”
  • 对端收到了也回了,但是这个回包在网络中丢了。

在这里插入图片描述

那么,从客户端的角度,对于SYN包发出去之后迟迟没有回应的情况,它的策略是做重试。而且不止一次。那会重试几次呢?重试多久呢? 下面来做个实验

实验

需要两台机器。

  • 第一步,在服务端,执行下面这条命令,让Iptables静默丢弃掉发往自己80端口的数据包
iptables -I INPUT -p tcp --dport 80 -j DROP
  • 第二步,在客户端启动tcpdump抓包
sudo tcpdump -i any -w telnet-80.pcap port 80
  • 第三步,从客户端发起一次telnet(注意,服务端必须先启动telnet服务才能连接):
 telnet 服务端IP 80

这个时候,这个telnet会挂起。
在这里插入图片描述

大约一两分钟后才会失败退出。这时,你可以把客户端的 tcpdump 停掉了(按下 Ctrl+C)。
在这里插入图片描述
在这里插入图片描述

然后用 Wireshark 打开这个抓包文件,看看里面是什么:

telnet挂起的原因就在这里:握手请求一直没有成功。客户端一共有7个SYN包发出,或者说,除了第一次SYN,后继还有6次重试。客户端当然也不是“傻子”,这么多次都失败,就放弃了连接尝试,把失败的消息传递给了用户空间程序,然后就是telent退出。

这里有个信息很值得关注。第二列是数据包之间的时间间隔,也就是 1 秒,2 秒,4.2秒,8.2 秒,16.1 秒,33 秒,每个间隔是上一个的两倍左右。到第6次重试失败之后,客户端就彻底放弃了。

这里的翻倍时间,就是指数退避原则的体现。这里的时间并不是精确的整秒,因为指数退避原则本身就不建议在精确的整秒做重试,最好是有所浮动,这样可以让重试成功的机会变得更大一些。

可能出现的错误

$ telnet 192.168.0.12
Trying 192.168.0.12...
telnet: Unable to connect to remote host: Connection refused

原因:

(1)输入命令netstat -tnl查看端口状态

$  netstat -tnl
激活Internet连接 (仅服务器)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN

可以看到没有进程在监听本地的23端口,说明本地的telnet服务没有启动。

解决

(1)安装xinetd和telnetd

sudo apt-get install xinetd telnetd

(2)创建文件/etc/inetd.conf

$ sudo vi /etc/inetd.conf

并加入以下一行

telnet stream tcp nowait telnetd /usr/sbin/tcpd /usr/sbin/in.telnetd

(3)修改文件/etc/xinetd.conf

$ sudo gedit /etc/xinetd.conf

并修改为以下内容

# Simple configuration file for xinetd
#
# Some defaults, and include /etc/xinetd.d/
defaults
{
# Please note that you need a log_type line to be able to use log_on_success
# and log_on_failure. The default is the following :
# log_type = SYSLOG daemon info
instances = 60
log_type = SYSLOG authpriv
log_on_success = HOST PID
log_on_failure = HOST
cps = 25 30
}
includedir /etc/xinetd.d

(4)创建文件/etc/xinetd.d/telnet

$ sudo gedit /etc/xinetd.d/telnet

并输入以下内容

# default: on
# description: The telnet server serves telnet sessions; it uses \
# unencrypted username/password pairs for authentication.
service telnet
{    
disable = no
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
log_on_failure += USERID
}

(5)启动服务sudo /etc/init.d/xinetd restart

(6)重启系统,查看端口状态

$ netstat -tnl
激活Internet连接 (仅服务器)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp6       0      0 :::23                   :::*                    LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN 

可以看到正在监听23端口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值