Java socket编程详解,TCPUDP实现
用一張圖來認識一下TCP和UDP
TCP點對點的傳輸方式,保證了數據的可達性;UDP只管發送數據,至于服務端能否接收到數據,不在它的保證范圍之內。
下面,我們進入正題。
一、網絡架構模型
TCP/IP協議分為分層架構:物理層、數據鏈路層、網絡層、傳輸層、應用層。
應用層:能被用戶感知到的一層,如瀏覽器的http、https協議,遠程連接工具的ftp、ftps協議等。
傳輸層:兩臺計算機之間的交互數據傳輸,就在這一層完成,傳輸層為上層協議提供端到端的可靠和透明的服務。TCP和UDP就是在這一層,是應用層協議的基礎。進程的端口號,就是在這一層。
網絡層:也就是IP層,兩臺計算機之間進行通信,先通過IP找到目標計算機,再根據端口號定位到具體的進程,然后進行數據傳輸。IP協議是internet 的基礎。
二、socket編程
socket本質是編程語言的API,在Java中就是具體的類,socket 類對TCP/IP和UDP/IP協議進行了封裝,提供一個可以供程序員做開發使用的接口。
TCP和UDP的區別
TCP:
UDP:
TCP 的三次握手
第一次握手:客戶端向服務端發送sny包,包括標記sny=1和數據seq=x,并進入sny_send狀態。
第二次握手:服務端接收到客戶端的TCP報文,確認客戶端發送的數據seq=x沒有問題,向客戶端返回TCP報文,包括標記sny=1,確認ack=x+1,數據seq=y,并進入sny_recv狀態。
第三次握手:客戶端接收到服務端返回的TCP報文,確認服務端發送的數據seq=y沒有問題,向服務端發送TCP報文,包括標記sny=1,確認ack=y+1, seq=x+1,并進入established狀態。
服務端接收到客戶端的TCP報文,進入established狀態,雙方可以進行數據傳輸。
三、TCP協議實現
socket實現的TCP協議客戶端: TcpClient.java
import java.io.*; import java.net.UnknownHostException; import java.util.Scanner; public class TcpClient {private final static String SERVER_IP = "127.0.0.1";private final static int SERVER_PORT = 10888;public static void main(String[] args) throws Exception {TcpClient tcpClient = new TcpClient();Scanner in = new Scanner(System.in);while(true) {String msg = in.next();if("exit".equals(msg)) {break;}tcpClient.startTcpClient(SERVER_IP, SERVER_PORT, msg);}}public void startTcpClient(String ip, int port, String msg) throws Exception {//創建客戶端 socket,并連接服務端IP:portSocket socket = new Socket(ip, port);//打開socket數據輸出流OutputStream outputStream = socket.getOutputStream();PrintWriter printWriter = new PrintWriter(outputStream);//將數據 寫入輸出流printWriter.write(msg);//刷新緩沖區,輸出緩沖區的數據;如果不刷新,服務端接收到數據printWriter.flush();//關閉socket客戶端的輸出流//當socket的寫操作打開后,會一直阻塞,所以,每次寫完數據,需要關閉socket的寫操作socket.shutdownOutput();/************* 客戶端接受服務器返回的數據 ***************///打開socket輸入流InputStream inputStream = socket.getInputStream();//字節流轉字符流,并指定編碼InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");//字符流封裝成緩沖流BufferedReader bufferedReader = new BufferedReader(inputStreamReader);StringBuffer stringBuffer = new StringBuffer();String len = null;while((len = bufferedReader.readLine()) != null) {stringBuffer.append(len);} System.out.println("接收到客戶端返回的數據:" + stringBuffer.toString());//關閉流bufferedReader.close();inputStreamReader.close();inputStream.close();printWriter.close();outputStream.close(); } }socket實現的TCP協議服務端:TcpServer.java
import java.net.ServerSocket; import java.net.Socket; public class TcpServer {public static void main(String[] args) throws Exception {TcpServer tcpServer = new TcpServer();tcpServer.startServer(10888);}public void startServer(int port) throws Exception {//創建一個socket服務端,監聽port 端口ServerSocket serverSocket = new ServerSocket(port);System.out.println("TCP服務器啟動,并監聽端口:" + port);//創建一個連接客戶端的socketSocket socket = null;//創建一個循環,web項目以監聽實現int count = 0;while(true){//監聽客戶端,等待客戶端連接socket = serverSocket.accept();System.out.println("第" + count + "個客戶端請求開始處理!");//創建一個線程,專門處理當前客戶端的請求,以便繼續處理其他客戶端請求,避免阻塞TcpServerThread tcpServerThread = new TcpServerThread(socket);Thread thread = new Thread(tcpServerThread);thread.start();count++;}} }服務端處理客戶端請求的線程: TcpServerThread.java
import java.io.*; import java.net.Socket; public class TcpServerThread implements Runnable {private Socket socket;public TcpServerThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {InputStream inputStream = null;InputStreamReader inputStreamReader = null;BufferedReader bufferedReader = null;PrintWriter printWriter = null;OutputStream outputStream = null;try {//獲取socket 字節輸入流inputStream = socket.getInputStream();//字節流轉字符流,指定編碼inputStreamReader = new InputStreamReader(inputStream,"utf-8");//字符流封裝成緩沖字符流bufferedReader = new BufferedReader(inputStreamReader);StringBuffer stringBuffer = new StringBuffer();String len = null;while((len = bufferedReader.readLine()) != null){stringBuffer.append(len);}System.out.println("客戶端的地址:" + socket.getInetAddress() + ",客戶端的端口:" + socket.getPort() + "接收到客戶端的數據為:" + stringBuffer.toString());/*************** 服務端返回數據給客戶端 ***************/outputStream = socket.getOutputStream();printWriter = new PrintWriter(outputStream);printWriter.write("客戶端你好,我接受到了你的數據:" + stringBuffer.toString());//刷新緩沖區,輸出緩沖區的數據,如果不刷新,客戶端接受不到數據printWriter.flush();//當socket的寫操作打開后,會一直阻塞,所以,每次寫完數據,需要關閉socket的寫操作socket.shutdownOutput();} catch (IOException e) {e.printStackTrace();}finally {try {printWriter.close();outputStream.close();bufferedReader.close();inputStreamReader.close();inputStream.close();} catch (IOException e) {e.printStackTrace();}}} }先啟動服務端,再啟動客戶端,演示動畫:
四、UDP協議的實現
UDP客戶端:UdpClient.java
import java.net.*; import java.util.Scanner; public class UdpClient {public final static String SERVER_IP = "127.0.0.1";public final static int SERVER_PORT = 10999;public final static int BYTE_LENGTH = 1024;public static void main(String[] args) throws Exception {UdpClient udpClient = new UdpClient();Scanner in = new Scanner(System.in);while(true) {String msg = in.next();if("exit".equals(msg)) {break;}udpClient.startUdpClient(SERVER_IP, SERVER_PORT, msg);}}public void startUdpClient(String ip, int port, String msg) throws Exception {//創建一個UDP的客戶端DatagramSocket datagramSocket = new DatagramSocket();//發送給服務端的數據byte[] bytes = msg.getBytes("UTF-8");//封裝數據包,包括數據、服務端IP、服務端端口DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName(ip), port);//發送數據datagramSocket.send(datagramPacket);/*********** 接收服務端發來的消息, 也可以像服務端開啟新的線程 ************///用來接受服務端發來的數據byte[] receiveData = new byte[BYTE_LENGTH];//封裝數據報,用來接收數據DatagramPacket receiveDataPacket = new DatagramPacket(receiveData, receiveData.length);//接受數據,阻塞,直到有數據發來datagramSocket.receive(receiveDataPacket);String serverSendData = new String(receiveDataPacket.getData(),0,receiveDataPacket.getLength(),"UTF-8");System.out.println("服務端返回的數據:" + serverSendData + ",服務端IP:" + receiveDataPacket.getAddress() + ",服務端端口:" + receiveDataPacket.getPort());} }UDP服務端:UdpServer.java
import java.net.*; public class UdpServer {public final static int SERVER_PORT = 10999;public final static int BYTE_LENGTH = 1024;public static void main(String[] args) throws Exception {UdpServer udpServer = new UdpServer();udpServer.startUdpServer(SERVER_PORT);}public void startUdpServer(int port) throws Exception {// 創建UDP服務端,監聽port端口DatagramSocket datagramSocket = new DatagramSocket(port);//創建一個字節數組,用來接受客戶端發來的數據byte[] bytes = new byte[BYTE_LENGTH];//創建數據報,用來接收數據DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);System.out.println("開啟UDP服務端,并監聽端口:" + port);//創建一個循環,接收和處理客戶端發送的數據while (true){//接收客戶端發送的數據,阻塞,直到有客戶端發送數據datagramSocket.receive(datagramPacket);//獲取接收到的數據String receiveData = new String(datagramPacket.getData(),0,datagramPacket.getLength(),"UTF-8");//獲取客戶端IPInetAddress clientIP = datagramPacket.getAddress();//獲取客戶端端口號int clientPort = datagramPacket.getPort();System.out.println("接收到客戶端發送的數據:" + receiveData + ",客戶端IP:" + clientIP + ",客戶端端口:" + clientPort);//服務端返回給客戶端的數據byte[] sendData = ("客戶端你好!"+System.currentTimeMillis()).getBytes("UTF-8");//將數據、客戶端IP、客戶端端口封裝進數據報DatagramPacket里面DatagramPacket sendDataPacket = new DatagramPacket(sendData, sendData.length, clientIP, clientPort);//發送數據datagramSocket.send(sendDataPacket);}} }先啟動服務端,再啟動客戶端,演示動畫:
總結
以上是生活随笔為你收集整理的Java socket编程详解,TCPUDP实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php xirr,一个傻瓜式的计算方法,
- 下一篇: Java Document 工具类