天天看點

Java學習筆記之網絡程式設計

Java 網絡程式設計 UDP TCP

0x00 概述

本文主要涉及Java知識點為Java網絡程式設計。

0x01 網絡程式設計入門

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.4 InetAddress

  • netAddress:此類表示Internet協定(IP)位址
  • 相關方法
Java學習筆記之網絡程式設計

 示例

package InetAddressDemo;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressDemo {
    public static void main(String[] args) throws UnknownHostException {
        // InetAddress address = InetAddress.getByName("Test");
        InetAddress address = InetAddress.getByName("127.0.0.1");

        // 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 端口和協定

  • 端口

    裝置上應用程式的唯一辨別

  • 端口号

    用兩個位元組表示的整數,它的取值範圍是0~65535。其中,0~1023之間的端口号用于一些知名的網絡服 務和應用,普通的應用程式需要使用1024以上的端口号。

    如果端口号被另外一個服務或應用所占用,會 導緻目前程式啟動失敗

  • 協定

    計算機網絡中,連接配接和通信的規則被稱為網絡通信協定

  • UDP協定

    使用者資料報協定(User Datagram Protocol)

    UDP是無連接配接通信協定,即在資料傳輸時,資料的發送端和接收端不建立邏輯連接配接。

    簡單來說,當一台 計算機向另外一台計算機發送資料時,發送端不會确認接收端是否存在,就會發出資料,同樣接收端在 收到資料時,也不會向發送端回報是否收到資料。

    由于使用UDP協定消耗資源小,通信效率高,是以通常都會用于音頻、視訊和普通資料的傳輸

    例如視訊會議通常采用UDP協定,因為這種情況即使偶爾丢失一兩個資料包,也不會對接收結果産生太大影響

    但是在使用UDP協定傳送資料時,由于UDP的面向無連接配接性,不能保證資料的完整性,是以在傳輸重要資料時不建議使用UDP協定

  • TCP協定

    傳輸控制協定 (Transmission Control Protocol)

    TCP協定是面向連接配接的通信協定,即傳輸資料之前,在發送端和接收端建立邏輯連接配接,然後再傳輸資料,它提供了兩台計算機之間可靠無差錯的資料傳輸。

    在TCP連接配接中必須要明确用戶端與伺服器端,由用戶端向服務端發出連接配接請求,每次連接配接的建立都需要經過“三次握手”

    三次握手:TCP協定中,在發送資料的準備階段,用戶端與伺服器之間的三次互動,以保證連接配接的可靠

      第一次握手,用戶端向伺服器端發出連接配接請求,等待伺服器确認

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

      第三次握手,用戶端再次向伺服器端發送确認資訊,确認連接配接

    完成三次握手,連接配接建立後,用戶端和伺服器就可以開始進行資料傳輸了。

    由于這種面向連接配接的特性, TCP協定可以保證傳輸資料的安全,是以應用十分廣泛。例如上傳檔案、下載下傳檔案、浏覽網頁等

0x02 UDP通信程式

2.1 UDP發送資料

  • Java中的UDP通信

    UDP協定是一種不可靠的網絡協定,它在通信的兩端各建立一個Socket對象,但是這兩個Socket隻是發送,接收資料的對象,

    是以對于基于UDP協定的通信雙方而言,沒有所謂的用戶端和伺服器的概念

    Java提供了DatagramSocket類作為基于UDP協定的Socket

  • 構造方法
Java學習筆記之網絡程式設計
  • 相關方法
Java學習筆記之網絡程式設計
  • 發送資料的步驟

    建發送端的Socket對象(DatagramSocket)

    建立資料,并把資料打包

    調用DatagramSocket對象的方法發送資料

    關閉發送端

示例

package SendDemo;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class SendDemo {
    public static void main(String[] args) throws IOException {
        // 建立發送端的Socket對象(DatagramSocket)
        // DatagramSocket ds = new DatagramSocket();
        DatagramSocket ds = new DatagramSocket();

        // 建立資料,并把資料打包
        // DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        // 構造一個資料包,發送長度為length的資料包到指定主機上的指定端口
        byte[] bys = "Hello, This is a test".getBytes();

        DatagramPacket dp =
                new DatagramPacket(bys, bys.length, InetAddress.getByName("127.0.0.1"), 100010);

        // 調用DataGramSocket對象的方法發送資料
        // void send(DatagramPacket p) 從此套接字發送資料包
        ds.send(dp);

        // 關閉發送端
        // void close() 關閉此資料報套接字
        ds.close();

    }
}      

2.2 UDP接受資料

  • 接收資料的步驟

    建立接收端的Socket對象(DatagramSocket)

    建立一個資料包,用于接收資料

    調用DatagramSocket對象的方法接收資料

    解析資料包,并把資料在控制台顯示

    關閉接收端 

  • 構造方法
Java學習筆記之網絡程式設計
  • 相關方法
Java學習筆記之網絡程式設計

示例

package ReceiveDemo;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;


public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        // 建立接收端的Socket對象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket(10010);

        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.3 UDP通信程式聯系

  • 需求:

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

    UDP接收資料:因為接收端不知道發送端什麼時候停止發送,故采用死循環接收

示例

package SendReceiveDemo;

/*
    UDP發送資料:
        資料來自于鍵盤錄入,直到輸入的資料是886,發送資料結束
    
 */


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 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("127.0.0.1"), 12345);

            // 調用DatagramSocket對象的方法發送資料
            ds.send(dp);
        }
        // 關閉發送端
        ds.close();
    }
}      
package SendReceiveDemo;

