Java網路編程
- 2019 年 10 月 3 日
- 筆記
內容介紹
- 網路通訊協議
- UDP通訊
- TCP通訊
1 網路通訊協議
通過電腦網路可以使多台電腦實現連接,位於同一個網路中的電腦在進行連接和通訊時需要遵守一定的規則,這就好比在道路中行駛的汽車一定要遵守交通規則一樣。在電腦網路中,這些連接和通訊的規則被稱為網路通訊協議,它對數據的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通訊雙方必須同時遵守才能完成數據交換。
網路通訊協議有很多種,目前應用最廣泛的是TCP/IP協議(Transmission Control Protocal/Internet Protoal傳輸控制協議/英特網互聯協議),它是一個包括TCP協議和IP協議,UDP(User Datagram Protocol)協議和其它一些協議的協議組,在學習具體協議之前首先了解一下TCP/IP協議組的層次結構。
在進行數據傳輸時,要求發送的數據與收到的數據完全一樣,這時,就需要在原有的數據上添加很多資訊,以保證數據在傳輸過程中數據格式完全一致。TCP/IP協議的層次結構比較簡單,共分為四層,如圖所示。
上圖中,TCP/IP協議中的四層分別是應用層、傳輸層、網路層和鏈路層,每層分別負責不同的通訊功能,接下來針對這四層進行詳細地講解。
鏈路層:鏈路層是用於定義物理傳輸通道,通常是對某些網路連接設備的驅動協議,例如針對光纖、網線提供的驅動。
網路層:網路層是整個TCP/IP協議的核心,它主要用於將傳輸的數據進行分組,將分組數據發送到目標電腦或者網路。
傳輸層:主要使網路程式進行通訊,在進行網路通訊時,可以採用TCP協議,也可以採用UDP協議。
應用層:主要負責應用程式的協議,例如HTTP協議、FTP協議等。
1.1 IP地址和埠號
要想使網路中的電腦能夠進行通訊,必須為每台電腦指定一個標識號,通過這個標識號來指定接受數據的電腦或者發送數據的電腦。
在TCP/IP協議中,這個標識號就是IP地址,它可以唯一標識一台電腦,目前,IP地址廣泛使用的版本是IPv4,它是由4個位元組大小的二進位數來表示,如:00001010000000000000000000000001。由於二進位形式表示的IP地址非常不便記憶和處理,因此通常會將IP地址寫成十進位的形式,每個位元組用一個十進位數字(0-255)表示,數字間用符號“.”分開,如 “192.168.1.100”。
隨著電腦網路規模的不斷擴大,對IP地址的需求也越來越多,IPV4這種用4個位元組表示的IP地址面臨枯竭,因此IPv6 便應運而生了,IPv6使用16個位元組表示IP地址,它所擁有的地址容量約是IPv4的8×1028倍,達到2128個(算上全零的),這樣就解決了網路地址資源數量不夠的問題。
通過IP地址可以連接到指定電腦,但如果想訪問目標電腦中的某個應用程式,還需要指定埠號。在電腦中,不同的應用程式是通過埠號區分的。埠號是用兩個位元組(16位的二進位數)表示的,它的取值範圍是0~65535,其中,0~1023之間的埠號用於一些知名的網路服務和應用,用戶的普通應用程式需要使用1024以上的埠號,從而避免埠號被另外一個應用或服務所佔用。
接下來通過一個圖例來描述IP地址和埠號的作用,如下圖所示。
從上圖中可以清楚地看到,位於網路中一台電腦可以通過IP地址去訪問另一台電腦,並通過埠號訪問目標電腦中的某個應用程式。
1.2 InetAddress
了解了IP地址的作用,我們看學習下JDK中提供了一個InetAdderss類,該類用於封裝一個IP地址,並提供了一系列與IP地址相關的方法,下表中列出了InetAddress類的一些常用方法。
上圖中,列舉了InetAddress的四個常用方法。其中,前兩個方法用於獲得該類的實例對象,第一個方法用於獲得表示指定主機的InetAddress對象,第二個方法用於獲得表示本地的InetAddress對象。通過InetAddress對象便可獲取指定主機名,IP地址等,接下來通過一個案例來演示InetAddress的常用方法,如下所示。
public class Example01 { public static void main(String[] args) throws Exception { InetAddress local = InetAddress.getLocalHost(); InetAddress remote = InetAddress.getByName("www.itcast.cn"); System.out.println("本機的IP地址:" + local.getHostAddress()); System.out.println("itcast的IP地址:" + remote.getHostAddress()); System.out.println("itcast的主機名為:" + remote.getHostName()); } }
2 UDP與TCP協議
在介紹TCP/IP結構時,提到傳輸層的兩個重要的高級協議,分別是UDP和TCP,其中UDP是User Datagram Protocol的簡稱,稱為用戶數據報協議,TCP是Transmission Control Protocol的簡稱,稱為傳輸控制協議。
2.1 UDP協議
UDP是無連接通訊協議,即在數據傳輸時,數據的發送端和接收端不建立邏輯連接。簡單來說,當一台電腦向另外一台電腦發送數據時,發送端不會確認接收端是否存在,就會發出數據,同樣接收端在收到數據時,也不會向發送端回饋是否收到數據。
由於使用UDP協議消耗資源小,通訊效率高,所以通常都會用於音頻、影片和普通數據的傳輸例如影片會議都使用UDP協議,因為這種情況即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。
但是在使用UDP協議傳送數據時,由於UDP的面向無連接性,不能保證數據的完整性,因此在傳輸重要數據時不建議使用UDP協議。UDP的交換過程如下圖所示。
2.2 TCP協議
TCP協議是面向連接的通訊協議,即在傳輸數據前先在發送端和接收端建立邏輯連接,然後再傳輸數據,它提供了兩台電腦之間可靠無差錯的數據傳輸。在TCP連接中必須要明確客戶端與伺服器端,由客戶端向服務端發出連接請求,每次連接的創建都需要經過“三次握手”。第一次握手,客戶端向伺服器端發出連接請求,等待伺服器確認,第二次握手,伺服器端向客戶端回送一個響應,通知客戶端收到了連接請求,第三次握手,客戶端再次向伺服器端發送確認資訊,確認連接。整個交互過程如下圖所示。
由於TCP協議的面向連接特性,它可以保證傳輸數據的安全性,所以是一個被廣泛採用的協議,例如在下載文件時,如果數據接收不完整,將會導致文件數據丟失而不能被打開,因此,下載文件時必須採用TCP協議。
3 UDP通訊
3.1 DatagramPacket
前面介紹了UDP是一種面向無連接的協議,因此,在通訊時發送端和接收端不用建立連接。UDP通訊的過程就像是貨運公司在兩個碼頭間發送貨物一樣。在碼頭髮送和接收貨物時都需要使用集裝箱來裝載貨物,UDP通訊也是一樣,發送和接收的數據也需要使用“集裝箱”進行打包,為此JDK中提供了一個DatagramPacket類,該類的實例對象就相當於一個集裝箱,用於封裝UDP通訊中發送或者接收的數據。
想要創建一個DatagramPacket對象,首先需要了解一下它的構造方法。在創建發送端和接收端的DatagramPacket對象時,使用的構造方法有所不同,接收端的構造方法只需要接收一個位元組數組來存放接收到的數據,而發送端的構造方法不但要接收存放了發送數據的位元組數組,還需要指定發送端IP地址和埠號。
接下來根據API文檔的內容,對DatagramPacket的構造方法進行逐一詳細地講解。
- DatagramPacket(byte[ ] buf, int length) 構造DatagramPacket,用來接收長度為length的數據包
使用該構造方法在創建DatagramPacket對象時,指定了封裝數據的位元組數組和數據的大小,沒有指定IP地址和埠號。很明顯,這樣的對象只能用於接收端,不能用於發送端。因為發送端一定要明確指出數據的目的地(ip地址和埠號),而接收端不需要明確知道數據的來源,只需要接收到數據即可。
- DatagramPacket(byte[ ] buf, int length, InetAddress address, int port) 構造DatagramPacket,用來接收長度為length的包發送到指定的主機上的指定埠號.
使用該構造方法在創建DatagramPacket對象時,不僅指定了封裝數據的位元組數組和數據的大小,還指定了數據包的目標IP地址(addr)和埠號(port)。該對象通常用於發送端,因為在發送數據時必須指定接收端的IP地址和埠號,就好像發送貨物的集裝箱上面必須標明接收人的地址一樣
說完DatagramPacket的構造方法,接下來對DatagramPacket類中的常用方法進行詳細地講解,如下表所示。
3.2 DatagramSocket
DatagramPacket數據包的作用就如同是“集裝箱”,可以將發送端或者接收端的數據封裝起來。然而運輸貨物只有“集裝箱”是不夠的,還需要有碼頭。在程式中需要實現通訊只有DatagramPacket數據包也同樣不行,為此JDK中提供的一個DatagramSocket類。DatagramSocket類的作用就類似於碼頭,使用這個類的實例對象就可以發送和接收DatagramPacket數據包,發送數據的過程如下圖所示。
在創建發送端和接收端的DatagramSocket對象時,使用的構造方法也有所不同,下面對DatagramSocket類中常用的構造方法進行講解。
- DatagramSocket() 構造數據報套接字並將其綁定到本機上任何可用的埠
該構造方法用於創建發送端的DatagramSocket對象,在創建DatagramSocket對象時,並沒有指定埠號,此時,系統會分配一個沒有被其它網路程式所使用的埠號。
- DatagramSocket() 構造數據報套接字並將其綁定到本機上指定的埠
構造方法既可用於創建接收端的DatagramSocket對象,又可以創建發送端的DatagramSocket對象,在創建接收端的DatagramSocket對象時,必須要指定一個埠號,這樣就可以監聽指定的埠。
說完DatagramSocket的構造方法,接下來對DatagramSocket類中的常用方法進行詳細地講解。
3.3 UDP網路程式
講解了DatagramPacket和DatagramSocket的作用,接下來通過一個案例來學習一下它們在程式中的具體用法。
下圖為UDP發送端與接收端交互圖解
要實現UDP通訊需要創建一個發送端程式和一個接收端程式,很明顯,在通訊時只有接收端程式先運行,才能避免因發送端發送的數據無法接收,而造成數據丟失。因此,首先需要來完成接收端程式的編寫。
- UDP完成數據的發送
/* * 發送端 * 1,創建DatagramSocket對象 * 2,創建DatagramPacket對象,並封裝數據 * 3,發送數據 * 4,釋放流資源 */ public class UDPSend { public static void main(String[] args) throws IOException { //1,創建DatagramSocket對象 DatagramSocket sendSocket = new DatagramSocket(); //2,創建DatagramPacket對象,並封裝數據 //public DatagramPacket(byte[] buf, int length, InetAddress address, int port) //構造數據報包,用來將長度為 length 的包發送到指定主機上的指定埠號。 byte[] buffer = "hello,UDP".getBytes(); DatagramPacket dp = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("192.168.75.58"), 12306); //3,發送數據 //public void send(DatagramPacket p) 從此套接字發送數據報包 sendSocket.send(dp); //4,釋放流資源 sendSocket.close(); } }
-
UDP完成數據的接收
/* * UDP接收端 * * 1,創建DatagramSocket對象 * 2,創建DatagramPacket對象 * 3,接收數據存儲到DatagramPacket對象中 * 4,獲取DatagramPacket對象的內容 * 5,釋放流資源 */ public class UDPReceive { public static void main(String[] args) throws IOException { //1,創建DatagramSocket對象,並指定埠號 DatagramSocket receiveSocket = new DatagramSocket(12306); //2,創建DatagramPacket對象, 創建一個空的倉庫 byte[] buffer = new byte[1024]; DatagramPacket dp = new DatagramPacket(buffer, 1024); //3,接收數據存儲到DatagramPacket對象中 receiveSocket.receive(dp); //4,獲取DatagramPacket對象的內容 //誰發來的數據 getAddress() InetAddress ipAddress = dp.getAddress(); String ip = ipAddress.getHostAddress();//獲取到了IP地址 //發來了什麼數據 getData() byte[] data = dp.getData(); //發來了多少數據 getLenth() int length = dp.getLength(); //顯示收到的數據 String dataStr = new String(data,0,length); System.out.println("IP地址:"+ip+ "數據是"+ dataStr); //5,釋放流資源 receiveSocket.close(); } }
4 TCP通訊
TCP通訊同UDP通訊一樣,都能實現兩台電腦之間的通訊,通訊的兩端都需要創建socket對象。
區別在於,UDP中只有發送端和接收端,不區分客戶端與伺服器端,電腦之間可以任意地發送數據。
而TCP通訊是嚴格區分客戶端與伺服器端的,在通訊時,必須先由客戶端去連接伺服器端才能實現通訊,伺服器端不可以主動連接客戶端,並且伺服器端程式需要事先啟動,等待客戶端的連接。
在JDK中提供了兩個類用於實現TCP程式,一個是ServerSocket類,用於表示伺服器端,一個是Socket類,用於表示客戶端。
通訊時,首先創建代表伺服器端的ServerSocket對象,該對象相當於開啟一個服務,並等待客戶端的連接,然後創建代表客戶端的Socket對象向伺服器端發出連接請求,伺服器端響應請求,兩者建立連接開始通訊。
4.1 ServerSocket
通過前面的學習知道,在開發TCP程式時,首先需要創建伺服器端程式。JDK的java.net包中提供了一個ServerSocket類,該類的實例對象可以實現一個伺服器段的程式。通過查閱API文檔可知,ServerSocket類提供了多種構造方法,接下來就對ServerSocket的構造方法進行逐一地講解。
- ServerSocket(int port) 創建綁定到特定埠的伺服器套接字
使用該構造方法在創建ServerSocket對象時,就可以將其綁定到一個指定的埠號上(參數port就是埠號)。
接下來學習一下ServerSocket的常用方法,如下所示。
- Socket accept() 偵聽並接受到此套接字的連接
- InetAddress getInetAddress() 返回此伺服器套接字的本地地址
ServerSocket對象負責監聽某台電腦的某個埠號,在創建ServerSocket對象後,需要繼續調用該對象的accept()方法,接收來自客戶端的請求。當執行了accept()方法之後,伺服器端程式會發生阻塞,直到客戶端發出連接請求,accept()方法才會返回一個Scoket對象用於和客戶端實現通訊,程式才能繼續向下執行。
4.2 Socket
講解了ServerSocket對象可以實現服務端程式,但只實現伺服器端程式還不能完成通訊,此時還需要一個客戶端程式與之交互,為此JDK提供了一個Socket類,用於實現TCP客戶端程式。
通過查閱API文檔可知Socket類同樣提供了多種構造方法,接下來就對Socket的常用構造方法進行詳細講解。
- Socket(String host, int port) 創建一個流套接字並將其連接到指定主機上的指定埠
使用該構造方法在創建Socket對象時,會根據參數去連接在指定地址和埠上運行的伺服器程式,其中參數host接收的是一個字元串類型的IP地址。
- Socket(InetAddress address, int port) 創建一個流套接字並將其連接到指定IP地址的指定埠
該方法在使用上與第二個構造方法類似,參數address用於接收一個InetAddress類型的對象,該對象用於封裝一個IP地址。
在以上Socket的構造方法中,最常用的是第一個構造方法。
接下來學習一下Socket的常用方法,如表所示。
方法聲明 |
功能描述 |
int getPort() |
該方法返回一個int類型對象,該對象是Socket對象與伺服器端連接的埠號 |
InetAddress getLocalAddress() |
該方法用於獲取Socket對象綁定的本地IP地址,並將IP地址封裝成InetAddress類型的對象返回 |
void close() |
該方法用於關閉Socket連接,結束本次通訊。在關閉socket之前,應將與socket相關的所有的輸入/輸出流全部關閉,這是因為一個良好的程式應該在執行完畢時釋放所有的資源 |
InputStream getInputStream() |
該方法返回一個InputStream類型的輸入流對象,如果該對象是由伺服器端的Socket返回,就用於讀取客戶端發送的數據,反之,用於讀取伺服器端發送的數據 |
OutputStream getOutputStream() |
該方法返回一個OutputStream類型的輸出流對象,如果該對象是由伺服器端的Socket返回,就用於向客戶端發送數據,反之,用於向伺服器端發送數據 |
在Socket類的常用方法中,getInputStream()和getOutStream()方法分別用於獲取輸入流和輸出流。當客戶端和服務端建立連接後,數據是以IO流的形式進行交互的,從而實現通訊。
接下來通過一張圖來描述伺服器端和客戶端的數據傳輸,如下圖所示。
4.3 簡單的TCP網路程式
了解了ServerSocket、Socket類的基本用法,為了讓大家更好地掌握這兩個類的使用,接下來通過一個TCP通訊的案例來進一步學習。
要實現TCP通訊需要創建一個伺服器端程式和一個客戶端程式,為了保證數據傳輸的安全性,首先需要實現伺服器端程式。
/* * TCP 伺服器端 * * 1,創建伺服器ServerSocket對象(指定伺服器埠號) * 2,開啟伺服器了,等待客戶端的連接,當客戶端連接後,可以獲取到連接伺服器的客戶端Socket對象 * 3,給客戶端回饋資訊 * 4,關閉流資源 */ public class TCPServer { public static void main(String[] args) throws IOException { //1,創建伺服器ServerSocket對象(指定伺服器埠號) ServerSocket ss = new ServerSocket(8888); //2,開啟伺服器了,等待客戶端的連接,當客戶端連接後,可以獲取到連接伺服器的客戶端Socket對象 Socket s = ss.accept(); //3,給客戶端回饋資訊 /* * a,獲取客戶端的輸出流 * b,在服務端端,通過客戶端的輸出流寫數據給客戶端 */ //a,獲取客戶端的輸出流 OutputStream out = s.getOutputStream(); //b,在服務端端,通過客戶端的輸出流寫數據給客戶端 out.write("你已經連接上了伺服器".getBytes()); //4,關閉流資源 out.close(); s.close(); //ss.close(); 伺服器流 通常都是不關閉的 } }
完成了伺服器端程式的編寫,接下來編寫客戶端程式。
/* * TCP 客戶端 * * 1,創建客戶端Socket對象,(指定要連接的伺服器地址與埠號) * 2,獲取伺服器端的回饋回來的資訊 * 3,關閉流資源 */ public class TCPClient { public static void main(String[] args) throws IOException { //1,創建客戶端Socket對象,(指定要連接的伺服器地址與埠號) Socket s = new Socket("192.168.74.58", 8888); //2,獲取伺服器端的回饋回來的資訊 InputStream in = s.getInputStream(); //獲取獲取流中的數據 byte[] buffer = new byte[1024]; //把流中的數據存儲到數組中,並記錄讀取位元組的個數 int length = in.read(buffer); //顯示數據 System.out.println( new String(buffer, 0 , length) ); //3,關閉流資源 in.close(); s.close(); } }
4.4 文件上傳案例
目前大多數伺服器都會提供文件上傳的功能,由於文件上傳需要數據的安全性和完整性,很明顯需要使用TCP協議來實現。接下來通過一個案例來實現圖片上傳的功能。如下圖所示。原圖:文件上傳.bmp
- 首先編寫伺服器端程式,用來接收圖片。
/* * 文件上傳 伺服器端 * */ public class TCPServer { public static void main(String[] args) throws IOException { //1,創建伺服器,等待客戶端連接 ServerSocket serverSocket = new ServerSocket(8888); Socket clientSocket = serverSocket.accept(); //顯示哪個客戶端Socket連接上了伺服器 InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址對象 String ip = ipObject.getHostAddress(); //得到IP地址字元串 System.out.println("小樣,抓到你了,連接我!!" + "IP:" + ip); //7,獲取Socket的輸入流 InputStream in = clientSocket.getInputStream(); //8,創建目的地的位元組輸出流 D:\upload\192.168.74.58(1).jpg BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\upload\192.168.74.58(1).jpg")); //9,把Socket輸入流中的數據,寫入目的地的位元組輸出流中 byte[] buffer = new byte[1024]; int len = -1; while((len = in.read(buffer)) != -1){ //寫入目的地的位元組輸出流中 fileOut.write(buffer, 0, len); } //-----------------回饋資訊--------------------- //10,獲取Socket的輸出流, 作用:寫回饋資訊給客戶端 OutputStream out = clientSocket.getOutputStream(); //11,寫回饋資訊給客戶端 out.write("圖片上傳成功".getBytes()); out.close(); fileOut.close(); in.close(); clientSocket.close(); //serverSocket.close(); } }
- 編寫客戶端,完成上傳圖片
/* * 文件上傳 客戶端 * * public void shutdownOutput() 禁用此Socket的輸出流,間接的相當於告知了伺服器數據寫入完畢 */ public class TCPClient { public static void main(String[] args) throws IOException { //2,創建客戶端Socket,連接伺服器 Socket socket = new Socket("192.168.74.58", 8888); //3,獲取Socket流中的輸出流,功能:用來把數據寫到伺服器 OutputStream out = socket.getOutputStream(); //4,創建位元組輸入流,功能:用來讀取數據源(圖片)的位元組 BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\NoDir\test.jpg")); //5,把圖片數據寫到Socket的輸出流中(把數據傳給伺服器) byte[] buffer = new byte[1024]; int len = -1; while ((len = fileIn.read(buffer)) != -1){ //把數據寫到Socket的輸出流中 out.write(buffer, 0, len); } //6,客戶端發送數據完畢,結束Socket輸出流的寫入操作,告知伺服器端 socket.shutdownOutput(); //-----------------回饋資訊--------------------- //12,獲取Socket的輸入流 作用: 讀回饋資訊 InputStream in = socket.getInputStream(); //13,讀回饋資訊 byte[] info = new byte[1024]; //把回饋資訊存儲到info數組中,並記錄位元組個數 int length = in.read(info); //顯示回饋結果 System.out.println( new String(info, 0, length) ); //關閉流 in.close(); fileIn.close(); out.close(); socket.close(); } }
4.5 文件上傳案例多執行緒版本
實現伺服器端可以同時接收多個客戶端上傳的文件。
- 我們要修改伺服器端程式碼
/* * 文件上傳多執行緒版本, 伺服器端 */ public class TCPServer { public static void main(String[] args) throws IOException { //1,創建伺服器,等待客戶端連接 ServerSocket serverSocket = new ServerSocket(6666); //實現多個客戶端連接伺服器的操作 while(true){ final Socket clientSocket = serverSocket.accept(); //啟動執行緒,完成與當前客戶端的數據交互過程 new Thread(){ public void run() { try{ //顯示哪個客戶端Socket連接上了伺服器 InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址對象 String ip = ipObject.getHostAddress(); //得到IP地址字元串 System.out.println("小樣,抓到你了,連接我!!" + "IP:" + ip); //7,獲取Socket的輸入流 InputStream in = clientSocket.getInputStream(); //8,創建目的地的位元組輸出流 D:\upload\192.168.74.58(1).jpg BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\upload\"+ip+"("+System.currentTimeMillis()+").jpg")); //9,把Socket輸入流中的數據,寫入目的地的位元組輸出流中 byte[] buffer = new byte[1024]; int len = -1; while((len = in.read(buffer)) != -1){ //寫入目的地的位元組輸出流中 fileOut.write(buffer, 0, len); } //-----------------回饋資訊--------------------- //10,獲取Socket的輸出流, 作用:寫回饋資訊給客戶端 OutputStream out = clientSocket.getOutputStream(); //11,寫回饋資訊給客戶端 out.write("圖片上傳成功".getBytes()); out.close(); fileOut.close(); in.close(); clientSocket.close(); } catch(IOException e){ e.printStackTrace(); } }; }.start(); } //serverSocket.close(); } }
回憶一下剛剛的知識點
- IP地址:用來唯一表示我們自己的電腦的,是一個網路標示
- 埠號: 用來區別當前電腦中的應用程式的
- UDP: 傳送速度快,但是容易丟數據,如影片聊天,語音聊天
- TCP: 傳送穩定,不會丟失數據,如文件的上傳、下載
- UDP程式交互的流程
發送端
1,創建DatagramSocket對象 2,創建DatagramPacket對象,並封裝數據 3,發送數據 4,釋放流資源
接收端
1,創建DatagramSocket對象 2,創建DatagramPacket對象 3,接收數據存儲到DatagramPacket對象中 4,獲取DatagramPacket對象的內容 5,釋放流資源
- TCP程式交互的流程
客戶端
1,創建客戶端的Socket對象 2,獲取Socket的輸出流對象 3,寫數據給伺服器 4,獲取Socket的輸入流對象 5,使用輸入流,讀回饋資訊 6,關閉流資源
伺服器端
1,創建伺服器端ServerSocket對象,指定伺服器端埠號 2,開啟伺服器,等待著客戶端Socket對象的連接,如有客戶端連接,返回客戶端的Socket對象 3,通過客戶端的Socket對象,獲取客戶端的輸入流,為了實現獲取客戶端發來的數據 4,通過客戶端的輸入流,獲取流中的數據 5,通過客戶端的Socket對象,獲取客戶端的輸出流,為了實現給客戶端回饋資訊 6,通過客戶端的輸出流,寫數據到流中 7,關閉流資源