本篇文章給大家?guī)砹岁P(guān)于java的相關(guān)知識,其中主要介紹了關(guān)于socket編程的相關(guān)內(nèi)容,Socket是網(wǎng)絡(luò)驅(qū)動層提供給應(yīng)用程序的一個接口或者說一種機(jī)制,下面一起來看一下,希望對大家有幫助。
程序員必備接口測試調(diào)試工具:立即使用
Apipost = Postman + Swagger + Mock + Jmeter
Api設(shè)計、調(diào)試、文檔、自動化測試工具
后端、前端、測試,同時在線協(xié)作,內(nèi)容實(shí)時同步
推薦學(xué)習(xí):《java視頻教程》
一、Socket知識
1. Socket概述
(1)Java最初是作為網(wǎng)絡(luò)編程語言出現(xiàn)的,它對網(wǎng)絡(luò)的高度支持,使得客戶端和服務(wù)器端流暢的溝通成為現(xiàn)實(shí)。
(2)在網(wǎng)絡(luò)編程中,使用最多的就是Socket,每一個實(shí)用的網(wǎng)絡(luò)程序都少不了它的參與。
(3)在計算機(jī)網(wǎng)絡(luò)編程技術(shù)中,兩個進(jìn)程或者說兩臺計算機(jī)可以通過一個網(wǎng)絡(luò)通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這種通信鏈路的端點(diǎn)就被稱為“套接字”(英文名稱也就是Socket)。
(4)Socket是網(wǎng)絡(luò)驅(qū)動層提供給應(yīng)用程序的一個接口或者說一種機(jī)制。
(5)使用物流送快遞的例子來說明Socket:
–>發(fā)件人將有收貨人地址信息的貨物送到快遞站,發(fā)件人不用關(guān)心物流是如何進(jìn)行的,貨物被送到收貨人所在地區(qū)的快遞站點(diǎn),進(jìn)行配送,收貨人等待收貨就可以了。
–>這個過程很形象地說明了信息在網(wǎng)絡(luò)中傳遞的過程。其中,貨物就是數(shù)據(jù)信息,2個快遞站點(diǎn)就是2個端點(diǎn)Socket。
(6)信息如何在網(wǎng)絡(luò)中尋址傳遞,應(yīng)用程序并不用關(guān)心,只負(fù)責(zé)準(zhǔn)備發(fā)送數(shù)據(jù)和接收數(shù)據(jù)即可。
2. Socket通信原理
(1)對于編程人員來說,無須了解Socket底層機(jī)制是如何傳送數(shù)據(jù)的,而是直接將數(shù)據(jù)提交給Socket,Socket會根據(jù)應(yīng)用程序提供的相關(guān)信息,通過一系列計算,綁定IP及信息數(shù)據(jù),將數(shù)據(jù)交給驅(qū)動程序向網(wǎng)絡(luò)上發(fā)送。
(2)Socket的底層機(jī)制非常復(fù)雜,Java平臺提供了一些簡單但是強(qiáng)大的類,可以簡單有效地使用Socket開發(fā)通信程序而無須了解底層機(jī)制。
3. java.net包
(1)java.net包提供了若干支持基于套接字的客戶端/服務(wù)器通信的類。
(2)java.net包中常用的類有Socket、ServerSocket、DatagramPacket、DatagramSocket、InetAddress、URL、URLConnection和URLEncoder等。
(3)為了監(jiān)聽客戶端的連接請求,可以使用ServerSocket類。
(4)Socket類實(shí)現(xiàn)用于網(wǎng)絡(luò)上進(jìn)程間通信的套接字。
(5)DatagramSocket類使用UDP協(xié)議實(shí)現(xiàn)客戶端和服務(wù)器套接字。
(6)DatagramPacket類使用DatagramSocket類的對象封裝設(shè)置和收到的數(shù)據(jù)報。
(7)InetAddress類表示Internet地址。
(8)在創(chuàng)建數(shù)據(jù)報報文和Socket對象時,可以使用InetAddress類
二、基于TCP協(xié)議的Socket編程
1.Socket類和ServerSocket類
(1)java.net包的兩個類Socket和ServerSocket,分別用來實(shí)現(xiàn)雙向安全連接的客戶端和服務(wù)器端,它們是基于TCP協(xié)議進(jìn)行工作的,工作過程如同打電話的過程,只有雙方都接通了,才能開始通話。
(2)進(jìn)行網(wǎng)絡(luò)通信時,Socket需要借助數(shù)據(jù)流來完成數(shù)據(jù)的傳遞工作。
(3)一個應(yīng)用程序要通過網(wǎng)絡(luò)向另一個應(yīng)用程序發(fā)送數(shù)據(jù),只要簡單地創(chuàng)建Socket,然后將數(shù)據(jù)寫入到與該Socket關(guān)聯(lián)的輸出流即可。對應(yīng)的,接收方的應(yīng)用程序創(chuàng)建Socket,從相關(guān)聯(lián)的輸入流讀取數(shù)據(jù)即可。
(4)注意:2個端點(diǎn)在基于TCP協(xié)議的Socket編程中,經(jīng)常一個作為客戶端,一個作為服務(wù)器端,也就是遵循client-server模型。
● Socket類
Socket對象在客戶端和服務(wù)器之間建立連接。可用Socket類的構(gòu)造方法創(chuàng)建套接字,并將此套接字連接至指定的主機(jī)和端口。
(1)構(gòu)造方法
–>第一種構(gòu)造方法以主機(jī)名和端口號作為參數(shù)來創(chuàng)建一個Socket對象。創(chuàng)建對象時可能拋出UnknownHostException或IOException異常,必須捕獲它們。
Socket s = new Socket(hostName,port);
–>第二種構(gòu)造方法以InetAddress對象和端口號作為參數(shù)來創(chuàng)建一個Socket對象。構(gòu)造方法可能拋出IOException或UnknownHostException異常,必須捕獲并處理它們。
Socket s = new Socket(address,port);
(2)常用方法
● ServerSocket類
ServerSocket對象等待客戶端建立連接,連接建立以后進(jìn)行通信。
(1)構(gòu)造方法
–>第一種構(gòu)造方法接受端口號作為參數(shù)創(chuàng)建ServerSocket對象,創(chuàng)建此對象時可能拋出IOException異常,必須捕獲和處理它。
ServerSocket ss = new ServerSocket(port);
–>第二種構(gòu)造方法接受端口號和最大隊(duì)列長度作為參數(shù),隊(duì)列長度表示系統(tǒng)在拒絕連接前可以擁有的最大客戶端連接數(shù)。
ServerSocket ss = new ServerSocket(port,maxqu);
(2)常用方法
–>Socket類中列出的方法也適用于ServerSocket類。
–>ServerSocket類具有accept()方法,此方法用于等待客戶端發(fā)起通信,這樣Socket對象就可用于進(jìn)一步的數(shù)據(jù)傳輸。
2.使用Socket編程實(shí)現(xiàn)登錄功能
● 實(shí)現(xiàn)單用戶登錄
–>Socket網(wǎng)絡(luò)編程一般分成如下4個步驟進(jìn)行:
(1)建立連接。
(2)打開Socket關(guān)聯(lián)的輸入/輸出流。
(3)從數(shù)據(jù)流中寫入信息和讀取信息。
(4)關(guān)閉所有的數(shù)據(jù)流和Socket。
–>使用兩個類模擬實(shí)現(xiàn)用戶登錄的功能,實(shí)現(xiàn)客戶端向服務(wù)器端發(fā)送用戶登錄信息,服務(wù)器端顯示這些信息。
客戶端實(shí)現(xiàn)步驟:
1)建立連接,連接指向服務(wù)器及端口。
2)打開Socket關(guān)聯(lián)的輸入/輸出流。
3)向輸出流中寫入信息。
4)從輸入流中讀取響應(yīng)信息。
5)關(guān)閉所有的數(shù)據(jù)流和Socket。
服務(wù)器端實(shí)現(xiàn)步驟:
1)建立連接,監(jiān)聽端口。
2)使用accept()方法等待客戶端發(fā)起通信
3)打開Socket關(guān)聯(lián)的輸入/輸出流。
4)從輸入流中讀取請求信息。
5)向輸出流中寫入信息。
6)關(guān)閉所有的數(shù)據(jù)流和Socket。
–>客戶端和服務(wù)器端的交互,采用一問一答的模式,先啟動服務(wù)器進(jìn)入監(jiān)聽狀態(tài),等待客戶端的連接請求,連接成功以后,客戶端先“發(fā)言”,服務(wù)器給予“回應(yīng)”。
示例01:實(shí)現(xiàn)傳遞對象信息。
♥ user類
package cn.bdqn.demo02; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; /** 用戶名 */ private String loginName; /** 用戶密碼 */ private String pwd; public User() { super(); } public User(String loginName, String pwd) { super(); this.loginName = loginName; this.pwd = pwd; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }登錄后復(fù)制♥ LoginServer類
package cn.bdqn.demo02; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ObjectInputStream ois = null; OutputStream os = null; try { // 建立一個服務(wù)器Socket(ServerSocket),指定端口8800并開始監(jiān)聽 serverSocket = new ServerSocket(8800); // 使用accept()方法等待客戶端發(fā)起通信 socket = serverSocket.accept(); // 打開輸入流 is = socket.getInputStream(); // 反序列化 ois = new ObjectInputStream(is); // 獲取客戶端信息,即從輸入流讀取信息 User user = (User) ois.readObject(); if (user != null) { System.out.println("我是服務(wù)器,客戶登錄信息為:" + user.getLoginName() + "," + user.getPwd()); } // 給客戶端一個響應(yīng),即向輸出流中寫入信息 String reply = "歡迎你,登錄成功"; os = socket.getOutputStream(); os.write(reply.getBytes()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { // 關(guān)閉資源 try { os.close(); ois.close(); is.close(); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }登錄后復(fù)制LoginClient類
package cn.bdqn.demo02; 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; public class LoginClient { /* * 示例02:升級演示示例01,實(shí)現(xiàn)傳遞對象信息。 */ public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is = null; BufferedReader br = null; try { // 建立客戶端Socket連接,指定服務(wù)器的位置為本機(jī)以及端口為8800 socket = new Socket("localhost", 8800); // 打開輸出流 os = socket.getOutputStream(); // 對象序列化 oos = new ObjectOutputStream(os); // 發(fā)送客戶端信息,即向輸出流中寫入信息 User user = new User("Tom", "123456"); oos.writeObject(user); socket.shutdownOutput(); // 接收服務(wù)器端的響應(yīng),即從輸入流中讀取信息 is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String reply; while ((reply = br.readLine()) != null) { System.out.println("我是客戶端,服務(wù)器的響應(yīng)為:" + reply); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { br.close(); is.close(); oos.close(); os.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }登錄后復(fù)制
示例02:升級演示示例01,實(shí)現(xiàn)傳遞多個對象信息。
user類
package cn.bdqn.demo03; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; /** 用戶名 */ private String loginName; /** 用戶密碼 */ private String pwd; public User() { super(); } public User(String loginName, String pwd) { super(); this.loginName = loginName; this.pwd = pwd; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }登錄后復(fù)制LoginServer類
package cn.bdqn.demo03; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ObjectInputStream ois = null; OutputStream os = null; try { // 建立一個服務(wù)器Socket(ServerSocket),指定端口8800并開始監(jiān)聽 serverSocket = new ServerSocket(8800); // 使用accept()方法等待客戶端發(fā)起通信 socket = serverSocket.accept(); // 打開輸入流 is = socket.getInputStream(); // 反序列化 ois = new ObjectInputStream(is); // 獲取客戶端信息,即從輸入流讀取信息 User[] users = (User[]) ois.readObject(); for (int i = 0; i < users.length; i++) { System.out.println("我是服務(wù)器,客戶登錄信息為:" + users[i].getLoginName() + "," + users[i].getPwd()); } // 給客戶端一個響應(yīng),即向輸出流中寫入信息 String reply = "歡迎你,登錄成功"; os = socket.getOutputStream(); os.write(reply.getBytes()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { // 關(guān)閉資源 try { os.close(); ois.close(); is.close(); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }登錄后復(fù)制LoginClient類
package cn.bdqn.demo03; 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; public class LoginClient { /* * 示例02:升級演示示例01,實(shí)現(xiàn)傳遞對象信息。 */ public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is = null; BufferedReader br = null; try { // 建立客戶端Socket連接,指定服務(wù)器的位置為本機(jī)以及端口為8800 socket = new Socket("localhost", 8800); // 打開輸出流 os = socket.getOutputStream(); // 對象序列化 oos = new ObjectOutputStream(os); // 發(fā)送客戶端信息,即向輸出流中寫入信息 User user1 = new User("Tom", "123456"); User user2 = new User("bob", "123456"); User user3 = new User("lisa", "123456"); User[] users = {user1,user2,user3}; oos.writeObject(users); socket.shutdownOutput(); // 接收服務(wù)器端的響應(yīng),即從輸入流中讀取信息 is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String reply; while ((reply = br.readLine()) != null) { System.out.println("我是客戶端,服務(wù)器的響應(yīng)為:" + reply); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { br.close(); is.close(); oos.close(); os.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }登錄后復(fù)制
● 實(shí)現(xiàn)多客戶端用戶登錄
–>一問一答的模式在現(xiàn)實(shí)中顯然不是人們想要的。一個服務(wù)器不可能只針對一個客戶端服務(wù),一般是面向很多的客戶端同時提供服務(wù)的,但是單線程實(shí)現(xiàn)必然是這樣的結(jié)果。
–>解決這個問題的辦法是采用多線程的方式,可以在服務(wù)器端創(chuàng)建一個專門負(fù)責(zé)監(jiān)聽的應(yīng)用主服務(wù)程序、一個專門負(fù)責(zé)響應(yīng)的線程程序。這樣可以利用多線程處理多個請求。
->客戶端實(shí)現(xiàn)步驟:
1)建立連接,連接指向服務(wù)器及端口。
2)打開Socket關(guān)聯(lián)的輸入/輸出流。
3)向輸出流中寫入信息。
4)從輸入流中讀取響應(yīng)信息。
5)關(guān)閉所有的數(shù)據(jù)流和Socket。
–>服務(wù)器端實(shí)現(xiàn)步驟:
1)創(chuàng)建服務(wù)器線程類,run()方法中實(shí)現(xiàn)對一個請求的響應(yīng)處理。
2)修改服務(wù)器端代碼,讓服務(wù)器端Socket一直處于監(jiān)聽狀態(tài)。
3)服務(wù)器端每監(jiān)聽到一個請求,創(chuàng)建一個線程對象并啟動。
示例03:升級演示示例02,實(shí)現(xiàn)多客戶端的響應(yīng)處理。
user類
package cn.bdqn.demo04; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1L; /** 用戶名 */ private String loginName; /** 用戶密碼 */ private String pwd; public User() { super(); } public User(String loginName, String pwd) { super(); this.loginName = loginName; this.pwd = pwd; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }登錄后復(fù)制LoginThread
package cn.bdqn.demo04; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.Socket; public class LoginThread extends Thread { /* * 示例03:升級示例02,實(shí)現(xiàn)多客戶端的響應(yīng)處理。 * * 分析如下: * (1)創(chuàng)建服務(wù)器端線程類,run()方法中實(shí)現(xiàn)對一個請求的響應(yīng)處理。 * (2)修改服務(wù)器端代碼,讓服務(wù)器端Socket一直處于監(jiān)聽狀態(tài)。 * (3)服務(wù)器端每監(jiān)聽到一個請求,創(chuàng)建一個線程對象并啟動 */ Socket socket = null; //每啟動一個線程,連接對應(yīng)的Socket public LoginThread(Socket socket) { this.socket = socket; } //啟動線程,即響應(yīng)客戶請求 public void run() { InputStream is = null; ObjectInputStream ois = null; OutputStream os = null; try { //打開輸入流 is = socket.getInputStream(); //反序列化 ois = new ObjectInputStream(is); //獲取客戶端信息,即從輸入流讀取信息 User user = (User)ois.readObject(); if(user!=null){ System.out.println("我是服務(wù)器,客戶登錄信息為:"+user.getLoginName()+","+user.getPwd()); } //給客戶端一個響應(yīng),即向輸出流中寫入信息 os = socket.getOutputStream(); String reply = "歡迎你,登錄成功"; os.write(reply.getBytes()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ try { os.close(); ois.close(); is.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }登錄后復(fù)制LoginServer類
package cn.bdqn.demo04; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class LoginServer { public static void main(String[] args) { ServerSocket serverSocket = null; try { // 建立一個服務(wù)器Socket(ServerSocket)指定端口并開始監(jiān)聽 serverSocket = new ServerSocket(8800); // 監(jiān)聽一直進(jìn)行中 while (true) { // 使用accept()方法等待客戶發(fā)起通信 Socket socket = serverSocket.accept(); LoginThread loginThread = new LoginThread(socket); loginThread.start(); } } catch (IOException e) { e.printStackTrace(); } } }登錄后復(fù)制♥ LoginClient1類
package cn.bdqn.demo04; 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; public class LoginClient01 { /* * 客戶端通過輸出流向服務(wù)器端發(fā)送請求信息 * 服務(wù)器偵聽客戶端的請求得到一個Socket對象,將這個Socket對象傳遞給線程類 * 線程類通過輸入流獲取客戶端的請求并通過輸出流向客戶端發(fā)送響應(yīng)信息 * 客戶端通過輸入流讀取服務(wù)器發(fā)送的響應(yīng)信息 * */ /* * 示例03:升級演示示例02,實(shí)現(xiàn)多客戶端的響應(yīng)處理 */ public static void main(String[] args) { Socket socket = null; OutputStream os = null; ObjectOutputStream oos = null; InputStream is = null; BufferedReader br = null; try { // 建立客戶端Socket連接,指定服務(wù)器的位置為本機(jī)以及端口為8800 socket = new Socket("localhost", 8800); // 打開輸出流 os = socket.getOutputStream(); // 對象序列化 oos = new ObjectOutputStream(os); // 發(fā)送客戶端信息,即向輸出流中寫入信息 User user = new User("Tom", "123456"); oos.writeObject(user); socket.shutdownOutput(); // 接收服務(wù)器端的響應(yīng),即從輸入流中讀取信息 is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String reply; while ((reply = br.readLine()) != null) { System.out.println("我是客戶端,服務(wù)器的響應(yīng)為:" + reply); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { br.close(); is.close(); oos.close(); os.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }登錄后復(fù)制♥ LoginClient2類和LoginClient3類
同LoginClient1類一樣,創(chuàng)建不同的User對象即可
–>java.net包中的InetAddress類用于封裝IP地址和DNS。要創(chuàng)建InetAddress類的實(shí)例,可以使用工廠方法,因?yàn)榇祟悰]有構(gòu)造方法。
–>InetAddress類中的工廠方法
–>如果找不到主機(jī),兩種方法都將拋出UnknownHostNameException異常。
三、基于UDP協(xié)議的Socket編程
TCP | UDP | |
是否連接 | 面向連接 | 面向非連接 |
傳輸可靠性 | 可靠 | 不可靠 |
速度 | 慢 | 快 |
1.DatagramPacket類和DatagramSocket類
(1)基于TCP的網(wǎng)絡(luò)通信是安全的,是雙向的,如同打電話,需要先有服務(wù)端,建立雙向連接后,才開始數(shù)據(jù)通信。
(2)基于UDP的網(wǎng)絡(luò)通信只需要指明對方地址,然后將數(shù)據(jù)送出去,并不會事先連接。這樣的網(wǎng)絡(luò)通信是不安全的,所以只應(yīng)用在如聊天系統(tǒng)、咨詢系統(tǒng)等場合下。
(3)數(shù)據(jù)報是表示通信的一種報文類型,使用數(shù)據(jù)報進(jìn)行通信時無須事先建立連接,它是基于UDP協(xié)議進(jìn)行的。
(4)Java中有兩個可使用數(shù)據(jù)報實(shí)現(xiàn)通信的類,即DatagramPacket和DatagramSocket。
(5)DatagramPacket類起到容器的作用,DatagramSocket類用于發(fā)送或接收DatagramPacket。
(6)DatagramPacket類不提供發(fā)送或接收數(shù)據(jù)的方法,而DatagramSocket類提供send()方法和receive()方法,用于通過套接字發(fā)送和接收數(shù)據(jù)報。
● DatagramPacket類
(1)構(gòu)造方法
–>客戶端要向外發(fā)送數(shù)據(jù),必須首先創(chuàng)建一個DatagramPacket對象,再使用DatagramSocket對象發(fā)送。
(2)常用方法
● DatagramSocket類
(1)構(gòu)造方法
–>DatagramSocket類不維護(hù)連接狀態(tài),不產(chǎn)生輸入/輸出數(shù)據(jù)流,它的唯一作用就是接收和發(fā)送DatagramPacket對象封裝好的數(shù)據(jù)報。
(2)常用方法
2.使用Socket編程實(shí)現(xiàn)客戶咨詢
–>利用UDP通信的兩個端點(diǎn)是平等的,也就是說通信的兩個程序關(guān)系是對等的,沒有主次之分,甚至它們的代碼都可以完全是一樣的,這一點(diǎn)要與基于TCP協(xié)議的Socket編程區(qū)分開來。
–>基于UDP協(xié)議的Socket網(wǎng)絡(luò)編程一般按照以下4個步驟進(jìn)行:
(1)利用DatagramPacket對象封裝數(shù)據(jù)包。
(2)利用DatagramSocket對象發(fā)送數(shù)據(jù)包。
(3)利用DatagramSocket對象接收數(shù)據(jù)包。
(4)利用DatagramPacket對象處理數(shù)據(jù)包。
–>模擬客戶咨詢功能,實(shí)現(xiàn)發(fā)送方發(fā)送咨詢問題,接收方接收并顯示發(fā)送來的咨詢問題。
發(fā)送方實(shí)現(xiàn)步驟:
1)獲取本地主機(jī)的InetAddress對象。
2)創(chuàng)建DatagramPacket對象,封裝要發(fā)送的信息。
3)利用DatagramSocket對象將DatagramPacket對象數(shù)據(jù)發(fā)送出去。
接收方實(shí)現(xiàn)步驟:
1)創(chuàng)建DatagramPacket對象,準(zhǔn)備接收封裝的數(shù)據(jù)。
2)創(chuàng)建DatagramSocket對象,接收數(shù)據(jù)保存于DatagramPacket對象中。
3)利用DatagramPacket對象處理數(shù)據(jù)。
示例04:發(fā)送方發(fā)送咨詢問題,接收方回應(yīng)咨詢。
♥ Receive類
package cn.bdqn.demo05; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; import java.net.SocketException; public class Receive { public static void main(String[] args) { /* * 示例06:發(fā)送方發(fā)送咨詢問題,接收方回應(yīng)咨詢。 * * 接收方實(shí)現(xiàn)步驟如下: * (1)創(chuàng)建DatagramPacket對象,準(zhǔn)備接收封裝的數(shù)據(jù)。 * (2)創(chuàng)建DatagramSocket對象,接收數(shù)據(jù)保存于DatagramPacket對象中。 * (3)利用DatagramPacket對象處理數(shù)據(jù)。 */ DatagramSocket ds = null; DatagramPacket dp = null; DatagramPacket dpto = null; // 創(chuàng)建DatagramPacket對象,用來準(zhǔn)備接收數(shù)據(jù) byte[] buf = new byte[1024]; dp = new DatagramPacket(buf, 1024); try { // 創(chuàng)建DatagramSocket對象,接收數(shù)據(jù) ds = new DatagramSocket(8800); ds.receive(dp); // 顯示接收到的信息 String mess = new String(dp.getData(), 0, dp.getLength()); System.out.println(dp.getAddress().getHostAddress() + "說:" + mess); String reply = "你好,我在,請咨詢!"; // 顯示與本地對話框 System.out.println("我 說:" + reply); // 創(chuàng)建DatagramPacket對象,封裝數(shù)據(jù) SocketAddress sa = dp.getSocketAddress(); dpto = new DatagramPacket(reply.getBytes(), reply.getBytes().length, sa); ds.send(dpto); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { ds.close(); } } }登錄后復(fù)制♥ Send類
package cn.bdqn.demo05; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; public class Send { /* * 示例06:升級示例05,發(fā)送方發(fā)送咨詢問題,接收方回應(yīng)咨詢。 * * 發(fā)送方實(shí)現(xiàn)步驟如下: * (1)獲取本地主機(jī)的InetAddress對象。 * (2)創(chuàng)建DatagramPacket對象,封裝要發(fā)送的信息。 * (3)利用DatagramSocket對象將DatagramPacket對象數(shù)據(jù)發(fā)送出去。 */ public static void main(String[] args) { DatagramSocket ds = null; InetAddress ia = null; String mess = "你好,我想咨詢一個問題。"; System.out.println("我說:" + mess); try { // 獲取本地主機(jī)地址 ia = InetAddress.getByName("localhost"); // 創(chuàng)建DatagramPacket對象,封裝數(shù)據(jù) DatagramPacket dp = new DatagramPacket(mess.getBytes(), mess.getBytes().length, ia, 8800); // 創(chuàng)建DatagramSocket對象,向服務(wù)器發(fā)送數(shù)據(jù) ds = new DatagramSocket(); ds.send(dp); byte[] buf = new byte[1024]; DatagramPacket dpre = new DatagramPacket(buf, buf.length); ds.receive(dpre); // 顯示接收到的信息 String reply = new String(dpre.getData(), 0, dpre.getLength()); System.out.println(dpre.getAddress().getHostAddress() + "說:" + reply); } catch (UnknownHostException e) { e.printStackTrace(); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { ds.close(); } } }登錄后復(fù)制
推薦學(xué)習(xí):《java視頻教程》