/*
    UDP接收資料
        因為接收端不知道發送端什麼時候停止發送資料,是以采用死循環方式接收
 */

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

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();
    }
}      

0x03 TCP通信程式

3.1 TCP發送資料

  • Java中的TCP通信

    Java對基于TCP協定的的網絡提供了良好的封裝,使用Socket對象來代表兩端的通信端口,并通過Socket産生IO流來進行網絡通信

    Java為用戶端提供了Socket類,為伺服器端提供了ServerSocket類

  • 構造方法
Java學習筆記之網絡程式設計
  • 相關方法
Java學習筆記之網絡程式設計

 示例

package clientDemo;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class clientDemo {
    public static void main(String[] args) throws IOException {
        // 建立用戶端的Socket對象(Socket)
        // Socket(String host, int port) 建立流套接字并将其連接配接到指定主機上的端口
        Socket s = new Socket("127.0.0.1", 12345);

        // 擷取輸出流,寫資料
        // OutputStream getOutPutStream() 傳回此套接字的輸出流
        OutputStream os = s.getOutputStream();
        os.write("Hello, this a test".getBytes());

        // 釋放資源
        s.close();
    }
}      

3.2 TCP接受資料

  • 構造方法
Java學習筆記之網絡程式設計
  • 相關方法
Java學習筆記之網絡程式設計

 示例

package ServerDemo;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器端的Socket對象(ServerSocket)
        // ServerSocket(int port) 建立綁定到指定端口的伺服器套接字
        ServerSocket ss = new ServerSocket(12345);

        // Socket accept() 偵聽要連接配接到此套接字并接受它
        Socket s = ss.accept();

        // 擷取輸入流,寫資料,并把資料顯示在控制台
        // OutputStream getOutputStream() 傳回此套接字的輸出流
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String data = new String(bys, 0, len);

        // 釋放資源
        s.close();
        ss.close();
    }
}      

3.3 TCP通信練習1

  • 需求:

    用戶端:發送資料,接受伺服器回報

    伺服器:收到消息後給出回報

  • 案例分析

    用戶端建立對象,使用輸出流輸出資料

    服務端建立對象,使用輸入流接受資料

    服務端使用輸出流給出回報資料

    用戶端使用輸入流接受回報資料

示例

package ServerClientTCPDemo1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器端的Socket對象(ServerSocket)
        ServerSocket ss = new ServerSocket(12345);

        // 監聽用戶端連接配接,傳回一個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();
    }
}      
package ServerClientTCPDemo1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 建立用戶端的Socket對象
        Socket s = new Socket("127.0.0.1", 12345);

        // 擷取輸出流,寫資料
        OutputStream os = s.getOutputStream();
        os.write("Hello, this is a test message".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.4 TCP通信練習2

  • 需求:

    用戶端:資料來自于鍵盤錄入, 直到輸入的資料是886,發送資料結束

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

  • 案例分析

    用戶端建立對象,使用鍵盤錄入循環接受資料,接受一行發送一行,直到鍵盤錄入886為止

    服務端建立對象,使用輸入流按行循環接受資料,直到接受到null為止

示例

package ServerClientTCPDemo2;

import java.io.*;
import java.net.Socket;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 建立socket對象
        Socket s = new Socket("127.0.0.1", 12345);

        // 資料來自鍵盤錄入,直到輸入的資料是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();

    }
}      
package ServerClientTCPDemo2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器Socket對象
        ServerSocket ss = new ServerSocket();

        // 監聽用戶端的連接配接,傳回一個對應的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.5 TCP通信練習3

  • 需求:

    用戶端:資料來自于鍵盤錄入,直到輸入的資料是886,發送資料結束

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

  • 案例分析:

    用戶端建立對象,使用鍵盤錄入循環接受資料,接受一行發送一行,直到鍵盤錄入886為止

    服務端建立對象,建立輸出流對象指向檔案,每接受一行資料後使用輸出流輸出到檔案中,直到接收到null為止

示例

package ServerClientTCPDemo3;

import java.io.*;
import java.net.Socket;

public class clientDemo {
    public static void main(String[] args) throws IOException {
        // 建立用戶端Socket對象
        Socket s = new Socket("127.0.0.1", 12345);

        // 資料來自鍵盤錄入,直到輸入的資料是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();
    }
}      
package ServerClientTCPDemo3;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class serverDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器Socket對象
        ServerSocket ss = new ServerSocket(12345);

        // 監聽用戶端連結,傳回一個對應的Socket對象
        Socket s = ss.accept();

        // 接收資料
        BufferedReader br = new BufferedReader(
                new InputStreamReader(s.getInputStream()));

        // 把資料寫入文本檔案
        BufferedWriter bw = new BufferedWriter(new FileWriter("my/s.txt"));
        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 釋放資源
        bw.close();
        ss.close();


    }
}      

