一、什麼是TCP通信?
- TCP通信能實現兩臺計算機之間的數據交互,通信的兩端,要嚴格區分爲客戶端(Client)與服務器(Server)
二、兩端通信時步驟:
- 服務端程序,需要事先啓動,等待客戶端的連接。
- 客戶端主動連接服務器端,連接成功才能通信。服務端不可以主動連接客戶端。
服務端先啓動
服務器端不會主動的請求客戶端
必須使用客戶端請求服務器端
客戶端和服務端就會建立一個邏輯連接
而這個連接中包含一個對象
這個對象就是IO對象
客戶端和服務器端就可以使用
IO對象進行通信
通信的數據不僅僅是字符
所以IO對象是字節流對象
三、在Java中,提供了兩個類用於實現TCP通信程序:
- 客戶端:
java.net.Socket
類表示。創建Socket對象,向服務端發出連接請求,服務端響應請求,兩者建立連接開始通信。 - 服務端:
java.net.ServerSocket
類表示。創建ServerSocket對象,相當於開啓一個服務,並等待客戶端的連接。
Socket類:
Socket
類:該類實現客戶端套接字,套接字指的是兩臺設備之間通訊的端點
構造方法:
public Socket(String host, int port)
:創建套接字對象並將其連接到指定主機上的指定端口號。如果指定的host是null,則相當於指定地址爲回送地址。
構造代碼如下:
Socket client = new Socket("127.0.0.1",6666);
四、服務器必須明確兩件事情:
- 多個客戶端同時和服務器進行交互,服務器必須明確和哪個客戶端進行的交互。在服務端有一個方法,叫accept客戶端獲取到請求的客戶端對象
- 多個客戶端同時和服務器進行交互,就需要使用多個IO流對象
服務器是沒有IO流的,服務器可以獲取到請求的客戶端對象Socket,使用每個客戶端Socket中提供的IO流和客戶端進行交互
服務器使用客戶端的字節輸入流讀取客戶端發送的數據;服務器使用客戶端的字節輸出流給客戶端回寫數據
五、代碼示例詳解
服務端代碼示例:
package Internet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
TCP通信的服務器端:接收客戶端的請求,讀取客戶端發送的數據,給客戶端回寫數據
表示服務器的類:
java.net.ServerSocket 此類實現服務器套接字
構造方法:
ServerSocket(int port) 創建綁定到特定端口的服務器套接字
服務器端必須明確一件事情,必須知道是哪個客戶端請求的服務器
所以可以使用accept方法獲取到請求的客戶端對象Socket
成員方法:
Socket accept() 監聽並接受到此套接字的連接
服務器的實現步驟:
1. 創建服務器ServerSocket對象和系統要指定的端口號
2. 使用ServerSocket對象中的方法accept,獲取請求的客戶端對象Socket
3. 使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象
4. 使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端發送的數據
5. 使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象
6. 使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫數據
7. 釋放資源
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
//1. 創建服務器ServerSocket對象和系統要指定的端口號
ServerSocket server = new ServerSocket(9999);
//2. 使用ServerSocket對象中的方法accept,獲取請求的客戶端對象Socket
Socket socket = server.accept();
//3. 使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象
InputStream is = socket.getInputStream();
//4. 使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端發送的數據
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
//5. 使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象
OutputStream os = socket.getOutputStream();
//6. 使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫數據
os.write("收到謝謝!".getBytes());
//7. 釋放資源
socket.close();
server.close();
}
}
客戶端代碼示例:
package Internet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*
TCP通信的客戶端:向服務器發送連接請求,給服務器發送數據,讀取服務器回寫的數據
表示客戶端的類:
java.net.Socket:此類實現客戶端套接字。套接字是兩臺機器之間通信的端點。
套接字:包含了IP地址和端口號的網絡單位
構造方法:
Socket(String host, int port) 創建一個流套接字並將其連接到指定主機上的指定端口號
參數:
String host:服務器主機的名稱/服務器的IP地址
int port:服務器的端口號
成員方法:
OutputStream getOutputStream() 返回此套接字的輸出流
InputStream getInputStream() 返回此套接字的輸入流
void close() 關閉此套接字
實現步驟:
1. 創建一個客戶端對象Socket,構造方法綁定服務器的IP地址和端口號
2. 使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象
3. 使用網絡字節輸出流OutputStream對象中的方法write,給服務器發送數據
4. 使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象
5. 使用網絡字節輸入流InputStream對象中的方法read,讀取服務器回寫的數據
6. 釋放資源(Socket)
注意:
1. 客戶端和服務器進行交互,必須使用Socket中提供的網絡流,不能使用自己創建的流對象
2. 當我們創建客戶端對象Socket的時候,就會去請求服務器和服務器經過三次握手建立連接通路
這時如果服務器沒有啓動,那麼就會拋出異常
如果服務器已經啓動,那麼就可以進行交互了
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
//1. 創建一個客戶端對象Socket,構造方法綁定服務器的IP地址和端口號
Socket socket = new Socket("127.0.0.1",9999);
//2. 使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream
OutputStream os = socket.getOutputStream();
//3. 使用網絡字節輸出流OutputStream對象中的方法write,給服務器發送數據
os.write("你好服務器".getBytes());
//4. 使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象
InputStream is = socket.getInputStream();
//5. 使用網絡字節輸入流InputStream對象中的方法read,讀取服務器回寫的數據
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
//6. 釋放資源(Socket)
socket.close();
}
}
運行結果:
現運行服務端,再運行客戶端