????????Java中使?TCP協議通信,使用ServerSocket來建立鏈接,使用Socket進行通信.
????????ServerSocket
? ? ? ? ServerSocket是創建TCP服務端Socket的api,主要方法:
方法簽名 | 說明 |
ServerSocket(int port) | 創建一個服務端流套接字Socket,并綁定指定端口 |
Socket accpet() | 開始監聽指定端口,有客戶端鏈接后,返回一個服務端Socket對象,基于這個對象與客戶端Socket對象通信,如果沒有客戶端鏈接,則阻塞等待, |
void close() | 關閉套接字 |
? ? ? ? Socket
? ? ? ? socket是客戶端socket或服務端接收到客戶端建立鏈接的請求后,返回的服務端socket.不管是客戶端Socket還是服務端Socket,都是雙方建立鏈接后,保存對端信息并用來通信的.Socket的主要方法:
方法簽名 | 說明 |
Socket(String host,int port) | 創建?個客?端流套接字Socket,并與對應IP的主機上,對應端?的進程建?連接. |
InetAddress?getInetAddress() | 返回套接字所鏈接的地址 |
InputStream getInputStream() | 返回套接字的輸入流 |
OutputStream getOutputStream() | 返回套接字的輸出流 |
? ? ? ? 輸入流InputStream與輸出流OutputStream分別使用Scanner與PrintWrite進行封裝,方便請求與響應的傳輸.
? ? ? ? 建立一個簡單的回顯服務器
? ? ? ? Server
????????服務端負責接收客戶端發送來的數據,然后處理相應邏輯,返回給客戶端一個響應.
public class TCPEchoServer {ServerSocket serverSocket = null;public TCPEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服務器已啟動!");//接受客戶端鏈接Socket clientSocket = serverSocket.accept();processConnection(clientSocket);}private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d]已上線!\n",clientSocket.getInetAddress(),clientSocket.getPort());//獲取socket中的輸入流和輸出流try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){//掃描客戶端請求while (true) {//用Scanner包裝inputStream輸入流 方便獲取請求Scanner scanner = new Scanner(inputStream);if(!scanner.hasNext()){//用戶不再輸入時 跳出循環 當用戶斷開后也為不再輸入System.out.printf("[%s:%d]已下線!\n",clientSocket.getInetAddress(),clientSocket.getPort());break;}String request = scanner.next();//計算響應String response = process(request);//直接使用outputStream的write方法無法返回換行符"\n",導致客戶端處理較為困難//選擇使用PrintWriter包裝outputStream,使用PrintWriter的println方法PrintWriter writer = new PrintWriter(outputStream);writer.println(response);//PrintWriter中存在緩沖區,需要"攢夠一波"數據之后才會真正的發送數據//使用flush方法,沖刷緩沖器,讓緩沖區的內容直接發送出去writer.flush();//打印服務器日志System.out.printf("[%s:%d] req: %s,resp : %s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);}finally {//執行完畢這一次的鏈接后 關閉鏈接clientSocket.close();}}private String process(String request) {return "響應:"+request;}public static void main(String[] args) throws IOException {TCPEchoServer server = new TCPEchoServer(8848);server.start();}
}
? ? ? ? 此時的服務端還存在一個問題,在多個客戶端同時訪問時,后續客戶端無法正常與服務器交互.
? ? ? ? Client
????????客戶端負責向服務端發送請求,并等待接收服務端的響應.
public class TCPEchoClient {private Socket socket = null;public TCPEchoClient(String ip,int port) throws IOException {//new操作完成后 開始建立鏈接 等待服務端acceptsocket = new Socket(ip, port);}public void start(){System.out.println("客戶端已啟動");//接收用戶輸入的請求Scanner input = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream();){//不斷掃描while(true){System.out.print("->");if(!input.hasNext()){break;}//獲取請求String request = input.next();PrintWriter writer = new PrintWriter(outputStream);writer.println(request);writer.flush();//接收服務端響應Scanner netWork = new Scanner(inputStream);String response = netWork.next();//向用戶展示響應System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TCPEchoClient client = new TCPEchoClient("127.0.0.1",8848);client.start();}
}
? ? ?運行結果:
啟動客戶端與服務端,從客戶端發送請求,查看客戶端與服務端的表現.