Java TCP通信详解(附带实例)
TCP 协议是英文 Transmission Control Protocol 的缩写,即传输控制文协议。
TCP 协议是一种可靠的网络协议,它在通信实例双方各自创建一个 Socket,在通信双方之间形成网络虚拟链路。
TCP 被称作一种端对端协议,是一种可靠的网络协议,它分别在通信的两端创建一个 Socket,形成可以进行通信的虚拟链路。TCP 通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信。服务器端不可以主动连接客户端,如果客户端没有发送连接请求,它将一直处于等待状态。
在 Java 中有两个用于实现 TCP 程序的类,一个是表示服务器端的 ServerSocket 类,另一个是用于表示客户端的 Socket 类。
在通信时,须先采用“三次握手”方式建立 TCP 连接,形成数据传输通道:
它保证了两台通信设备之间的无差别传输,在连接中可以进行大量数据的传输,传输完毕后要释放已建立的连接。
TCP 是一种可靠的网络通信协议,数据传输安全且完整,但是效率比较低。一些对完整性和安全性要求高的数据采用 TCP 协议传输,比如文件传输和下载,如果文件下载不完全,会导致文件损坏而无法打开。
TCP 的“三次握手”如下图所示:

图 1 TCP的“三次握手”
在图 1 中,客户端先向服务器端发出连接请求,等待服务器进行确认,服务器端收到后向客户端发送一个响应,告诉客户端已经收到了连接请求,最后客户端再次向服务器端发送确认信息,确认连接成功。
上表中列出了 ServerSocket 类的构造方法,通过这些方法可以获得 ServerSocket 类的实例,它还有一些常用方法,如下表所示:
上表中列出了 ServerSocket 类的常用方法,其中 accept() 方法用来接收客户端的请求,当此方法执行后,服务器端程序开始等待,直到客户端发送过来请求,程序才能继续执行,如下图所示。

图 2 TCP服务器端和客户端
在图 2 中,ServerSocket 代表服务器端,Socket 代表客户端,服务器端在调用 accept() 方法后就开始绑定某个端口等待客户端的请求,在客户端发出连接请求后,accept() 方法会将一个 Socket 对象返回给服务器端,用于和客户端实现通信。
Socket 类的常用构造方法如下表所示:
上表中列出了 Socket 类的常用构造方法,通过这些方法可以获得 Socket 类的实例,它还有一些常用方法,如下表所示。
上表中列出了 Socket 类的常用方法,通过这些方法可以使用 TCP 协议进行网络通信。
在运行程序时,必须先运行服务器端程序,服务器端程序如下:
在创建了服务器端程序后,接着来创建客户端程序:
在接收到客户端发送的数据时,服务器端的运行结果如下:
注意,在运行的时候一定要先运行服务器端,再运行客户端,不然在师傅没睡醒的时候来打扰,肯定要吃闭门羹啊。如果不小心先启动了客户端,那么吃了闭门羹的孙悟空就会报 ConnectException 异常,提示“Connection refused”,中文含义为“拒绝连接”,出现错误的原因在于服务器端程序未开启或者连接的端口错误。
TCP 协议是一种可靠的网络协议,它在通信实例双方各自创建一个 Socket,在通信双方之间形成网络虚拟链路。
TCP 被称作一种端对端协议,是一种可靠的网络协议,它分别在通信的两端创建一个 Socket,形成可以进行通信的虚拟链路。TCP 通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信。服务器端不可以主动连接客户端,如果客户端没有发送连接请求,它将一直处于等待状态。
在 Java 中有两个用于实现 TCP 程序的类,一个是表示服务器端的 ServerSocket 类,另一个是用于表示客户端的 Socket 类。
在通信时,须先采用“三次握手”方式建立 TCP 连接,形成数据传输通道:
- 第 1 次握手,客户端向服务器端发送连接请求,等待服务器进行确认;
- 第 2 次握手,服务器端向客户端返回确认响应,通知客户端已经收到了连接请求;
- 第 3 次握手,客户端再次向服务器端发送确认信息,确认连接完成。
它保证了两台通信设备之间的无差别传输,在连接中可以进行大量数据的传输,传输完毕后要释放已建立的连接。
TCP 是一种可靠的网络通信协议,数据传输安全且完整,但是效率比较低。一些对完整性和安全性要求高的数据采用 TCP 协议传输,比如文件传输和下载,如果文件下载不完全,会导致文件损坏而无法打开。
TCP 的“三次握手”如下图所示:

图 1 TCP的“三次握手”
在图 1 中,客户端先向服务器端发出连接请求,等待服务器进行确认,服务器端收到后向客户端发送一个响应,告诉客户端已经收到了连接请求,最后客户端再次向服务器端发送确认信息,确认连接成功。
Java ServerSocket类
在 java.net 包中有一个 ServerSocket 类,它可以实现服务器端程序,其构造方法如下表所示:构造方法 | 方法描述 |
---|---|
public ServerSocket() | 构造非绑定服务器套接字 |
public ServerSocket(int port) | 构造绑定到特定端口的服务器套接字 |
public ServerSocket(int port, int backlog) | 利用指定的 backlog 构造服务器套接字并将其绑定到指定的本地端口号 |
public ServerSocket(int port, int backlog, InetAddress bindAddr) | 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址构造套接字 |
上表中列出了 ServerSocket 类的构造方法,通过这些方法可以获得 ServerSocket 类的实例,它还有一些常用方法,如下表所示:
方法 | 方法描述 |
---|---|
Socket accept() | 监听并接受到此套接字的连接 |
void close() | 关闭此套接字连接 |
InetAddress getInetAddress() | 返回此服务器套接字的本地地址 |
boolean isClosed() | 返回此服务器套接字的关闭状态 |
void bind(SocketAddress endpoint) | 将此服务器套接字绑定到特定地址(IP 地址和端口号) |
上表中列出了 ServerSocket 类的常用方法,其中 accept() 方法用来接收客户端的请求,当此方法执行后,服务器端程序开始等待,直到客户端发送过来请求,程序才能继续执行,如下图所示。

