通过Socket通信理解TCP机制

1 篇文章 0 订阅
1 篇文章 0 订阅

通过Socket通信理解TCP

1、什么是TCP协议

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。即客户端和服务器之间在交换数据之前会先建立一个TCP连接,才能相互传输数据。并且提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

2、什么是Socket协议

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。socket里面已经封装好了UDP和TCP/IP协议,直接使用就可以了。

网上好多说TCP 三次握手 四次挥手,如下图
完整流程

那么什么是三次握手四次挥手,我们通过实践来理解并检验一下真理。

通过代码运行来分析TCP

服务端

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

class TcpServer {

	public static void main(String[] args) {
		try {
			ServerSocket ss = new ServerSocket(10002);// 建立服务端的socket服务
			Socket s = ss.accept();// 获取客户端对象
			String ip = s.getInetAddress().getHostAddress();
			System.out.println(ip + ".....connected");
			InputStream in = s.getInputStream();
			byte[] buf = new byte[1024];
			int len = in.read(buf);
			String text = new String(buf, 0, len);
			System.out.println("接收到客户端消息:" + text);
			OutputStream out = s.getOutputStream();
			out.write("Server Message".getBytes());
			s.close();
			ss.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

服务端接受客户端的消息,并回复“Server Message”,最后关闭Socket和 ServerSocket

客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TcpClient {

    public static void main(String[] args) {

		try {
			Socket s = new Socket("127.0.0.1", 10002);
			OutputStream out = s.getOutputStream();// 获取了socket流中的输出流对象。
			out.write("Client message".getBytes());
			InputStream in = s.getInputStream();// 获取了socket流中的输出流对象。
			byte[] buf = new byte[1024];
			int len = in.read(buf);
			String text = new String(buf, 0, len);
			System.out.println("接收到服务端消息:" + text);
			s.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

客户端在建立连接后发送一条消息“Client message”到服务器,最后关闭socket。

需要注意,代码中可以理解到,客户端收到消息后,发起的断开请求

首先运行服务端(10002端口),在运行客户端(系统随机建立端口)
通过 Wireshark 工具进行监听,如图

服务端口10002,客户端口52500
全流程

1、进行三次握手
第一次握手
客户端主动打开,发送连接请求报文段,将SYN标识位置为1,Sequence Number置为x(TCP规定SYN=1时不能携带数据,x为随机产生的一个值),然后进入SYN_SEND状态。
第二次握手
服务器收到SYN报文段进行确认,将SYN标识位置为1,ACK置为1,Sequence Number置为y,Acknowledgment Number置为x+1,然后进入SYN_RECV状态,这个状态被称为半连接状态。
第三次握手
客户端再进行一次确认,将ACK置为1(此时不用SYN),Sequence Number置为x+1,Acknowledgment Number置为y+1发向服务器,最后客户端与服务器都进入ESTABLISHED状态。

2、进行数据传输
由哪一端发送的数据就有那一段标记为PSH,ACK
另一端回复 标记为ACK
客户端发送给服务器
客户端发送到服务器

服务器发送到客户端
服务器发送到客户端

这一部分内容涉及了TCP 的深层次内容和精髓,有传输超时相关问题,阻塞相关问题,请参考其他文章:
https://www.cnblogs.com/duan2/p/9180861.html
https://www.cnblogs.com/linuxprobe-sarah/p/10634626.html

3、进行四次挥手
第一次挥手: 关闭客户端到服务器的连接:首先客户端A发送一个FIN,用来关闭客户到服务器的数据传送,然后等待服务器的确认。其中终止标志位FIN=1,序列号seq=u。
第二次挥手: 服务器收到这个FIN,它发回一个ACK,确认号ack为收到的序号加1。
第三次挥手: 关闭服务器到客户端的连接:也是发送一个FIN给客户端。
第四次挥手: 客户段收到FIN后,并发回一个ACK报文确认,并将确认序号seq设置为收到序号加1。
首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。(这也就是为什么在客户端后面写的 “需要注意,代码中可以理解到,客户端收到消息后,发起的断开请求”

  • 客户端A发送FIN后,进入终止等待状态, 服务器B收到客户端A连接释放报文段后,就立即给客户端A发送确认,然后服务器B就进入close-wait状态,此时TCP服务器进程就通知上层应用进程,因而从A到B的连接就释放了。此时是“半关闭”状态。即A不可以发送给B,但是B可以发送给A。

  • 此时,若B没有数据报要发送给A了,其应用进程就通知TCP释放连接,然后发送给A连接释放报文段,并等待确认。A发送确认后,进入time-wait,注意,此时TCP连接还没有释放掉,然后经过时间等待计时器设置的2MSL后,A才进入到close状态。
    为什么要等待2MSL呢?

  • MSL即Maximum Segment Lifetime,也就是最大报文生存时间,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。引用《TCP/IP详解》中的话:“它(MSL)是任何报文段被丢弃前在网络内的最长时间”。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

参考:https://blog.csdn.net/laomumu1992/article/details/83011898

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值