1. 程式人生 > >19、網絡編程 (Socket套接字編程)

19、網絡編程 (Socket套接字編程)

目的 throws 通信協議 load 字節 隨機 ram java 使用

網絡模型

*A:網絡模型
    TCP/IP協議中的四層分別是應用層、傳輸層、網絡層和鏈路層,每層分別負責不同的通信功能,接下來針對這四層進行詳細地講解。
    鏈路層:鏈路層是用於定義物理傳輸通道,通常是對某些網絡連接設備的驅動協議,例如針對光纖、網線提供的驅動。
    網絡層:網絡層是整個TCP/IP協議的核心,它主要用於將傳輸的數據進行分組,將分組數據發送到目標計算機或者網絡。
    傳輸層:主要使網絡程序進行通信,在進行網絡通信時,可以采用TCP協議,也可以采用UDP協議。
    應用層:主要負責應用程序的協議,例如HTTP協議、FTP協議等。

IP地址

*A:IP地址
    在TCP/IP協議中,這個標識號就是IP地址,它可以唯一標識一臺計算機,
    目前,IP地址廣泛使用的版本是IPv4,它是由4個字節大小的二進制數來表示,如:00001010000000000000000000000001。
    由於二進制形式表示的IP地址非常不便記憶和處理,因此通常會將IP地址寫成十進制的形式,
    每個字節用一個十進制數字(0-255)表示,數字間用符號“.”分開,如 “192.168.1.100”
    127.0.0.1 為本地主機地址(本地回環地址)

端口號

*A:端口號
    通過IP地址可以連接到指定計算機,但如果想訪問目標計算機中的某個應用程序,還需要指定端口號。
    在計算機中,不同的應用程序是通過端口號區分的。
    端口號是用兩個字節(16位的二進制數)表示的,它的取值範圍是0~65535,
    其中,0~1023之間的端口號用於一些知名的網絡服務和應用,用戶的普通應用程序需要使用1024以上的端口號,從而避免端口號被另外一個應用或服務所占用

InetAddress類

*A:InetAddress類
    /*
     *  表示互聯網中的IP地址
     *    java.net.InetAddress
     *  靜態方法
     *    static InetAddress  getLocalHost()   LocalHost本地主機
     *    返回本地主機,返回值InetAddress對象
     *
     *    static InetAddress getByName(String hostName)傳遞主機名,獲取IP地址對象
     *
     *  非靜態方法
     *     String getHoustAddress()獲取主機IP地址
     *     String getHoustName()獲取主機名
     *
     */
    public class InetAddressDemo {
        public static void main(String[] args)throws UnknownHostException {
            function_1();
        }
        /*
         * static InetAddress getByName(String hostName)傳遞主機名,獲取IP地址對象
         */
        public static void function_1()throws UnknownHostException {
            InetAddress inet = InetAddress.getByName("www.baidu.com");
            System.out.println(inet);
        }
        /*
     *  static InetAddress  getLocalHost()   LocalHost本地主機
     */
        public static void function() throws UnknownHostException{
            InetAddress inet = InetAddress.getLocalHost();
            //輸出結果就是主機名,和 IP地址
            System.out.println(inet.toString());

            String ip = inet.getHostAddress();
            String name = inet.getHostName();
            System.out.println(ip+"   "+name);

        /*String host = inet.toString();
        String[] str = host.split("/");
        for(String s : str){
          System.out.println(s);
        }*/
        }
    }

UDP協議

*A:UDP協議
    a:UDP協議概述:
        UDP是無連接通信協議,即在數據傳輸時,數據的發送端和接收端不建立邏輯連接。
        簡單來說,當一臺計算機向另外一臺計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,同樣接收端在收到數據時,也不會向發送端反饋是否收到數據。
    b:UDP協議特點:
        由於使用UDP協議消耗資源小,通信效率高,所以通常都會用於音頻、視頻和普通數據的傳輸例如視頻會議都使用UDP協議,
        因為這種情況即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。

TCP協議

*A:TCP協議
    TCP協議是面向連接的通信協議,即在傳輸數據前先在發送端和接收端建立邏輯連接,然後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。
    在TCP連接中必須要明確客戶端與服務器端,
    由客戶端向服務端發出連接請求,每次連接的創建都需要經過“三次握手”。
        第一次握手,客戶端向服務器端發出連接請求,等待服務器確認
        第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求
        第三次握手,客戶端再次向服務器端發送確認信息,確認連接

數據包和發送對象介紹

*A:數據包和發送對象介紹:
    DatagramPacket數據包的作用就如同是“集裝箱”,
        可以將發送端或者接收端的數據封裝起來。然而運輸貨物只有“集裝箱”是不夠的,還需要有碼頭。
        在程序中需要實現通信只有DatagramPacket數據包也同樣不行,為此JDK中提供的一個DatagramSocket類。
        DatagramSocket類的作用就類似於碼頭,使用這個類的實例對象就可以發送和接收DatagramPacket數據包
        DatagramPacket:封裝數據
        DatagramSocket:發送DatagramPacket

UDP發送端

*A:UDP發送端
    /*
    *  實現UDP協議的發送端:
    *    實現封裝數據的類 java.net.DatagramPacket  將你的數據包裝
    *    實現數據傳輸的類 java.net.DatagramSocket  將數據包發出去
    *
    *  實現步驟:
    *    1. 創建DatagramPacket對象,封裝數據, 接收的地址和端口
    *    2. 創建DatagramSocket
    *    3. 調用DatagramSocket類方法send,發送數據包
    *    4. 關閉資源
    *
    *    DatagramPacket構造方法:
    *      DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    *
    *    DatagramSocket構造方法:
    *      DatagramSocket()空參數
    *      方法: send(DatagramPacket d)
    *
    */
    public class UDPSend {
        public static void main(String[] args) throws IOException {
            //創建數據包對象,封裝要發送的數據,接收端IP,端口
            byte[] date = "你好UDP".getBytes();
            //創建InetAddress對象,封裝自己的IP地址
            InetAddress inet = InetAddress.getByName("127.0.0.1");
            DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000);
            //創建DatagramSocket對象,數據包的發送和接收對象
            DatagramSocket ds = new DatagramSocket();
            //調用ds對象的方法send,發送數據包
            ds.send(dp);
            //關閉資源
            ds.close();
        }
    }

UDP接收端

*A:UDP接收端
    /*
     *  實現UDP接收端
     *    實現封裝數據包 java.net.DatagramPacket 將數據接收
     *    實現輸出傳輸     java.net.DatagramSocket 接收數據包
     *
     *  實現步驟:
     *     1. 創建DatagramSocket對象,綁定端口號
     *         要和發送端端口號一致
     *     2. 創建字節數組,接收發來的數據
     *     3. 創建數據包對象DatagramPacket
     *     4. 調用DatagramSocket對象方法
     *        receive(DatagramPacket dp)接收數據,數據放在數據包中
     *     5. 拆包
     *          發送的IP地址
     *            數據包對象DatagramPacket方法getAddress()獲取的是發送端的IP地址對象
     *            返回值是InetAddress對象
     *          接收到的字節個數
     *            數據包對象DatagramPacket方法 getLength()
     *          發送方的端口號
     *            數據包對象DatagramPacket方法 getPort()發送端口
     *     6. 關閉資源
     */
    public class UDPReceive {
        public static void main(String[] args)throws IOException {
            //創建數據包傳輸對象DatagramSocket 綁定端口號
            DatagramSocket ds = new DatagramSocket(6000);
            //創建字節數組
            byte[] data = new byte[1024];
            //創建數據包對象,傳遞字節數組
            DatagramPacket dp = new DatagramPacket(data, data.length);
            //調用ds對象的方法receive傳遞數據包
            ds.receive(dp);
        }
    }

UDP接收端的拆包?

*A:UDP接收端的拆包

    /*
     *  實現UDP接收端
     *    實現封裝數據包 java.net.DatagramPacket 將數據接收
     *    實現輸出傳輸     java.net.DatagramSocket 接收數據包
     *
     *  實現步驟:
     *     1. 創建DatagramSocket對象,綁定端口號
     *         要和發送端端口號一致
     *     2. 創建字節數組,接收發來的數據
     *     3. 創建數據包對象DatagramPacket
     *     4. 調用DatagramSocket對象方法
     *        receive(DatagramPacket dp)接收數據,數據放在數據包中
     *     5. 拆包
     *          發送的IP地址
     *            數據包對象DatagramPacket方法getAddress()獲取的是發送端的IP地址對象
     *            返回值是InetAddress對象
     *          接收到的字節個數
     *            數據包對象DatagramPacket方法 getLength()
     *          發送方的端口號
     *            數據包對象DatagramPacket方法 getPort()發送端口
     *     6. 關閉資源
     */
    public class UDPReceive {
        public static void main(String[] args)throws IOException {
            //創建數據包傳輸對象DatagramSocket 綁定端口號
            DatagramSocket ds = new DatagramSocket(6000);
            //創建字節數組
            byte[] data = new byte[1024];
            //創建數據包對象,傳遞字節數組
            DatagramPacket dp = new DatagramPacket(data, data.length);
            //調用ds對象的方法receive傳遞數據包
            ds.receive(dp);

            //獲取發送端的IP地址對象
            String ip=dp.getAddress().getHostAddress();

            //獲取發送的端口號
            int port = dp.getPort();

            //獲取接收到的字節個數
            int length = dp.getLength();
            System.out.println(new String(data,0,length)+"..."+ip+":"+port);
            ds.close();
        }
    }

鍵盤輸入的聊天

*A:鍵盤輸入的聊天
    *a:發送端:
    /*
     * 實現UDP發送,鍵盤輸入的形式
     * 輸入完畢,發送給接收端
     */
    public class UDPSend {
        public static void main(String[] args) throws IOException {
            Scanner sc = new Scanner(System.in);
            DatagramSocket ds = new DatagramSocket();
            InetAddress inet = InetAddress.getByName("127.0.0.1");
            while(true){
                String message = sc.nextLine();
              /*if("886".equals(message)){
                break;
              }*/
                byte[] date = message.getBytes();
                DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000);
                ds.send(dp);
            }
            //  ds.close();
        }
    }

    /*
     *  實現UDP接收端
     *  永不停歇的接收端
     */
    public class UDPReceive {
        public static void main(String[] args)throws IOException {
            //創建數據包傳輸對象DatagramSocket 綁定端口號
            DatagramSocket ds = new DatagramSocket(6000);
            //創建字節數組
            byte[] data = new byte[1024];
            //創建數據包對象,傳遞字節數組
            while(true){
                DatagramPacket dp = new DatagramPacket(data, data.length);
                //調用ds對象的方法receive傳遞數據包
                ds.receive(dp);

                //獲取發送端的IP地址對象
                String ip=dp.getAddress().getHostAddress();

                //獲取發送的端口號
                int port = dp.getPort();

                //獲取接收到的字節個數
                int length = dp.getLength();
                System.out.println(new String(data,0,length)+"..."+ip+":"+port);
            }
            //ds.close();
        }
    }

TCP的客戶端和服務器

*A:TCP的客戶端和服務器
    TCP通信同UDP通信一樣,都能實現兩臺計算機之間的通信,通信的兩端都需要創建socket對象。
    區別在於,UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據。
    而TCP通信是嚴格區分客戶端與服務器端的,在通信時,必須先由客戶端去連接服務器端才能實現通信,
    服務器端不可以主動連接客戶端,並且服務器端程序需要事先啟動,等待客戶端的連接。
    在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。
    通信時,首先創建代表服務器端的ServerSocket對象,該對象相當於開啟一個服務,並等待客戶端的連接,然後創建代表客戶端的Socket對象向服務器端發出連接請求,服務器端響應請求,兩者建立連接開始通信。

TCP的客戶端程序

*A:TCP的客戶端程序
    /*
     *  實現TCP客戶端,連接到服務器
     *  和服務器實現數據交換
     *  實現TCP客戶端程序的類 java.net.Socket
     *
     *  構造方法:
     *      Socket(String host, int port)  傳遞服務器IP和端口號
     *      註意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
     *
     *    OutputStream  getOutputStream() 返回套接字的輸出流
     *      作用: 將數據輸出,輸出到服務器
     *
     *    InputStream getInputStream() 返回套接字的輸入流
     *      作用: 從服務器端讀取數據
     *
     *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
     */
    public class TCPClient {
        public static void main(String[] args)throws IOException {
            //創建Socket對象,連接服務器
            Socket socket = new Socket("127.0.0.1", 8888);
            //通過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器
            OutputStream out = socket.getOutputStream();
            out.write("服務器OK".getBytes());
            socket.close();
        }
    }

TCP的服務器程序accept方法

*A:TCP的服務器程序accept方法
    /*
     *  實現TCP服務器程序
     *  表示服務器程序的類 java.net.ServerSocket
     *  構造方法:
     *    ServerSocket(int port) 傳遞端口號
     *
     *  很重要的事情: 必須要獲得客戶端的套接字對象Socket
     *    Socket  accept()
     */
    public class TCPServer {
        public static void main(String[] args) throws IOException {
            ServerSocket server = new ServerSocket(8888);
            //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象
            Socket socket = server.accept();
            //通過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據
            InputStream in = socket.getInputStream();
            byte[] data = new byte[1024];
            int len = in.read(data);
            System.out.println(new String(data,0,len));


            socket.close();
            server.close();
        }
    }

TCP的服務器程序讀取客戶端數據

*A:TCP的服務器程序讀取客戶端數據

    /*
     *  實現TCP客戶端,連接到服務器
     *  和服務器實現數據交換
     *  實現TCP客戶端程序的類 java.net.Socket
     *
     *  構造方法:
     *      Socket(String host, int port)  傳遞服務器IP和端口號
     *      註意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
     *
     *    OutputStream  getOutputStream() 返回套接字的輸出流
     *      作用: 將數據輸出,輸出到服務器
     *
     *    InputStream getInputStream() 返回套接字的輸入流
     *      作用: 從服務器端讀取數據
     *
     *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
     */
    public class TCPClient {
        public static void main(String[] args)throws IOException {
            //創建Socket對象,連接服務器
            Socket socket = new Socket("127.0.0.1", 8888);
            //通過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器
            OutputStream out = socket.getOutputStream();
            out.write("服務器OK".getBytes());
            socket.close();
        }
    }
    /*
     *  實現TCP服務器程序
     *  表示服務器程序的類 java.net.ServerSocket
     *  構造方法:
     *    ServerSocket(int port) 傳遞端口號
     *
     *  很重要的事情: 必須要獲得客戶端的套接字對象Socket
     *    Socket  accept()
     */
    public class TCPServer {
        public static void main(String[] args) throws IOException{
            ServerSocket server = new ServerSocket(8888);
            //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象
            Socket socket = server.accept();
            //通過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據
            InputStream in = socket.getInputStream();
            byte[] data = new byte[1024];
            int len = in.read(data);
            System.out.println(new String(data,0,len));

        }
    }

TCP的服務器和客戶端的數據交換?

*A:TCP的服務器和客戶端的數據交換
    /*
     *  實現TCP客戶端,連接到服務器
     *  和服務器實現數據交換
     *  實現TCP客戶端程序的類 java.net.Socket
     *
     *  構造方法:
     *      Socket(String host, int port)  傳遞服務器IP和端口號
     *      註意:構造方法只要運行,就會和服務器進行連接,連接失敗,拋出異常
     *
     *    OutputStream  getOutputStream() 返回套接字的輸出流
     *      作用: 將數據輸出,輸出到服務器
     *
     *    InputStream getInputStream() 返回套接字的輸入流
     *      作用: 從服務器端讀取數據
     *
     *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,自己new流,不行
     */
    public class TCPClient {
        public static void main(String[] args)throws IOException {
            //創建Socket對象,連接服務器
            Socket socket = new Socket("127.0.0.1", 8888);
            //通過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器
            OutputStream out = socket.getOutputStream();
            out.write("服務器OK".getBytes());
            //讀取服務器發回的數據,使用socket套接字對象中的字節輸入流
            InputStream in = socket.getInputStream();
            byte[] data = new byte[1024];
            int len = in.read(data);
            System.out.println(new String(data,0,len));

            socket.close();
        }
    }
    /*
     *  實現TCP服務器程序
     *  表示服務器程序的類 java.net.ServerSocket
     *  構造方法:
     *    ServerSocket(int port) 傳遞端口號
     *
     *  很重要的事情: 必須要獲得客戶端的套接字對象Socket
     *    Socket  accept()
     */
    public class TCPServer {
        public static void main(String[] args) throws IOException{
            ServerSocket server = new ServerSocket(8888);
            //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象
            Socket socket = server.accept();
            //通過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據
            InputStream in = socket.getInputStream();
            byte[] data = new byte[1024];
            int len = in.read(data);
            System.out.println(new String(data,0,len));

            //服務器向客戶端回數據,字節輸出流,通過客戶端套接字對象獲取字節輸出流
            OutputStream out = socket.getOutputStream();
            out.write("收到,謝謝".getBytes());

            socket.close();
            server.close();
        }
    }

TCP的中的流對象

*A:TCP的中的流對象
    參見圖解TCP中的流對象.jpg  

18TCP圖片上傳案例分析

*A:圖片上傳案例分析
     參見圖解TCP上傳圖片案例.jpg  

TCP上傳客戶端

*A TCP上傳客戶端
    /*
     *  實現TCP圖片上傳客戶端
     *  實現步驟:
     *    1. Socket套接字連接服務器
     *    2. 通過Socket獲取字節輸出流,寫圖片
     *    3. 使用自己的流對象,讀取圖片數據源
     *         FileInputStream
     *    4. 讀取圖片,使用字節輸出流,將圖片寫到服務器
     *       采用字節數組進行緩沖
     *    5. 通過Socket套接字獲取字節輸入流
     *       讀取服務器發回來的上傳成功
     *    6. 關閉資源
     */
    public class TCPClient {
        public static void main(String[] args) throws IOException {
            Socket socket = new Socket("127.0.0.1", 8000);
            //獲取字節輸出流,圖片寫到服務器
            OutputStream out = socket.getOutputStream();
            //創建字節輸入流,讀取本機上的數據源圖片
            FileInputStream fis = new FileInputStream("c:\\t.jpg");
            //開始讀寫字節數組
            int len = 0 ;
            byte[] bytes = new byte[1024];
            while((len = fis.read(bytes))!=-1){
                out.write(bytes, 0, len);
            }
            //給服務器寫終止序列
            //socket.shutdownOutput();

            //獲取字節輸入流,讀取服務器的上傳成功
            InputStream in = socket.getInputStream();

            len = in.read(bytes);
            System.out.println(new String(bytes,0,len));

            fis.close();
            socket.close();
        }
    }

TCP上傳服務器?

A:TCP上傳服務器
    /*
     *  TCP圖片上傳服務器
     *   1. ServerSocket套接字對象,監聽端口8000
     *   2. 方法accept()獲取客戶端的連接對象
     *   3. 客戶端連接對象獲取字節輸入流,讀取客戶端發送圖片
     *   4. 創建File對象,綁定上傳文件夾
     *       判斷文件夾存在, 不存,在創建文件夾
     *   5. 創建字節輸出流,數據目的File對象所在文件夾
     *   6. 字節流讀取圖片,字節流將圖片寫入到目的文件夾中
     *   7. 將上傳成功會寫客戶端
     *   8. 關閉資源
     *
     */
    public class TCPServer {
        public static void main(String[] args) throws IOException {
            ServerSocket server = new ServerSocket(8000);
            Socket socket = server.accept();
            //通過客戶端連接對象,獲取字節輸入流,讀取客戶端圖片
            InputStream in = socket.getInputStream();
            //將目的文件夾封裝到File對象
            File upload = new File("d:\\upload");
            if(!upload.exists())
                upload.mkdirs();
            //創建字節輸出流,將圖片寫入到目的文件夾中
            FileOutputStream fos = new FileOutputStream(upload+"t.jpg");
            //讀寫字節數組
            byte[] bytes = new byte[1024];
            int len = 0 ;
            while((len = in.read(bytes))!=-1){
                fos.write(bytes, 0, len);
            }
            //通過客戶端連接對象獲取字節輸出流
            //上傳成功寫回客戶端
            socket.getOutputStream().write("上傳成功".getBytes());

            fos.close();
            socket.close();
            server.close();
        }
    }

TCP圖片上傳問題解決

/*
- 實現TCP圖片上傳客戶端
- 實現步驟:
- 1. Socket套接字連接服務器
- 1. 通過Socket獲取字節輸出流,寫圖片
- 1. 使用自己的流對象,讀取圖片數據源
- FileInputStream
- 1. 讀取圖片,使用字節輸出流,將圖片寫到服務器
- 采用字節數組進行緩沖
- 1. 通過Socket套接字獲取字節輸入流
- 讀取服務器發回來的上傳成功
- 1. 關閉資源
 */
    public class TCPClient {
        public static void main(String[] args) throws IOException {
            Socket socket = new Socket("127.0.0.1", 8000);
            //獲取字節輸出流,圖片寫到服務器
            OutputStream out = socket.getOutputStream();
            //創建字節輸入流,讀取本機上的數據源圖片
            FileInputStream fis = new FileInputStream("c:\\t.jpg");
            //開始讀寫字節數組
            int len = 0 ;
            byte[] bytes = new byte[1024];
            while((len = fis.read(bytes))!=-1){
                out.write(bytes, 0, len);
            }
            //給服務器寫終止序列
            socket.shutdownOutput();//想服務端寫入一個結束標誌

            //獲取字節輸入流,讀取服務器的上傳成功
            InputStream in = socket.getInputStream();

            len = in.read(bytes);
            System.out.println(new String(bytes,0,len));

            fis.close();
            socket.close();
        }
    }

TCP上傳文件名

*A:TCP上傳文件名
    /*
     *  TCP圖片上傳服務器
     *   1. ServerSocket套接字對象,監聽端口8000
     *   2. 方法accept()獲取客戶端的連接對象
     *   3. 客戶端連接對象獲取字節輸入流,讀取客戶端發送圖片
     *   4. 創建File對象,綁定上傳文件夾
     *       判斷文件夾存在, 不存,在創建文件夾
     *   5. 創建字節輸出流,數據目的File對象所在文件夾
     *   6. 字節流讀取圖片,字節流將圖片寫入到目的文件夾中
     *   7. 將上傳成功會寫客戶端
     *   8. 關閉資源
     *
     */
    public class TCPServer {
        public static void main(String[] args) throws IOException {
            ServerSocket server = new ServerSocket(8000);
            Socket socket = server.accept();
            //通過客戶端連接對象,獲取字節輸入流,讀取客戶端圖片
            InputStream in = socket.getInputStream();
            //將目的文件夾封裝到File對象
            File upload = new File("d:\\upload");
            if(!upload.exists())
                upload.mkdirs();
            //防止文件同名被覆蓋,從新定義文件名字
            //規則:  域名+毫秒值+6位隨機數
            String filename="itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
            //創建字節輸出流,將圖片寫入到目的文件夾中
            FileOutputStream fos = new FileOutputStream(upload+ File.separator+filename);
            //讀寫字節數組
            byte[] bytes = new byte[1024];
            int len = 0 ;
            while((len = in.read(bytes))!=-1){
                fos.write(bytes, 0, len);
            }
            //通過客戶端連接對象獲取字節輸出流
            //上傳成功寫回客戶端
            socket.getOutputStream().write("上傳成功".getBytes());

            fos.close();
            socket.close();
            server.close();
        }
    }

多線程上傳案例

*A:多線程上傳案例
    public class TCPThreadServer {
        public static void main(String[] args) throws IOException {
            ServerSocket server = new ServerSocket(8000);
            while (true) {
                // 獲取到一個客戶端,必須開啟新線程,為這個客戶端服務
                Socket socket = server.accept();
                new Thread(new Upload(socket)).start();
            }
        }
    }

    public class Upload implements Runnable {
        private Socket socket;

        public Upload(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {
                // 通過客戶端連接對象,獲取字節輸入流,讀取客戶端圖片
                InputStream in = socket.getInputStream();
                // 將目的文件夾封裝到File對象
                File upload = new File("d:\\upload");
                if (!upload.exists())
                    upload.mkdirs();

                // 防止文件同名被覆蓋,從新定義文件名字
                // 規則: 域名+毫秒值+6位隨機數
                String filename = "itcast" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";
                // 創建字節輸出流,將圖片寫入到目的文件夾中
                FileOutputStream fos = new FileOutputStream(upload + File.separator + filename);
                // 讀寫字節數組
                byte[] bytes = new byte[1024];
                int len = 0;
                while ((len = in.read(bytes)) != -1) {
                    fos.write(bytes, 0, len);
                }
                // 通過客戶端連接對象獲取字節輸出流
                // 上傳成功寫回客戶端
                socket.getOutputStream().write("上傳成功".getBytes());

                fos.close();
                socket.close();
            } catch (Exception ex) {

            }
        }
    }

總結

19、網絡編程 (Socket套接字編程)