Java-基礎語法19:網路程式設計

卓老闆發表於2020-10-31

1.網路程式設計入門

1.1 網路程式設計概述【理解】

  • 計算機網路

    是指將地理位置不同的具有獨立功能的多臺計算機及其外部裝置,通過通訊線路連線起來,在網路作業系統,網路管理軟體及網路通訊協議的管理和協調下,實現資源共享和資訊傳遞的計算機系統

  • 網路程式設計

    在網路通訊協議下,實現網路互連的不同計算機上執行的程式間可以進行資料交換

1.2 網路程式設計三要素【理解】

  • IP地址

    要想讓網路中的計算機能夠互相通訊,必須為每臺計算機指定一個標識號,通過這個標識號來指定要接收資料的計算機和識別傳送的計算機,而IP地址就是這個標識號。也就是裝置的標識

  • 網路的通訊,本質上是兩個應用程式的通訊。每臺計算機都有很多的應用程式,那麼在網路通訊時,如何區分這些應用程式呢?如果說IP地址可以唯一標識網路中的裝置,那麼埠號就可以唯一標識裝置中的應用程式了。也就是應用程式的標識

  • 協議

    通過計算機網路可以使多臺計算機實現連線,位於同一個網路中的計算機在進行連線和通訊時需要遵守一定的規則,這就好比在道路中行駛的汽車一定要遵守交通規則一樣。在計算機網路中,這些連線和通訊的規則被稱為網路通訊協議,它對資料的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通訊雙方必須同時遵守才能完成資料交換。常見的協議有UDP協議和TCP協議

1.3 IP地址【理解】

IP地址:是網路中裝置的唯一標識

  • IP地址分為兩大類

    • IPv4:是給每個連線在網路上的主機分配一個32bit地址。按照TCP/IP規定,IP地址用二進位制來表示,每個IP地址長32bit,也就是4個位元組。例如一個採用二進位制形式的IP地址是“11000000 10101000 00000001 01000010”,這麼長的地址,處理起來也太費勁了。為了方便使用,IP地址經常被寫成十進位制的形式,中間使用符號“.”分隔不同的位元組。於是,上面的IP地址可以表示為“192.168.1.66”。IP地址的這種表示法叫做“點分十進位制表示法”,這顯然比1和0容易記憶得多

    • IPv6:由於網際網路的蓬勃發展,IP地址的需求量愈來愈大,但是網路地址資源有限,使得IP的分配越發緊張。為了擴大地址空間,通過IPv6重新定義地址空間,採用128位地址長度,每16個位元組一組,分成8組十六進位制數,這樣就解決了網路地址資源數量不夠的問題

  • DOS常用命令:

    • ipconfig:檢視本機IP地址

    • ping IP地址:檢查網路是否連通

  • 特殊IP地址:

    • 127.0.0.1:是回送地址,可以代表本機地址,一般用來測試使用

1.4InetAddress【應用】

InetAddress:此類表示Internet協議(IP)地址

  • 相關方法

    方法名說明
    static InetAddress getByName(String host)確定主機名稱的IP地址。主機名稱可以是機器名稱,也可以是IP地址
    String getHostName()獲取此IP地址的主機名
    String getHostAddress()返回文字顯示中的IP地址字串
  • 程式碼演示

    public class InetAddressDemo {
        public static void main(String[] args) throws UnknownHostException {
    		//InetAddress address = InetAddress.getByName("itheima");
            InetAddress address = InetAddress.getByName("192.168.1.66");
    
            //public String getHostName():獲取此IP地址的主機名
            String name = address.getHostName();
            //public String getHostAddress():返回文字顯示中的IP地址字串
            String ip = address.getHostAddress();
    
            System.out.println("主機名:" + name);
            System.out.println("IP地址:" + ip);
        }
    }
    

