(1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。
(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。
(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。
TCP的三次握手可以通过报文来分析:
(1)客户端向服务器端发起同步请求,服务器侧端口固定为 102,客户端端口由 socket 随机产生
(2)服务器端向客户端响应,同时也向客户端发起同步请求
(3)客户端予以确认
2 连接终止协议(四次挥手)
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。
(4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
通过Java代码实现TCP连接三次握手和四次挥手的过程:
package com.zhaoming.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ClientConnect extends Thread
{
//定义一个Client的对象
private Client client;
private Socket socket;
//定义IP和端口号是常量
private static final String IP = "192.168.1.190";
private static final int PORT = 20108;
//声明str是一个静态变量,
public static String str = null;
//进行构造(持有另一个类对象的引用)
public ClientConnect(Client client)
{
this.client = client;
}
//启用线程,处理连接
public void run()
{
try
{
//初始化要连接的socket套接字
socket = new Socket(IP,PORT);
client.getjButton1().setEnabled(false);
}
catch (UnknownHostException e1)
{
e1.printStackTrace();
}
catch (IOException e1)
{
e1.printStackTrace();
}
//从服务器端通过socket读取信息
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//把读到的信息显示到TextArea中
while (true)
{
str = br.readLine();
client.getjTextArea1().append(str + "\n");
//建一个新的文本文档,用于存储从服务器读到的信息
File file = new File("E:/temperatrue.txt");
PrintWriter out = null;
String date = null;
//修改时间显示的格式
SimpleDateFormat sdf = null;
try
{
//把读到的信息,写到到文本文件中存储起来
out = new PrintWriter(new FileOutputStream(file, true));
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
date = sdf.format(new Date());
out.println(date+"\t"+str);
out.flush();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
finally
{
out.close();
}
}
} catch (IOException e)
{
e.printStackTrace();
}
//进行流关闭处理,先进行判断,然后再关闭
finally
{
try
{
if(br != null)
{
br.close();
br =null;
}
if(socket != null)
{
socket.close();
socket = null;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。 TCP协议的连接是全双工连接,一个TCP连接存在双向的读写通道。 简单说来是 “先关读,后关写”,一共需要四个阶段。以客户机发起关闭连接为例: 1.服务器读通道关闭 2.客户机写通道关闭 3.客户机读通道关闭 4.服务器写通道关闭 关闭行为是在发起方数据发送完毕之后,给对方发出一个FIN(finish)数据段。直到接收到对方发送的FIN,且对方收到了接收确认ACK之后,双方的数据通信完全结束,过程中每次接收都需要返回确认数据段ACK。