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,關閉流資源