3.6 TCP通信練習4

  • 需求:

    用戶端:資料來自于文本檔案

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

  • 案例分析:

    建立用戶端,建立輸入流對象指向檔案,從檔案循環讀取資料,每讀取一行就使用輸出流給伺服器輸出一行

    建立服務端,建立輸出流對象指向檔案,從用戶端接受資料,每接受一行就給檔案中輸出一行

示例

package ServerClientTCPDemo4;

import java.io.*;
import java.net.Socket;

public class clientDemo {
    public static void main(String[] args) throws IOException {
        // 建立用戶端Socket對象
        Socket s = new Socket("127.0.0.1", 12345);

        // 封裝文本檔案的資料
        BufferedReader br = new BufferedReader(new FileReader("myNet/test.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();
    }
}      
package ServerClientTCPDemo4;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class serverDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器Socket對象
        ServerSocket ss = new ServerSocket(12345);

        // 監聽用戶端連接配接,傳回i個對應的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.7 TCP通信練習5

  • 需求:

    用戶端:資料來自于文本檔案,接收伺服器回報

    伺服器:接收到的資料寫入文本檔案,給出回報

  • 案例分析

    建立用戶端對象,建立輸入流對象指向檔案,每讀入一行資料就給伺服器輸出一行資料,輸出結束後使用shutdownOutput()方法告知服務端傳輸結束

    建立伺服器對象,建立輸出流對象指向檔案,每接受一行資料就使用輸出流輸出到檔案中,傳輸結束後。使用輸出流給用戶端回報資訊

    用戶端接受服務端的回饋資訊

  • 相關方法
Java學習筆記之網絡程式設計

 示例

package ServerClientTCPDemo5;

import java.io.*;
import java.net.Socket;

public class clientDemo {
    public static void main(String[] args) throws IOException {
        // 建立用戶端Socket對象
        Socket s = new Socket("127.0.0.1", 12345);

        // 封裝文本檔案的資料
        BufferedReader br = new BufferedReader(
                new FileReader("myNet/test.java"));

        // 封裝輸出流寫資料
        BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(s.getOutputStream()));
        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // pubic void shutdownOutput()
        s.shutdownOutput();

        // 接收回報
        BufferedReader brClient = new BufferedReader(
                new InputStreamReader(s.getInputStream())
        );
        String data = brClient.readLine();
        System.out.println("伺服器的回報: " + data);

        // 釋放資源
        br.close();
        s.close();


    }
}      
package ServerClientTCPDemo5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class serverDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器Socket對象
        ServerSocket ss = new ServerSocket(12345);

        // 監聽用戶端連接配接,傳回一個對應的Socket對象
        Socket s = ss.accept();

        // 接收資料
        BufferedReader br = new BufferedReader(
                new InputStreamReader(s.getInputStream())
        );

        // 把資料寫入文本檔案
        BufferedWriter bw = new BufferedWriter(
                new FileWriter("myNet/test.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.8 TCP通信聯系6

  • 需求:

    用戶端:資料來自于文本檔案,接收伺服器回報

    伺服器:接收到的資料寫入文本檔案,給出回報,代碼用線程進行封裝,為每一個用戶端開啟一個線程

  • 案例分析

    建立用戶端對象,建立輸入流對象指向檔案,每讀入一行資料就給伺服器輸出一行資料,輸出結束後使用shutdownOutput()方法告知服務端傳輸結束

    建立多線程類,在run()方法中讀取用戶端發送的資料,為了防止檔案重名,使用計數器給檔案名編号,接受結束後使用輸出流給用戶端發送回報資訊

    建立服務端對象,每監聽到一個用戶端則開啟一個新的線程接受資料

    用戶端接受服務端的回饋資訊

示例

package ServerClientTCPDemo6;


import java.io.*;
import java.net.Socket;

public class clientDemo {
    public static void main(String[] args) throws IOException {
        // 建立Socket對象
        Socket s = new Socket("127.0.0.1", 12345);

        // 封裝文本檔案的資料
        BufferedReader br = new BufferedReader(
                new FileReader("myNet/test.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();

    }
}      
package ServerClientTCPDemo6;

import java.io.*;
import java.net.Socket;

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/test[" + count + "].java");

            while (file.exists()) {
                count++;
                file = new File("myNet/test[" + 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();
        }
    }
}      
package ServerClientTCPDemo6;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class serverDemo {
    public static void main(String[] args) throws IOException {
        // 建立伺服器Socket對象
        ServerSocket ss = new ServerSocket(12345);

        while (true) {
            // 監聽用戶端連接配接,傳回一個對應的Socket對象
            Socket s = ss.accept();
            // 為每一個用戶端開啟一個線程
            new Thread(new serverThread(s)).start();

        }
    }
}