在了解網絡編程之前,我們先了解一下什么叫套接字
套接字即指同一台主機內應用層和運輸層之間的接口
由於這個套接字是建立在網絡上建立網絡應用的可編程接口
因此也將套接字稱為應用程序和網絡之間的應用程序編程接口!
關於TCP和UDP這里就不作太多介紹了,我們知道TCP是面向連接的,UDP是不面向連接的,TCP可靠,UDP不可靠即可!
我們來設計一個應用來示范一下,流程:
- 客戶機從鍵盤讀取一行字符串,並通過套接字發送到服務器。
- 服務器從連接的套接字獲取這行字符串,並對其進行修改(將小寫轉為大寫),最后再發回客戶端。
- 客戶機讀取到服務器發送的修改后的字符串,並輸出到屏幕。
不說太多了,直接上代碼:
TCP套接字編程:
客戶端:
package TCP套接字編程; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.UnknownHostException; public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { // 創建兩個String類型的字符串用來接收和發送字符 String sentence; String modifiedSentence; // 創建輸入流,用來接收鍵盤輸入 BufferedReader inFromUser = new BufferedReader(new InputStreamReader( System.in)); // 創建一個Scoket型的clientScoket用來發起服務器和客戶機之間的連接 String postname = "169.264.187.20";// 客戶端ip地址(請用自己電腦的ip地址代替) Socket clientSocket = new Socket(postname, 6789); // 創建向服務器發送信息的輸出流 DataOutputStream outToServer = new DataOutputStream( clientSocket.getOutputStream()); // 創建輸入流,用來接收來自服務器的字節流 BufferedReader inFromServer = new BufferedReader(new InputStreamReader( clientSocket.getInputStream())); // 讀取要發送的數據 sentence = inFromUser.readLine(); // 向服務器發送數據 outToServer.writeBytes(sentence + '\n'); // 獲取從服務器接收的數據 modifiedSentence = inFromServer.readLine(); // 打印接收數據 System.out.println("From Server:" + modifiedSentence); } }
服務器端:
package TCP套接字編程; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class TCPServer { public static void main(String[] args) throws IOException { // 從客戶端接收的字符串,要發送給客戶端的字符串 String clientSentence; String serverSentence; // 服務器打開6789端口,建立連接 ServerSocket welcomeSocket = new ServerSocket(6789); while (true) {// 服務器的6789端口一直打開 // 用此連接來獲取和發送客戶端數據流 Socket connectionSocket = welcomeSocket.accept(); // 獲取來自客戶端的數據流 BufferedReader inFromClient = new BufferedReader( new InputStreamReader(connectionSocket.getInputStream())); // 准備發送更改后的數據流 DataOutputStream outToClient = new DataOutputStream( connectionSocket.getOutputStream()); // 讀取收到的數據 clientSentence = inFromClient.readLine(); // 將讀取到的數據都中的小寫字母改為大寫字母 serverSentence = clientSentence.toUpperCase() + '\n'; // 發送修改后的數據給客戶端 outToClient.writeBytes(serverSentence); } } }
UDP套接字編程:
客戶端:
package UDP套接字編程; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPClient { public static void main(String[] args) throws IOException { // 讀取鍵盤輸入的字節流 BufferedReader inFromUser = new BufferedReader(new InputStreamReader( System.in)); // 為客戶端創造一個傳輸信息的門,但是並沒有像TCP那樣建立連接 DatagramSocket clientSocket = new DatagramSocket(); // 調用DNS查詢,得到主機名對應的IP地址 InetAddress IPAddress = InetAddress.getByName(null);//null的話得到的是自己的IP地址 System.out.println(IPAddress); // 定義需要發送的字節數組 byte[] sendData = new byte[1024];// 不能動態開數組。。。 // 定義需要接收的字節數組 byte[] receiveData = new byte[1024]; // 將從鍵盤接收到的數據先用字符串存起來 String sentence = inFromUser.readLine(); // 將字符串轉為字節存入sendData sendData = sentence.getBytes(); // 准備發送UDP數據報,里面包含發送內容和目的地址等信息 DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 9878); // 用這個門來發送數據報 clientSocket.send(sendPacket); // 准備獲取從服務器返回的數據報 DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); // 用這個門來接收服務器發的數據報 clientSocket.receive(receivePacket); // 將獲取的數據報轉換為String類型 String modifiedSentence = new String(receivePacket.getData()); // 打印從服務器收到的內容 System.out.println("From Server:" + modifiedSentence + '\n'); // 關閉這個門 clientSocket.close(); } }
服務器端:
package UDP套接字編程; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPServer { public static void main(String[] args) throws IOException { // 創建一個門,在9878端口 DatagramSocket serverSocket = new DatagramSocket(9878); while (true) { // 定義接收數據的字節數組 byte[] receiveData = new byte[1024]; // 定義發送數據的字節數組 byte[] sendData = new byte[1024]; // 創建UDP數據報對象,准備接收UDP數據報 DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); // 接收UDP數據報 serverSocket.receive(receivePacket); // 將收到的UDP數據報轉換為String字符串 String sentence = new String(receivePacket.getData()); // 得到接收到的UDP數據報的源IP地址 InetAddress IPAddress = receivePacket.getAddress(); // 得到接收到的UDP數據報的源端口號 int port = receivePacket.getPort(); // 小寫字母全部變為大寫字母 String capitalized = sentence.toUpperCase(); // 將字符串轉換為字節數組以便發送 sendData = capitalized.getBytes(); // 准備發送字節數組,做好封裝UDP數據報工作 DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); // 通過門正式發送UDP數據報 serverSocket.send(sendPacket); } } }
分析:
先運行服務器端代碼,這樣服務器才能工作:打開相應端口,做好接收數據的准備
然后運行客戶端代碼,發送數據
服務器工作時,對應端口一直的打開的,隨時准備響應客戶端的請求
參考書籍:《計算機網絡自頂向下方法》