1.5埠和協議【理解】

    • 裝置上應用程式的唯一標識
  • 埠號

    • 用兩個位元組表示的整數,它的取值範圍是065535。其中,01023之間的埠號用於一些知名的網路服務和應用,普通的應用程式需要使用1024以上的埠號。如果埠號被另外一個服務或應用所佔用,會導致當前程式啟動失敗
  • 協議

    • 計算機網路中,連線和通訊的規則被稱為網路通訊協議
  • UDP協議

    • 使用者資料包協議(User Datagram Protocol)
    • UDP是無連線通訊協議,即在資料傳輸時,資料的傳送端和接收端不建立邏輯連線。簡單來說,當一臺計算機向另外一臺計算機傳送資料時,傳送端不會確認接收端是否存在,就會發出資料,同樣接收端在收到資料時,也不會向傳送端反饋是否收到資料。
    • 由於使用UDP協議消耗資源小,通訊效率高,所以通常都會用於音訊、視訊和普通資料的傳輸
    • 例如視訊會議通常採用UDP協議,因為這種情況即使偶爾丟失一兩個資料包,也不會對接收結果產生太大影響。但是在使用UDP協議傳送資料時,由於UDP的面向無連線性,不能保證資料的完整性,因此在傳輸重要資料時不建議使用UDP協議
  • TCP協議

    • 傳輸控制協議 (Transmission Control Protocol)

    • TCP協議是面向連線的通訊協議,即傳輸資料之前,在傳送端和接收端建立邏輯連線,然後再傳輸資料,它提供了兩臺計算機之間可靠無差錯的資料傳輸。在TCP連線中必須要明確客戶端與伺服器端,由客戶端向服務端發出連線請求,每次連線的建立都需要經過“三次握手”

    • 三次握手:TCP協議中,在傳送資料的準備階段,客戶端與伺服器之間的三次互動,以保證連線的可靠

      第一次握手,客戶端向伺服器端發出連線請求,等待伺服器確認

      第二次握手,伺服器端向客戶端回送一個響應,通知客戶端收到了連線請求

      第三次握手,客戶端再次向伺服器端傳送確認資訊,確認連線

    • 完成三次握手,連線建立後,客戶端和伺服器就可以開始進行資料傳輸了。由於這種面向連線的特性,TCP協議可以保證傳輸資料的安全,所以應用十分廣泛。例如上傳檔案、下載檔案、瀏覽網頁等

2.UDP通訊程式

2.1 UDP傳送資料【應用】

  • Java中的UDP通訊

    • UDP協議是一種不可靠的網路協議,它在通訊的兩端各建立一個Socket物件,但是這兩個Socket只是傳送,接收資料的物件,因此對於基於UDP協議的通訊雙方而言,沒有所謂的客戶端和伺服器的概念
    • Java提供了DatagramSocket類作為基於UDP協議的Socket
  • 構造方法

    方法名說明
    DatagramSocket()建立資料包套接字並將其繫結到本機地址上的任何可用埠
    DatagramPacket(byte[] buf,int len,InetAddress add,int port)建立資料包,傳送長度為len的資料包到指定主機的指定埠
  • 相關方法

    方法名說明
    void send(DatagramPacket p)傳送資料包包
    void close()關閉資料包套接字
    void receive(DatagramPacket p)從此套接字接受資料包包
  • 傳送資料的步驟

    • 建立傳送端的Socket物件(DatagramSocket)
    • 建立資料,並把資料打包
    • 呼叫DatagramSocket物件的方法傳送資料
    • 關閉傳送端
  • 程式碼演示

    public class SendDemo {
        public static void main(String[] args) throws IOException {
            //建立傳送端的Socket物件(DatagramSocket)
            // DatagramSocket() 構造資料包套接字並將其繫結到本地主機上的任何可用埠
            DatagramSocket ds = new DatagramSocket();
    
            //建立資料,並把資料打包
            //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
            //構造一個資料包,傳送長度為 length的資料包到指定主機上的指定埠號。
            byte[] bys = "hello,udp,我來了".getBytes();
    
            DatagramPacket dp = new DatagramPacket(bys,bys.length,InetAddress.getByName("192.168.1.66"),10086);
    
            //呼叫DatagramSocket物件的方法傳送資料
            //void send(DatagramPacket p) 從此套接字傳送資料包包
            ds.send(dp);
    
            //關閉傳送端
            //void close() 關閉此資料包套接字
            ds.close();
        }
    }
    

2.2UDP接收資料【應用】

  • 接收資料的步驟

    • 建立接收端的Socket物件(DatagramSocket)
    • 建立一個資料包,用於接收資料
    • 呼叫DatagramSocket物件的方法接收資料
    • 解析資料包,並把資料在控制檯顯示
    • 關閉接收端
  • 構造方法

    方法名說明
    DatagramPacket(byte[] buf, int len)建立一個DatagramPacket用於接收長度為len的資料包
  • 相關方法

    方法名說明
    byte[] getData()返回資料緩衝區
    int getLength()返回要傳送的資料的長度或接收的資料的長度
  • 示例程式碼

    public class ReceiveDemo {
        public static void main(String[] args) throws IOException {
            //建立接收端的Socket物件(DatagramSocket)
            DatagramSocket ds = new DatagramSocket(12345);
    
            while (true) {
                //建立一個資料包,用於接收資料
                byte[] bys = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bys, bys.length);
    
                //呼叫DatagramSocket物件的方法接收資料
                ds.receive(dp);
    
                //解析資料包,並把資料在控制檯顯示
                System.out.println("資料是:" + new String(dp.getData(), 0,                                             dp.getLength()));
            }
        }
    }
    

