網絡編程、Socket、ServerSocket

一、網絡編程
    1.軟件結構
        CS結構:Client/Server   客戶端和服務端獨立
        BS結構:Browser/Server  瀏覽器和服務端獨立

    2.網絡通信
        網絡通信協議指的就是多個計算機之間如果想實現通信,就必須遵守一定的規則

    3.TCP協議和UDP協議
        UDP協議:面向無連接。不區分客戶端和服務端的。發送數據效率快,但是數據不安全!而且有大小限制64KB
        TCP協議:面向有連接。區分客戶端和服務端的。發送數據效率較慢。但是數據安全!沒有大小限制

    4.網絡通信三要素
        IP地址:每一臺電腦的唯一標示
        端口號:是每一個軟件的標識,範圍:0--65535    常用的軟件端口號:網絡端口號80   MySQL3306   oracle1521   tomcat8080
        通信協議:TCP協議和UDP協議
    4.文件上傳步驟
        客戶端:
            a.首先創建Socket對象,指定IP與端口
            b.創建一個本地輸入流(讀取文件),再創建一個網絡輸出流(通過Socket對象getOutputStream)
            c.通過本地讀取流循環讀取並寫入到網絡輸出流中
            d.一定要給服務器一個結束的標記    void shutdownOutput() 禁用此套接字的輸出流。
        服務器端:
            a.首先創建ServerSocket對象,指定IP端口
            b.通過上面的對象調用accept()方法返回一個Socket對象
            c.創建一個文件對象,指定文件客戶端上傳到的儲存路徑(爲了代碼的健壯性,建議對文件做一個判斷是否存在)
            d.創建一個網絡輸入流(通過前面返回的Socket對象getInputStream),創建一個本地輸出流(將網絡輸出流裏面讀取的數據寫入到本地)
            e.在通過Socket對象創建一個網絡輸出流(getOutputStream),寫一個提示反饋給客戶端write("傳輸成功".getBytes)
        注意事項:
            客戶端需要關閉   Socket對象和本地輸入流
            服務器端需要關閉 ServerSocket對象



    5.TCP協議的客戶端代碼實現
        public class TCPClient {
            public static void main(String[] args) throws IOException{
                Socket s = new Socket("127.0.0.1",10086);

                Scanner sc = new Scanner(System.in);

                while(true) {
                    //獲取輸出流對象
                    OutputStream os = s.getOutputStream();
                    //寫出數據
                    System.out.println("請輸入給服務端發送的消息:");
                    String str = sc.nextLine();
                    os.write(str.getBytes());

                    //接收服務端發送過來的消息
                    //獲取輸入流對象
                    InputStream is = s.getInputStream();
                    byte[] arr = new byte[2048];
                    int len =is.read(arr);
                    System.out.println("從服務端接收到的消息是:");
                    System.out.println(new String(arr,0,len));

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

    6.TCP協議的服務端代碼實現
        public class TCPServer {
            public static void main(String[] args) throws IOException{
                ServerSocket ss = new ServerSocket(10086);
                Scanner sc = new Scanner(System.in);

                //獲取服務端的Socket對象
                Socket s = ss.accept();

                while(true) {
                    //獲取輸入流對象
                    InputStream is = s.getInputStream();
                    byte[] arr = new byte[2048];
                    int len = is.read(arr);
                    System.out.println("從客戶端接收到的消息是:");
                    System.out.println(new String(arr,0,len));

                    //給客戶端回覆消息
                    //獲取輸出流對象
                    OutputStream os = s.getOutputStream();
                    System.out.println("請輸入給客戶端發送的消息:");
                    String str = sc.nextLine();
                    os.write(str.getBytes());
                }

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


    7.操作TCP協議的常見異常
        ConnectException
            出現原因:沒有開啓服務端。
            解決方式:先開啓服務端,然後再開啓客戶端

        BindException
            出現原因:使用了已經被佔用的端口號
            解決方式:換一個沒有被佔用的端口號

    8.文件上傳案例-客戶端代碼
        public class TCPClient {
            public static void main(String[] args) throws IOException {
                //1.創建一個本地字節輸入流FileInputStream對象,構造方法中綁定要讀取的數據源
                FileInputStream fis = new FileInputStream("c:\\1.jpg");
                //2.創建一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號
                Socket socket = new Socket("127.0.0.1",8888);
                //3.使用Socket中的方法getOutputStream,獲取網絡字節輸出流OutputStream對象
                OutputStream os = socket.getOutputStream();
                //4.使用本地字節輸入流FileInputStream對象中的方法read,讀取本地文件
                int len = 0;
                byte[] bytes = new byte[1024];
                while((len = fis.read(bytes))!=-1){
                    //5.使用網絡字節輸出流OutputStream對象中的方法write,把讀取到的文件上傳到服務器
                    os.write(bytes,0,len);
                }

                /*
                    解決:上傳完文件,給服務器寫一個結束標記
                    void shutdownOutput() 禁用此套接字的輸出流。
                    對於 TCP 套接字,任何以前寫入的數據都將被髮送,並且後跟 TCP 的正常連接終止序列。
                 */
                socket.shutdownOutput();

                //6.使用Socket中的方法getInputStream,獲取網絡字節輸入流InputStream對象
                InputStream is = socket.getInputStream();

                //7.使用網絡字節輸入流InputStream對象中的方法read讀取服務回寫的數據
                while((len = is.read(bytes))!=-1){
                    System.out.println(new String(bytes,0,len));
                }

                //8.釋放資源(FileInputStream,Socket)
                fis.close();
                socket.close();
            }
        }

    9.文件上傳案例-服務端代碼
        public class TCPServer {
            public static void main(String[] args) throws IOException {
                //1.創建一個服務器ServerSocket對象,和系統要指定的端口號
                ServerSocket server = new ServerSocket(8888);
                //2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端Socket對象

                //4.判斷d:\\upload文件夾是否存在,不存在則創建
                File file =  new File("d:\\upload");
                if(!file.exists()){
                    file.mkdirs();
                }

                /*
                    讓服務器一直處於監聽狀態(死循環accept方法)
                    有一個客戶端上傳文件,就保存一個文件
                 */
                while(true){
                    Socket socket = server.accept();

                    /*
                        使用多線程技術,提高程序的效率
                        有一個客戶端上傳文件,就開啓一個線程,完成文件的上傳
                     */
                    new Thread(new Runnable() {
                        //完成文件的上傳
                        @Override
                        public void run() {
                           try {
                               //3.使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象
                               InputStream is = socket.getInputStream();

                            /*
                                自定義一個文件的命名規則:防止同名的文件被覆蓋
                                規則:域名+毫秒值+隨機數
                             */
                               String fileName = "itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";

                               //5.創建一個本地字節輸出流FileOutputStream對象,構造方法中綁定要輸出的目的地
                               //FileOutputStream fos = new FileOutputStream(file+"\\1.jpg");
                               FileOutputStream fos = new FileOutputStream(file+"\\"+fileName);
                               //6.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端上傳的文件


                               int len =0;
                               byte[] bytes = new byte[1024];
                               while((len = is.read(bytes))!=-1){
                                   //7.使用本地字節輸出流FileOutputStream對象中的方法write,把讀取到的文件保存到服務器的硬盤上
                                   fos.write(bytes,0,len);
                               }


                               //8.使用Socket對象中的方法getOutputStream,獲取到網絡字節輸出流OutputStream對象
                               //9.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫"上傳成功"
                               socket.getOutputStream().write("上傳成功".getBytes());
                               //10.釋放資源(FileOutputStream,Socket,ServerSocket)
                               fos.close();
                               socket.close();
                           }catch (IOException e){
                               System.out.println(e);
                           }
                        }
                    }).start();


                }

                //服務器就不用關閉
                //server.close();
            }
        }

        文本文件上傳
        public class TCPClient {
            public static void main(String[] args) throws IOException {

                Socket socket = new Socket("127.0.0.1", 520);
                //創建一個本地讀取流,因爲是txt文件,所以使用高效字符流,txt文件是在windows創建的,默認爲GBK格式
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("f:\\Test\\1.txt"),"GBK"));
                //創建一個網絡輸出流,也是用高效輸出流
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"GBK"));
                String line;
                while ((line = br.readLine()) != null) {
                    bw.write(line);
                    bw.newLine();
                    bw.flush();
                }
                br.close();
                //給個結束標記
                socket.shutdownOutput();

            }
        }
        public class TCPServer {
            public static void main(String[] args) throws IOException {
                ServerSocket server = new ServerSocket(520);
                //創建一個網絡讀取流   需要用到轉換 流
                BufferedReader br = new BufferedReader(new InputStreamReader(server.accept().getInputStream(),"GBK"));
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("f:\\Test\\22.txt"),"GBK"));
                String line;
                while ((line = br.readLine()) != null) {
                    bw.write(line);
                    bw.flush();
                }
                br.close();

                server.close();
            }
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章