图 2 TCP服务器端和客户端
在图 2 中,ServerSocket 代表服务器端,Socket 代表客户端,服务器端在调用 accept() 方法后就开始绑定某个端口等待客户端的请求,在客户端发出连接请求后,accept() 方法会将一个 Socket 对象返回给服务器端,用于和客户端实现通信。
Java Socket类
在 java.net 包中还提供了一个 Socket 类,它是一个数据报套接字,包含了源 IP 地址和目的 IP 地址以及源端口号和目的端口号的组合,用于发送和接收 TCP 数据。Socket 类的常用构造方法如下表所示:
构造方法 | 方法描述 |
---|---|
public Socket() | 使用系统默认类型的 SocketImpl 对象,创建一个未连接的套接字 |
public Socket(InetAddress address, int port) | 构造一个流套接字并将其连接到指定 IP 地址的指定端口号 |
public Socket(Proxy proxy) | 构造一个未连接的套接字并指定代理类型(如果有),该代理不管其他设置如何都被使用 |
public Socket(String host, int port) | 构造一个流套接字并将其连接到指定主机上的指定端口号 |
上表中列出了 Socket 类的常用构造方法,通过这些方法可以获得 Socket 类的实例,它还有一些常用方法,如下表所示。
方法 | 方法描述 |
---|---|
void close() | 关闭此套接字连接 |
InetAddress getInetAddress() | 返回此套接字连接的 InetAdress 对象 |
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
int getPort() | 返回此套接字连接到的远程端口 |
boolean isClosed() | 返回套接字的关闭状态 |
void shutdownOutput() | 关闭此套接字的输出流 |
上表中列出了 Socket 类的常用方法,通过这些方法可以使用 TCP 协议进行网络通信。
Java TCP网络程序
前面讲解了 java.net 包中 ServerSocket 类和 Socket 类的基本用法,接下来创建一个服务器端程序和一个客户端程序,通过这两个程序来深入理解 TCP 通信的基本原理。在运行程序时,必须先运行服务器端程序,服务器端程序如下:
import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Demo { public static void main(String[] args) throws Exception { // 创建服务器端ServerSocket对象,并指定IP为8081 ServerSocket serverSocket = new ServerSocket(8081); System.out.println("等待接收数据"); // 等待接收客户端的请求 Socket socket = serverSocket.accept(); // 获取输入流,并通过数组接收 InputStream inputStream = socket.getInputStream(); byte[] arr = new byte[1024]; int len; while ((len = inputStream.read(arr)) != -1) { String str = new String(arr, 0, len); System.out.println(str); } // 获取输出流,并向客户端做出响应 OutputStream outputStream = socket.getOutputStream(); outputStream.write("师傅:为师知道了,退下吧".getBytes()); // 释放资源 outputStream.close(); socket.close(); serverSocket.close(); } }程序的运行结果如下:
等待接收数据
在创建了服务器端程序后,接着来创建客户端程序:
import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; public class Demo { public static void main(String[] args) throws Exception { // 准备去给服务器端的师傅问好 System.out.println("准备去叫师傅起床"); // 创建一个Socket对象,并指定接收端的IP为本机IP,端口号为8081; Socket socket = new Socket(InetAddress.getByName("localhost"), 8081); // 获取输出流,并将数据通过输出流传送出去,输出字符串要转为字节 OutputStream outputStream = socket.getOutputStream(); outputStream.write("悟空说:师傅,老孙向您问好来了".getBytes()); // 关闭输出流 socket.shutdownOutput(); // 获取输入流,并定义一个大小为1024字节的数组,用来接收数据 InputStream inputStream = socket.getInputStream(); byte[] arr = new byte[1024]; int len; // 当输入流读取的数据不为空时,往下执行,输出服务器端响应的消息 while ((len = inputStream.read(arr)) != -1) { String str = new String(arr, 0, len); System.out.println(str); } // 释放资源 inputStream.close(); outputStream.close(); socket.close(); } }客户端程序的运行结果如下:
准备去叫师傅起床
唐僧:为师知道了,悟空退下吧
在接收到客户端发送的数据时,服务器端的运行结果如下:
等待接收数据
悟空说:师傅,老孙向您问好来了
注意,在运行的时候一定要先运行服务器端,再运行客户端,不然在师傅没睡醒的时候来打扰,肯定要吃闭门羹啊。如果不小心先启动了客户端,那么吃了闭门羹的孙悟空就会报 ConnectException 异常,提示“Connection refused”,中文含义为“拒绝连接”,出现错误的原因在于服务器端程序未开启或者连接的端口错误。