2.3UDP通訊程式練習【應用】

  • 案例需求

    UDP傳送資料:資料來自於鍵盤錄入,直到輸入的資料是886,傳送資料結束

    UDP接收資料:因為接收端不知道傳送端什麼時候停止傳送,故採用死迴圈接收

  • 程式碼實現

    /*
        UDP傳送資料:
            資料來自於鍵盤錄入,直到輸入的資料是886,傳送資料結束
     */
    public class SendDemo {
        public static void main(String[] args) throws IOException {
            //建立傳送端的Socket物件(DatagramSocket)
            DatagramSocket ds = new DatagramSocket();
            //自己封裝鍵盤錄入資料
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line;
            while ((line = br.readLine()) != null) {
                //輸入的資料是886,傳送資料結束
                if ("886".equals(line)) {
                    break;
                }
                //建立資料,並把資料打包
                byte[] bys = line.getBytes();
                DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.1.66"), 12345);
    
                //呼叫DatagramSocket物件的方法傳送資料
                ds.send(dp);
            }
            //關閉傳送端
            ds.close();
        }
    }
    
    /*
        UDP接收資料:
            因為接收端不知道傳送端什麼時候停止傳送,故採用死迴圈接收
     */
    public class ReceiveDemo {
        public static void main(String[] args) throws IOException {
            //建立接收端的Socket物件(DatagramSocket)
            DatagramSocket ds = new DatagramSocket(12345);
            while (true) {
                //建立一個資料包,用於接收資料
                byte[] bys = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bys, bys.length);
                //呼叫DatagramSocket物件的方法接收資料
                ds.receive(dp);
                //解析資料包,並把資料在控制檯顯示
                System.out.println("資料是:" + new String(dp.getData(), 0, dp.getLength()));
            }
            //關閉接收端
    //        ds.close();
        }
    }
    

3.TCP通訊程式

3.1TCP傳送資料【應用】

  • Java中的TCP通訊

    • Java對基於TCP協議的的網路提供了良好的封裝,使用Socket物件來代表兩端的通訊埠,並通過Socket產生IO流來進行網路通訊。
    • Java為客戶端提供了Socket類,為伺服器端提供了ServerSocket類
  • 構造方法

    方法名說明
    Socket(InetAddress address,int port)建立流套接字並將其連線到指定IP指定埠號
    Socket(String host, int port)建立流套接字並將其連線到指定主機上的指定埠號
  • 相關方法

    方法名說明
    InputStream getInputStream()返回此套接字的輸入流
    OutputStream getOutputStream()返回此套接字的輸出流
  • 示例程式碼

    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端的Socket物件(Socket)
            //Socket(String host, int port) 建立流套接字並將其連線到指定主機上的指定埠號
            Socket s = new Socket("192.168.1.66",10000);
    
            //獲取輸出流,寫資料
            //OutputStream getOutputStream() 返回此套接字的輸出流
            OutputStream os = s.getOutputStream();
            os.write("hello,tcp,我來了".getBytes());
    
            //釋放資源
            s.close();
        }
    }
    

3.2TCP接收資料【應用】

  • 構造方法

    方法名說明
    ServletSocket(int port)建立繫結到指定埠的伺服器套接字
  • 相關方法

    方法名說明
    Socket accept()監聽要連線到此的套接字並接受它
  • 示例程式碼

    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器端的Socket物件(ServerSocket)
            //ServerSocket(int port) 建立繫結到指定埠的伺服器套接字
            ServerSocket ss = new ServerSocket(10000);
    
            //Socket accept() 偵聽要連線到此套接字並接受它
            Socket s = ss.accept();
    
            //獲取輸入流,讀資料,並把資料顯示在控制檯
            InputStream is = s.getInputStream();
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            String data = new String(bys,0,len);
            System.out.println("資料是:" + data);
    
            //釋放資源
            s.close();
            ss.close();
        }
    }
    

3.3TCP通訊程式練習【應用】

  • 案例需求

    客戶端:傳送資料,接受伺服器反饋

    伺服器:收到訊息後給出反饋

  • 案例分析

    • 客戶端建立物件,使用輸出流輸出資料
    • 服務端建立物件,使用輸入流接受資料
    • 服務端使用輸出流給出反饋資料
    • 客戶端使用輸入流接受反饋資料
  • 程式碼實現

    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器端的Socket物件(ServerSocket)
            ServerSocket ss = new ServerSocket(10000);
    
            //監聽客戶端連線,返回一個Socket物件
            Socket s = ss.accept();
    
            //獲取輸入流,讀資料,並把資料顯示在控制檯
            InputStream is = s.getInputStream();
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            String data = new String(bys, 0, len);
            System.out.println("伺服器:" + data);
    
            //給出反饋
            OutputStream os = s.getOutputStream();
            os.write("資料已經收到".getBytes());
    
            //釋放資源
    //        s.close();
            ss.close();
        }
    }
    
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端的Socket物件(Socket)
            Socket s = new Socket("192.168.1.66", 10000);
    
            //獲取輸出流,寫資料
            OutputStream os = s.getOutputStream();
            os.write("hello,tcp,我來了".getBytes());
    
            //接收伺服器反饋
            InputStream is = s.getInputStream();
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            String data = new String(bys, 0, len);
            System.out.println("客戶端:" + data);
    
            //釋放資源
    //        is.close();
    //        os.close();
            s.close();
        }
    }
    

3.4TCP通訊程式練習【應用】

  • 案例需求

    客戶端:資料來自於鍵盤錄入, 直到輸入的資料是886,傳送資料結束

    服務端:接收到資料在控制檯輸出

  • 案例分析

    • 客戶端建立物件,使用鍵盤錄入迴圈接受資料,接受一行傳送一行,直到鍵盤錄入886為止
    • 服務端建立物件,使用輸入流按行迴圈接受資料,直到接受到null為止
  • 程式碼實現

    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端Socket物件
            Socket s = new Socket("192.168.1.66",10000);
    
            //資料來自於鍵盤錄入,直到輸入的資料是886,傳送資料結束
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            //封裝輸出流物件
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            String line;
            while ((line=br.readLine())!=null) {
                if("886".equals(line)) {
                    break;
                }
    
                //獲取輸出流物件
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            s.close();
        }
    }
    
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器Socket物件
            ServerSocket ss = new ServerSocket(10000);
    
            //監聽客戶端的連線,返回一個對應的Socket物件
            Socket s = ss.accept();
    
            //獲取輸入流
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
    
            //釋放資源
            ss.close();
        }
    }
    

3.5TCP通訊程式練習【應用】

  • 案例需求

    客戶端:資料來自於鍵盤錄入,直到輸入的資料是886,傳送資料結束

    服務端:接受到的資料寫入文字檔案中

  • 案例分析

    • 客戶端建立物件,使用鍵盤錄入迴圈接受資料,接受一行傳送一行,直到鍵盤錄入886為止
    • 服務端建立物件,建立輸出流物件指向檔案,每接受一行資料後使用輸出流輸出到檔案中,直到接受到null為止
  • 程式碼實現

    ublic class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端Socket物件
            Socket s = new Socket("192.168.1.66",10000);
            //資料來自於鍵盤錄入,直到輸入的資料是886,傳送資料結束
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            //封裝輸出流物件
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            String line;
            while ((line=br.readLine())!=null) {
                if("886".equals(line)) {
                    break;
                }
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            //釋放資源
            s.close();
        }
    }
    
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器Socket物件
            ServerSocket ss = new ServerSocket(10000);
            //監聽客戶端連線,返回一個對應的Socket物件
            Socket s = ss.accept();
            //接收資料
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //把資料寫入文字檔案
            BufferedWriter bw = new BufferedWriter(new FileWriter("myNet\\s.txt"));
    
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
            ss.close();
        }
    }
    

3.6TCP通訊程式練習【應用】

  • 案例需求

    客戶端:資料來自於文字檔案

    伺服器:接收到的資料寫入文字檔案

  • 案例分析

    • 建立客戶端,建立輸入流物件指向檔案,從檔案迴圈讀取資料,每讀取一行就使用輸出流給伺服器輸出一行
    • 建立服務端,建立輸出流物件指向檔案,從客戶端接受資料,每接受一行就給檔案中輸出一行
  • 程式碼實現

    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端Socket物件
            Socket s = new Socket("192.168.1.66",10000);
    
            //封裝文字檔案的資料
            BufferedReader br = new BufferedReader(new FileReader("myNet\\InetAddressDemo.java"));
            //封裝輸出流寫資料
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            br.close();
            s.close();
        }
    }
    
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器Socket物件
            ServerSocket ss = new ServerSocket(10000);
    
            //監聽客戶端連線,返回一個對應的Socket物件
            Socket s = ss.accept();
    
            //接收資料
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //把資料寫入文字檔案
            BufferedWriter bw = new BufferedWriter(new FileWriter("myNet\\Copy.java"));
    
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
            ss.close();
        }
    }
    
    

3.7TCP通訊程式練習【應用】

  • 案例需求

    客戶端:資料來自於文字檔案,接收伺服器反饋

    伺服器:接收到的資料寫入文字檔案,給出反饋

  • 案例分析

    • 建立客戶端物件,建立輸入流物件指向檔案,每讀入一行資料就給伺服器輸出一行資料,輸出結束後使用shutdownOutput()方法告知服務端傳輸結束
    • 建立伺服器物件,建立輸出流物件指向檔案,每接受一行資料就使用輸出流輸出到檔案中,傳輸結束後。使用輸出流給客戶端反饋資訊
    • 客戶端接受服務端的回饋資訊
  • 相關方法

    方法名說明
    void shutdownInput()將此套接字的輸入流放置在“流的末尾”
    void shutdownOutput()禁止用此套接字的輸出流
  • 程式碼實現

    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端Socket物件
            Socket s = new Socket("192.168.1.66",10000);
    
            //封裝文字檔案的資料
            BufferedReader br = new BufferedReader(new FileReader("myNet\\InetAddressDemo.java"));
            //封裝輸出流寫資料
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //public void shutdownOutput()
            s.shutdownOutput();
    
            //接收反饋
            BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String data = brClient.readLine(); //等待讀取資料
            System.out.println("伺服器的反饋:" + data);
    
            //釋放資源
            br.close();
            s.close();
        }
    }
    
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器Socket物件
            ServerSocket ss = new ServerSocket(10000);
    
            //監聽客戶端連線,返回一個對應的Socket物件
            Socket s = ss.accept();
    
            //接收資料
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //把資料寫入文字檔案
            BufferedWriter bw = new BufferedWriter(new FileWriter("myNet\\Copy.java"));
    
            String line;
            while ((line=br.readLine())!=null) { //等待讀取資料
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            //給出反饋
            BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            bwServer.write("檔案上傳成功");
            bwServer.newLine();
            bwServer.flush();
    
            //釋放資源
            bw.close();
            ss.close();
        }
    }
    
    

3.8TCP通訊程式練習【應用】

  • 案例需求

    客戶端:資料來自於文字檔案,接收伺服器反饋

    伺服器:接收到的資料寫入文字檔案,給出反饋,程式碼用執行緒進行封裝,為每一個客戶端開啟一個執行緒

  • 案例分析

    • 建立客戶端物件,建立輸入流物件指向檔案,每讀入一行資料就給伺服器輸出一行資料,輸出結束後使用shutdownOutput()方法告知服務端傳輸結束
    • 建立多執行緒類,在run()方法中讀取客戶端傳送的資料,為了防止檔案重名,使用計數器給檔名編號,接受結束後使用輸出流給客戶端傳送反饋資訊。
    • 建立服務端物件,每監聽到一個客戶端則開啟一個新的執行緒接受資料。
    • 客戶端接受服務端的回饋資訊
  • 程式碼實現

    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //建立客戶端Socket物件
            Socket s = new Socket("192.168.1.66",10000);
    
            //封裝文字檔案的資料
            BufferedReader br = new BufferedReader(new FileReader("myNet\\InetAddressDemo.java"));
            //封裝輸出流寫資料
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            s.shutdownOutput();
    
            //接收反饋
            BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String data = brClient.readLine(); //等待讀取資料
            System.out.println("伺服器的反饋:" + data);
    
            //釋放資源
            br.close();
            s.close();
        }
    }
    
    public class ServerThread implements Runnable {
        private Socket s;
    
        public ServerThread(Socket s) {
            this.s = s;
        }
    
        @Override
        public void run() {
            try {
                //接收資料寫到文字檔案
                BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                //解決名稱衝突問題
                int count = 0;
                File file = new File("myNet\\Copy["+count+"].java");
                while (file.exists()) {
                    count++;
                    file = new File("myNet\\Copy["+count+"].java");
                }
                BufferedWriter bw = new BufferedWriter(new FileWriter(file));
    
                String line;
                while ((line=br.readLine())!=null) {
                    bw.write(line);
                    bw.newLine();
                    bw.flush();
                }
    
                //給出反饋
                BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                bwServer.write("檔案上傳成功");
                bwServer.newLine();
                bwServer.flush();
    
                //釋放資源
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            //建立伺服器Socket物件
            ServerSocket ss = new ServerSocket(10000);
    
            while (true) {
                //監聽客戶端連線,返回一個對應的Socket物件
                Socket s = ss.accept();
                //為每一個客戶端開啟一個執行緒
                new Thread(new ServerThread(s)).start();
            }
    
        }
    }
    

相關文章