一、TCP編程
TCP協議是面向連接的、可靠地、有序的,以字節流的方式發送數據。java實現TCP通信依靠2個類:客戶端的Socket類和服務器端的ServerSocket類。
基於TCP通信的Socket模型如下:
Socket通信的實現步驟如下:
1. 創建服務器端Socket:ServerSocket和客戶端Socket:Socket;
2. 打開連接到Socket的InputStream/OutputStream;
3. 按照協議對Socket進行讀寫操作;
4. 關閉InputStream和OutputStream和Socket。
下面是一個例子:實現功能是,客戶端向服務端發送一個User類實體對象,服務端每接收到一個請求便開啟一個處理線程將用戶信息打印出來,並向客戶端發送“歡迎登錄”。
1)工程結構
2)服務端和客戶端信息交流類:User
為了能實現傳輸。客戶端和服務端的User類的包結構要一樣,該類必須要序列化
User類
package com.model; import java.io.Serializable; public class User implements Serializable { private int id; private String name; private String password; public User(int id, String name, String password) { super(); this.id = id; this.name = name; this.password = password; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", password=" + password+ "]"; } }
3)服務端
simpleServer類,主要是用於接受請求並開起處理線程
package simpleSocketServer; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; public class simpleServer { public static void main(String[] args){ try { ServerSocket serverSocket = new ServerSocket(9999); int count = 0;// 記錄客戶端的數量 System.out.println("服務器啟動,等待客戶端的連接。。。"); Socket socket = null; while(true){ socket=serverSocket.accept(); ++count; Thread serverHandleThread=new Thread(new ServerHandleThread(socket)); serverHandleThread.setPriority(4); serverHandleThread.start(); System.out.println("上線的客戶端有" + count + "個!"); InetAddress inetAddress = socket.getInetAddress(); System.out.println("當前客戶端的IP地址是:"+inetAddress.getHostAddress()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
ServerHandleThread,服務器對socket進行處理的線程
package simpleSocketServer; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import com.model.User; public class ServerHandleThread implements Runnable{ Socket socket=null; public ServerHandleThread(Socket socket) { super(); this.socket = socket; } @Override public void run() { // TODO Auto-generated method stub OutputStream os = null; PrintWriter pw = null; try { InputStream is = socket.getInputStream(); ObjectInputStream ois=new ObjectInputStream(is); //readObject()方法必須保證服務端和客戶端的User包名一致,要不然會出現找不到類的錯誤 System.out.println("客戶端發送的對象:" + (User) ois.readObject()); socket.shutdownInput();// 禁用套接字的輸入流 os=socket.getOutputStream(); pw=new PrintWriter(os); pw.println("歡迎登錄!"); pw.flush(); socket.shutdownOutput(); } catch (IOException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try{ if(pw!=null){ pw.close(); } if(os!=null){ os.close(); } if(socket!=null){ socket.close(); } }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
4)客戶端
package simpleSocketClient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.nio.file.attribute.UserPrincipalNotFoundException; import javax.sound.midi.MidiDevice.Info; import com.model.User; /** * 基於TCP協議的Socket通信,實現用戶登錄-客戶端 */ public class Client { public static void main(String[] args) { // 1.創建客戶端的Socket,指定服務器的IP和端口 try { Socket socket = new Socket("127.0.0.1", 9999); // 2.獲取該Socket的輸出流,用來向服務器發送信息 OutputStream os = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(new User(1, "root", "123456")); socket.shutdownOutput(); String infoString=null; // 3.獲取輸入流,取得服務器的信息 InputStream is = socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); String info=null; while((info=br.readLine())!=null){ System.out.println("服務器端的信息:" + info); } socket.shutdownInput(); oos.close(); os.close(); is.close(); br.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }