程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java基礎學習第二十六天——網絡編程總結

Java基礎學習第二十六天——網絡編程總結

編輯:JAVA綜合教程

Java基礎學習第二十六天——網絡編程總結


文檔版本 開發工具 測試平台 工程名字 日期 作者 備注 V1.0       2016.04.03 lutianfei none

第十二章網絡編程

網絡編程概述

就是用來實現網絡互連的不同計算機上運行的程序間可以進行數據交換。

網絡模型

計算機網絡之間以何種規則進行通信,就是網絡模型研究問題。 網絡模型一般是指
OSI(Open System Interconnection開放系統互連)參考模型 TCP/IP參考模型

\

網絡模型7層概述

1 . 物理層:主要定義物理設備標准,如網線的接口類型、光纖的接口類型、各種傳輸介質的傳輸速率等。它的主要作用是傳輸比特流。這一層的數據叫做比特

2 . 數據鏈路層:主要將從物理層接收的數據進行MAC地址(網卡的地址)的封裝解封裝。常把這一層的數據叫做。在這一層工作的設備是交換機,數據通過交換機來傳輸。

3 . 網絡層:主要將從下層接收到的數據進行IP地址封裝解封裝。在這一層工作的設備是路由器,常把這一層的數據叫做數據包

4 . 傳輸層:定義了一些傳輸數據的協議端口號。 主要是將從下層接收的數據進行分段傳輸,到達目的地址後再進行重組。常常把這一層數據叫做

TCP:傳輸控制協議,傳輸效率低可靠性強,用於傳輸可靠性要求高,數據量大的數據。 UDP:用戶數據包協議,與TCP特性恰恰相反,用於傳輸可靠性要求不高數據量小的數據。
如QQ聊天數據就是通過這種方式傳輸的。

5 . 會話層:通過傳輸層建立數據傳輸的通路。主要在你的系統之間發起會話或者接受會話請求(設備之間需要互相認識可以是IP也可以是MAC或者是主機名)。

6 . 表示層:主要是進行對接收的數據進行解釋加密解密壓縮解壓縮等(把計算機能夠識別的東西轉換成人能夠能識別的東西(如圖片、聲音等)。

7 . 應用層: 主要是一些終端的應用,比如說FTP(各種文件下載),WEB(IE浏覽),QQ之類的(可以把它理解成我們在電腦屏幕上可以看到的東西.就是終端應用)。

網絡通信三要素

IP地址:InetAddress
網絡中設備的標識,不易記憶,可用主機名 端口號
用於標識進程的邏輯地址,不同進程的標識 傳輸協議
通訊的規則 常見協議:TCP,UDP

網絡通信模型

第一個條件:我要先找到你 (IP) 第二個條件:你得有接收數據的地方 耳朵 (端口) 第三個條件:我跟你說話,你能接收到,咱按什麼方式接收啊,我說英文你懂嗎,說韓文你懂嗎,不懂是吧,所以我還是說中文把.(協議)

IP地址

要想讓網絡中的計算機能夠互相通信,必須為每台計算機指定一個標識號,通過這個標識號來指定要接受數據的計算機和識別發送的計算機,在TCP/IP協議中,這個標識號就是IP地址。

如何獲取和操作IP地址呢?

為了方便我們對IP地址的獲取和操作,java提供了一個類InetAddress

所謂IP地址就是給每個連接在Internet上的主機分配的一個32bit地址。按照TCP/IP規定,IP地址用二進制來表示,每個IP地址長32bit,比特換算成字節,就是4個字節。IP地址的這種表示法叫做“點分十進制表示法”,這顯然比1和0容易記憶得多。

IP地址的組成

IP地址 = 網絡號碼+主機地址

A類IP地址 : 第一段號碼為網絡號碼剩下的三段號碼為本地計算機的號碼

B類IP地址:前二段號碼為網絡號碼剩下的二段號碼為本地計算機的號碼

C類IP地址:前三段號碼為網絡號碼剩下的一段號碼為本地計算機的號碼

特殊地址:

127.0.0.1 回環地址,可用於測試本機的網絡是否有問題。
eg : ping 127.0.0.1 xxx.xxx.xxx.0 網絡地址 xxx.xxx.xxx.255 廣播地址
InetAddress類的使用
沒有構造方法,那麼如何使類提供的功能呢? 要掌握的方法
獲取任意主機:getByName 主機名:getHostName 主機Ip地址:getHostAddress

端口號

物理端口 網卡口 邏輯端口 我們指的就是邏輯端口
A:每個網絡程序都會至少有一個邏輯端口 B:用於標識進程的邏輯地址,不同進程的標識 C:有效端口:0~65535,其中0~1024系統使用或保留端口。 通過360可以查看端口號

協議UDP和TCP

UDP
數據源目的封裝成數據包中,不需要建立連接;每個數據報的大小在限制在64k;因無連接,是不可靠協議;不需要建立連接,速度快 舉例:
聊天留言,在線視頻,視頻會議,發短信,郵局包裹。
TCP
建立連接,形成傳輸數據的通道;在連接中進行大數據量傳輸;通過三次握手完成連接,是可靠協議;必須建立連接效率會稍低 舉例:
下載,打電話,QQ聊天(你在線嗎,在線,就回應下,就開始聊天了)

 

Socket編程

又稱網絡編程套接字編程 Socket套接字:
網絡上具有唯一標識的IP地址端口號組合在一起才能構成唯一能識別的標識符套接字。 Socket原理機制:
通信的兩端都有Socket。 網絡通信其實就是Socket間的通信。 數據在兩個Socket間通過IO傳輸。

 

UDP傳輸過程

DatagramSocketDatagramPacket 建立發送端接收端。 建立數據包。 調用Socket的發送接收方法。 關閉Socket。 發送端與接收端是兩個獨立的運行程序。

UDP傳輸-發送端思路

1:建立udp的socket服務 2:將要發送的數據封裝成數據包 3:通過udp的socket服務,將數據包發送出

4:關閉資源

UDP傳輸-發送端代碼

/*
 * UDP協議發送數據:
 * A:創建發送端Socket對象
 * B:創建數據,並把數據打包
 * C:調用Socket對象的發送方法發送數據包
 * D:釋放資源
 */
public class SendDemo {
    public static void main(String[] args) throws IOException {
        // 創建發送端Socket對象
        // DatagramSocket()
        DatagramSocket ds = new DatagramSocket();

        // 創建數據,並把數據打包
        // DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        // 創建數據
        byte[] bys = "hello,udp,我來了".getBytes();
        // 長度
        int length = bys.length;
        // IP地址對象
        InetAddress address = InetAddress.getByName("192.168.12.92");
        // 端口
        int port = 10086;
        DatagramPacket dp = new DatagramPacket(bys, length, address, port);

        // 調用Socket對象的發送方法發送數據包
        // public void send(DatagramPacket p)
        ds.send(dp);

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

 

UDP傳輸-接收端思路

1:建立udp的socket服務. 2:通過receive方法接收數據 3:將收到的數據存儲到數據包對象中 4:通過數據包對象的功能來完成對接收到數據進行解析.

5:可以對資源進行關閉

UDP傳輸-接收端代碼

/*
 * UDP協議接收數據:
 * A:創建接收端Socket對象
 * B:創建一個數據包(接收容器)
 * C:調用Socket對象的接收方法接收數據
 * D:解析數據包,並顯示在控制台
 * E:釋放資源
 */
public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        // 創建接收端Socket對象
        // DatagramSocket(int port)
        DatagramSocket ds = new DatagramSocket(10086);

        // 創建一個數據包(接收容器)
        // DatagramPacket(byte[] buf, int length)
        byte[] bys = new byte[1024];
        int length = bys.length;
        DatagramPacket dp = new DatagramPacket(bys, length);

        // 調用Socket對象的接收方法接收數據
        // public void receive(DatagramPacket p)
        ds.receive(dp); // 阻塞式

        // 解析數據包,並顯示在控制台
        // 獲取對方的ip
        // public InetAddress getAddress()
        InetAddress address = dp.getAddress();
        String ip = address.getHostAddress();
        // public byte[] getData():獲取數據緩沖區
        // public int getLength():獲取數據的實際長度
        byte[] bys2 = dp.getData();
        int len = dp.getLength();
        String s = new String(bys2, 0, len);
        System.out.println(ip + "傳遞的數據是:" + s);

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

 

優化後代碼
/*
 * 多次啟動接收端:
 *         java.net.BindException: Address already in use: Cannot bind
 *         端口被占用。
 */
public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        // 創建接收端的Socket對象
        DatagramSocket ds = new DatagramSocket(12345);

        // 創建一個包裹
        byte[] bys = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys, bys.length);

        // 接收數據
        ds.receive(dp);

        // 解析數據
        String ip = dp.getAddress().getHostAddress();
        String s = new String(dp.getData(), 0, dp.getLength());
        System.out.println("from " + ip + " data is : " + s);

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




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

        // 創建數據並打包
        byte[] bys = "helloworld".getBytes();
        DatagramPacket dp = new DatagramPacket(bys, bys.length,
                InetAddress.getByName("192.168.12.92"), 12345);

        // 發送數據
        ds.send(dp);

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

 

UDP案例

從鍵盤錄入數據進行發送,如果輸入的是886那麼客戶端就結束輸入數據。
/*
 * 多次啟動接收端:
 *         java.net.BindException: Address already in use: Cannot bind
 *         端口被占用。
 */
public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        // 創建接收端的Socket對象
        DatagramSocket ds = new DatagramSocket(12345);

        while (true) {
            // 創建一個包裹
            byte[] bys = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bys, bys.length);

            // 接收數據
            ds.receive(dp);

            // 解析數據
            String ip = dp.getAddress().getHostAddress();
            String s = new String(dp.getData(), 0, dp.getLength());
            System.out.println("from " + ip + " data is : " + s);
        }

        // 釋放資源
        // 接收端應該一直開著等待接收數據,是不需要關閉
        // ds.close();
    }
}




/*
 * 數據來自於鍵盤錄入
 * 鍵盤錄入數據要自己控制錄入結束。
 */
public class SendDemo {
    public static void main(String[] args) throws IOException {
        // 創建發送端的Socket對象
        DatagramSocket ds = new DatagramSocket();

        // 封裝鍵盤錄入數據
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while ((line = br.readLine()) != null) {
            if ("886".equals(line)) {
                break;
            }

            // 創建數據並打包
            byte[] bys = line.getBytes();
            // DatagramPacket dp = new DatagramPacket(bys, bys.length,
            // InetAddress.getByName("192.168.12.92"), 12345);
            DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.12.255"), 12345);

            // 發送數據
            ds.send(dp);
        }

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

 

把剛才發送和接收程序分別用線程進行封裝,完成一個UDP的聊天程序。
/*
 * 通過多線程改進剛才的聊天程序,這樣我就可以實現在一個窗口發送和接收數據了
 */
public class ChatRoom {
    public static void main(String[] args) throws IOException {
        DatagramSocket dsSend = new DatagramSocket();
        DatagramSocket dsReceive = new DatagramSocket(12306);

        SendThread st = new SendThread(dsSend);
        ReceiveThread rt = new ReceiveThread(dsReceive);

        Thread t1 = new Thread(st);
        Thread t2 = new Thread(rt);

        t1.start();
        t2.start();
    }
}




public class ReceiveThread implements Runnable {
    private DatagramSocket ds;

    public ReceiveThread(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            while (true) {
                // 創建一個包裹
                byte[] bys = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bys, bys.length);

                // 接收數據
                ds.receive(dp);

                // 解析數據
                String ip = dp.getAddress().getHostAddress();
                String s = new String(dp.getData(), 0, dp.getLength());
                System.out.println("from " + ip + " data is : " + s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}



public class SendThread implements Runnable {

    private DatagramSocket ds;

    public SendThread(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            // 封裝鍵盤錄入數據
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    System.in));
            String line = null;
            while ((line = br.readLine()) != null) {
                if ("886".equals(line)) {
                    break;
                }

                // 創建數據並打包
                byte[] bys = line.getBytes();
                // DatagramPacket dp = new DatagramPacket(bys, bys.length,
                // InetAddress.getByName("192.168.12.92"), 12345);
                DatagramPacket dp = new DatagramPacket(bys, bys.length,
                        InetAddress.getByName("192.168.12.255"), 12306);

                // 發送數據
                ds.send(dp);
            }

            // 釋放資源
            ds.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

 

TCP傳輸

Socket和ServerSocket 建立客戶端和服務器端 建立連接後,通過Socket中的IO流進行數據的傳輸 關閉socket 同樣,客戶端與服務器端是兩個獨立的應用程序。

TCP傳輸-客戶端思路

1:建立客戶端的Socket服務,並明確要連接的服務器。 2:如果連接建立成功,就表明已經建立了數據傳輸的通道。就可以在該通道通過IO進行數據的讀取和寫入。該通道稱為Socket流,Socket流中既有讀取流,也有寫入流。 3:通過Socket對象的方法,可以獲取這兩個流。 4:通過流的對象可以對數據進行傳輸

5:如果傳輸數據完畢,關閉資源

TCP傳輸-客戶端代碼

/*
 * 連接被拒絕。TCP協議一定要先開服務器。
 * java.net.ConnectException: Connection refused: connect
 */
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 創建發送端的Socket對象
        // Socket(InetAddress address, int port)
        // Socket(String host, int port)
        // Socket s = new Socket(InetAddress.getByName("192.168.12.92"), 8888);
        Socket s = new Socket("192.168.12.92", 8888);

        // 獲取輸出流,寫數據
        // public OutputStream getOutputStream()
        OutputStream os = s.getOutputStream();
        os.write("hello,tcp,我來了".getBytes());

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

 

TCP傳輸-服務器端思路

1:建立服務器端的socket服務,需要一個端口 2:服務端沒有直接流的操作,而是通過accept方法獲取客戶端對象,再通過獲取到的客戶端對象的流和客戶端進行通信。 3:通過客戶端的獲取流對象的方法,讀取數據或者寫入數據

4:如果服務完成,需要關閉客戶端,然後關閉服務器,但是,一般會關閉客戶端,不會關閉服務器,因為服務端是一直提供服務的。

TCP傳輸-服務器端代碼

/*
 * TCP協議接收數據:
 * A:創建接收端的Socket對象
 * B:監聽客戶端連接。返回一個對應的Socket對象
 * C:獲取輸入流,讀取數據顯示在控制台
 * D:釋放資源
 */
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 創建接收端的Socket對象
        // ServerSocket(int port)
        ServerSocket ss = new ServerSocket(8888);

        // 監聽客戶端連接。返回一個對應的Socket對象
        // public Socket accept()
        Socket s = ss.accept(); // 偵聽並接受到此套接字的連接。此方法在連接傳入之前一直阻塞。

        // 獲取輸入流,讀取數據顯示在控制台
        InputStream is = s.getInputStream();

        byte[] bys = new byte[1024];
        int len = is.read(bys); // 阻塞式方法
        String str = new String(bys, 0, len);

        String ip = s.getInetAddress().getHostAddress();

        System.out.println(ip + "---" + str);

        // 釋放資源
        s.close();
        // ss.close(); //這個不應該關閉
    }
}

 

TCP傳輸案例

服務器給客戶端反饋
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 創建服務器Socket對象
        ServerSocket ss = new ServerSocket(9999);

        // 監聽客戶端的連接
        Socket s = ss.accept(); // 阻塞

        // 獲取輸入流
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys); // 阻塞
        String server = new String(bys, 0, len);
        System.out.println("server:" + server);

        // 獲取輸出流
        OutputStream os = s.getOutputStream();
        os.write("數據已經收到".getBytes());

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


public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 創建客戶端Socket對象
        Socket s = new Socket("192.168.12.92", 9999);

        // 獲取輸出流
        OutputStream os = s.getOutputStream();
        os.write("今天天氣很好,適合睡覺".getBytes());

        // 獲取輸入流
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys);// 阻塞
        String client = new String(bys, 0, len);
        System.out.println("client:" + client);

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

 

客戶端鍵盤錄入,服務器輸出到控制台
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 創建服務器Socket對象
        ServerSocket ss = new ServerSocket(22222);

        // 監聽客戶端連接
        Socket s = ss.accept();

        // 包裝通道內容的流
        BufferedReader br = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

        // br.close();
        s.close();
        // ss.close();
    }
}



/*
 * 客戶端鍵盤錄入,服務器輸出到控制台
 */
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 創建客戶端Socket對象
        Socket s = new Socket("192.168.12.92", 22222);

        // 鍵盤錄入數據
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        // 把通道內的流給包裝一下
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                s.getOutputStream()));

        String line = null;
        while ((line = br.readLine()) != null) {
            // 鍵盤錄入數據要自定義結束標記
            if ("886".equals(line)) {
                break;
            }
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

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

 

客戶端鍵盤錄入,服務器輸出文本文件
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 創建服務器Socket對象
        ServerSocket ss = new ServerSocket(23456);

        // 監聽客戶端連接
        Socket s = ss.accept();

        // 封裝通道內的數據
        BufferedReader br = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
        // 封裝文本文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

        String line = null;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        bw.close();
        // br.close();
        s.close();
        // ss.close();
    }
}

 

客戶端文本文件,服務器輸出到控制台
/*
 * 客戶端文本文件,服務器輸出到控制台
 */
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 創建Socket對象
        Socket s = new Socket("192.168.12.92", 34567);

        // 封裝文本文件
        BufferedReader br = new BufferedReader(new FileReader(
                "InetAddressDemo.java"));
        // 封裝通道內的流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                s.getOutputStream()));

        String line = null;
        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(34567);

        // 監聽客戶端連接
        Socket s = ss.accept();

        // 封裝通道內的流
        BufferedReader br = new BufferedReader(new InputStreamReader(
                s.getInputStream()));

        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }


        s.close();
    }
}

 

TCP傳輸容易出現的問題

客戶端連接上服務端,兩端都在等待,沒有任何數據傳輸。 通過例程分析:
因為read方法或者readLine方法是阻塞式。 解決辦法:
自定義結束標記 使用shutdownInput,shutdownOutput方法。 客戶端文本文件,服務器輸出文本文件
/*
 * 問題:按照我們正常的思路加入反饋信息,結果卻沒反應。為什麼呢?
 * 讀取文本文件是可以以null作為結束信息的,但是呢,通道內是不能這樣結束信息的。
 * 所以,服務器根本就不知道你結束了。而你還想服務器給你反饋。所以,就相互等待了。
 * 
 * 如何解決呢?
 * A:再多寫一條數據,告訴服務器,讀取到這條數據說明我就結束,你也結束吧。
 *         這樣做可以解決問題,但是不好。
 * B:Socket對象提供了一種解決方案
 *         public void shutdownOutput()
 */

public class UploadClient {
    public static void main(String[] args) throws IOException {
        // 創建客戶端Socket對象
        Socket s = new Socket("192.168.12.92", 11111);

        // 封裝文本文件
        BufferedReader br = new BufferedReader(new FileReader(
                "InetAddressDemo.java"));
        // 封裝通道內流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                s.getOutputStream()));

        String line = null;
        while ((line = br.readLine()) != null) { // 阻塞
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        //Socket提供了一個終止,它會通知服務器你別等了,我沒有數據過來了
        s.shutdownOutput();

        // 接收反饋
        BufferedReader brClient = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
        String client = brClient.readLine(); // 阻塞
        System.out.println(client);

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




public class UploadServer {
    public static void main(String[] args) throws IOException {
        // 創建服務器端的Socket對象
        ServerSocket ss = new ServerSocket(11111);

        // 監聽客戶端連接
        Socket s = ss.accept();// 阻塞

        // 封裝通道內的流
        BufferedReader br = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
        // 封裝文本文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));

        String line = null;
        while ((line = br.readLine()) != null) { // 阻塞
        // if("over".equals(line)){
        // break;
        // }
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 給出反饋
        BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(
                s.getOutputStream()));
        bwServer.write("文件上傳成功");
        bwServer.newLine();
        bwServer.flush();

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

 

上傳圖片案例
public class UploadServer {
    public static void main(String[] args) throws IOException {
        // 創建服務器Socket對象
        ServerSocket ss = new ServerSocket(19191);

        // 監聽客戶端連接
        Socket s = ss.accept();

        // 封裝通道內流
        BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
        // 封裝圖片文件
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("mn.jpg"));

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
            bos.flush();
        }

        // 給一個反饋
        OutputStream os = s.getOutputStream();
        os.write("圖片上傳成功".getBytes());

        bos.close();
        s.close();
    }
}




    public static void main(String[] args) throws IOException {
        // 創建客戶端Socket對象
        Socket s = new Socket("192.168.12.92", 19191);

        // 封裝圖片文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                "林青霞.jpg"));
        // 封裝通道內的流
        BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
            bos.flush();
        }

        s.shutdownOutput();

        // 讀取反饋
        InputStream is = s.getInputStream();
        byte[] bys2 = new byte[1024];
        int len2 = is.read(bys2);
        String client = new String(bys2, 0, len2);
        System.out.println(client);

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

 

服務器的代碼用線程進行封裝,這樣可以模擬一個同時接收多人上傳文件的服務器。(用循環也可以但是效率低,是單線程的程序)
public class UploadClient {
    public static void main(String[] args) throws IOException {
        // 創建客戶端Socket對象
        Socket s = new Socket("192.168.12.92", 11111);

        // 封裝文本文件
        // BufferedReader br = new BufferedReader(new FileReader(
        // "InetAddressDemo.java"));
        BufferedReader br = new BufferedReader(new FileReader(
                "ReceiveDemo.java"));
        // 封裝通道內流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                s.getOutputStream()));

        String line = null;
        while ((line = br.readLine()) != null) { // 阻塞
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // Socket提供了一個終止,它會通知服務器你別等了,我沒有數據過來了
        s.shutdownOutput();

        // 接收反饋
        BufferedReader brClient = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
        String client = brClient.readLine(); // 阻塞
        System.out.println(client);

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





public class UserThread implements Runnable {
    private Socket s;

    public UserThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            // 封裝通道內的流
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));
            // 封裝文本文件
            // BufferedWriter bw = new BufferedWriter(new
            // FileWriter("Copy.java"));

            // 為了防止名稱沖突
            String newName = System.currentTimeMillis() + ".java";
            BufferedWriter bw = new BufferedWriter(new FileWriter(newName));

            String line = null;
            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();
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}



public class UploadServer {
    public static void main(String[] args) throws IOException {
        // 創建服務器Socket對象
        ServerSocket ss = new ServerSocket(11111);

        while (true) {
            Socket s = ss.accept();
            new Thread(new UserThread(s)).start();
        }
    }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved