TCP服務器
他也涉及到兩個核心的類
ServerSocket
Socket
這裏注意:
UDP協議無連接,類似發微信,直接發就行
TCP協議有連接,類似打電話,要接通才能通話。
這裏依然用回顯服務器模式來體會TCP服務器:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpEchoServer {
private ServerSocket serverSocket = null;
public TcpEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服務器啓動");
//進入主循環
while (true) {
//獲取內核連接
Socket clientSocket = serverSocket.accept();
//處理連接
processConnection(clientSocket);
}
}
private void processConnection(Socket clientSocket) {
System.out.printf("[%s:%d] 客戶端上線\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort());
//獲取clientSocket中的流對象
try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()))) {
//客戶端和服務器有時並不是只交互一次
//這時服務器處理的方式
//(短連接)1.一個連接客戶端和服務器只交互一次完畢之後就斷開連接
//(長連接)2.一個連接中客戶端和服務器交互N次,直到滿足一定條件再斷開連接
//當客戶端斷開連接,循環就結束啦
//當斷開連接,readLine或者write就會觸發異常
//此處爲長連接
while (true) {
//客戶端發送的數據必須按行
String request = bufferedReader.readLine();
String response = process(request);
bufferedWriter.write(response+"\n");
System.out.printf("[%s:%d] req: %s;resp %s\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort(),request,response);
}
} catch (IOException e) {
System.out.printf("[%s:%d] 客戶端下線\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort());
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer server = new TcpEchoServer(9090);
server.start();
}
}
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoClient {
//a.啓動客戶端(和服務器建立連接)
//b.進入主循環
//1.讀取用戶輸入內容
//2.構造請求發送給服務器
//3.讀取響應
//4.吧響應顯示在界面
private Socket socket = null;
public TcpEchoClient(String serverIp,int serverPort) throws IOException {
socket = new Socket(serverIp,serverPort);
}
public void start() {
System.out.println("客戶端啓動");
Scanner scanner = new Scanner(System.in);
try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
while (true) {
System.out.print("->");
String request = scanner.nextLine();
if (request.equals("exit")) {
break;
}
//構造請求併發送
bufferedWriter.write(request+"\n");
//讀取響應
//請求和響應格式不一定相同
String response = bufferedReader.readLine();
System.out.println(response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
此時有一個問題:
這裏我們就考慮用線程池來解決這個問題:
節省了頻繁創建和銷燬線程的開銷。