java核心技術卷 -- 網絡編程

1.4因特網地址

       是用一串數字表示的主機地址,一個因特網地址是由4個字節組成,如果需要在主機名和因特網地址之間進行轉換,就需要使用InetAddress類
       只要主機操作系統支持IPV6格式的因特網地址,java.net包也支持
       靜態的getByName方法可以返回代表某個主機的InteAddress地址。
       可以通過調用getAllByName方法來獲取所有主機
InetAdddress

package socket;

import java.net.InetAddress;

public class InetAddressTest {
    public static void main(String[] args)throws Exception{
        if(args.length > 0){
            String host = args[0];
            InetAddress[] addresses = InetAddress.getAllByName(host);
            for(InetAddress a : addresses){
                System.out.println(a);
            }
        }
        else{
            InetAddress localHostAddress = InetAddress.getLocalHost();
            System.out.println(localHostAddress);
        }
    }
}

2.1服務器套接字

       一旦啓動了服務器程序,它便會等待某個客戶端連接它的接口。
       每一個服務器程序,比如一個HTTP Web服務器,都會不間斷地執行這個循環
1.通過輸入數據流從客戶端接受一個命令(“get me this information”)
2.解碼這個客戶端命令
3.手機客戶端所請求的命令
4.通過輸出數據流發送信息給客戶端

package socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class EchoServer {
    public static void main(String[] args)throws Exception{
        //建立套接字
        try(ServerSocket s = new ServerSocket(8189)) {

            //用於建立一個負責監控端口8189的服務器,等待連接,該方法阻塞知道當前對象建立連接爲止
            try(Socket incoming = s.accept()) {
                InputStream inStream = incoming.getInputStream();
                OutputStream outStream = incoming.getOutputStream();

                try(Scanner in = new Scanner(inStream,"UTF-8")) {
                    PrintWriter out = new PrintWriter(new OutputStreamWriter(outStream, "UTF-8"),true);
                    out.println("Hello, Enter BYE to exit");
                    boolean done = false;
                    while (!done && in.hasNextLine())
                    {
                        String line = in.nextLine();
                        out.println("Echo"+ line);
                        if(line.trim().equals("BYE")) done = true;
                    }
                }
            }
        }
    }
}

2.2爲多個客戶端服務

       每當建立一個新的套接字連接, 也就是當調用accept(),將會啓動一個新的線程來處理服務器和該客戶端之間的連接,而主程序將立即返回並等待下一個連接,
操作步驟
1.編譯和運行服務器程序
2.打開數個telnet窗口 cmd -> telnet localhost 8189
3.在這些窗口之間切換,並鍵入命令,注意你可以同時通過這些窗口進行通信
4.當完成之後,切換到你啓動服務器程序的窗口,並使用CTRL+C強行關閉

package socket;

import javax.sound.midi.Soundbank;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ThreadedEchoServer {
    public static void main(String[] args){
        try(ServerSocket s = new ServerSocket(8189)) {
            int i=1;
            while(true){
                Socket incoming = s.accept();
                System.out.println("Spawning" + i);
                Runnable r = new ThreadedEchoHandler(incoming);
                Thread t = new Thread(r);
                t.start();
                i++;
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }
    }

   static  class ThreadedEchoHandler implements Runnable{
        private Socket incoming;

        public ThreadedEchoHandler(Socket incomingSocket){
            incoming = incomingSocket;
        }

        public void run(){
            try(InputStream inStream = incoming.getInputStream();
                OutputStream outStream =  incoming.getOutputStream()) {
                Scanner in = new Scanner(inStream,"UTF-8");
                PrintWriter out = new PrintWriter(new OutputStreamWriter(outStream,"UTF-8"),true);
                out.println("HELLO! ENTER BYE to exit");
                boolean done = false;
                while (!done && in.hasNextLine())
                {
                    String line = in.nextLine();
                    out.println("Echo"+ line);
                    if(line.trim().equals("BYE")) done = true;
                }
            }
            catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

2.3半關閉

       套接字連接的一端可以終止其輸出,同時仍舊可以接收來自另一端的數據
       服務器端將讀取輸入信息,直至到達輸入流的結尾,然後在發送響應
       該協議只適用於一站式的服務,例如http服務,在這種服務中,客戶端連接服務器,發送一個請求,捕獲響應信息,然後斷開連接。
       Void shutdownOutput() 將輸出流設置爲”流結束”
       Void shutdownInput() 輸入流
       Boolean isOutputShutdown() 如果輸出已被關閉,則返回true
       Boolean isInputShutdown() 輸入被關閉,返回true

3.0可中斷套接字

       當連接到一個套接字時,當前線程將會被阻塞直到建立連接或者超時爲止,同樣,當通過套接字讀取數據時,當前線程也會被阻塞直到操作成功或產生超時爲止。
       爲了中斷套接字操作,可以使用java.nio包提供的socketChannel類。
       通道並沒有與之相關聯的流,實際上,所擁有的的read和write方法都是通過Buffer對象實現的。
       如果不想處理緩衝區,可以使用Scanner類從SocketChannel中讀取信息,因爲Scanner有一個帶ReadableByteChannel參數的構造器。

4.1URL和URI

       URL 和URLConnection類封裝了大量複雜的實現細節,例如,可以自一個字符串構建一個URL對象
URL url = new URL(urlString);
       只想獲取該資源的內容,可以使用URL類中的openStream方法。
       URI是個純粹的語法結構,包含用來指定web資源的字符串的各種組成部分,URL是URI的一個特例,包含了用於定位WEB 資源的足夠信息。
       在java類庫中,URI類並不包括任何用於訪問資源的方法,它的唯一作用是解析。
       URI類的另一個作用是處理絕對標誌符和相對標識符。

4.2使用URLConnection獲取信息

       當操作URLConnection對象時,應該小心的安排操作步驟
1.調用URL類中的openConnection方法獲得URLConnection對象
URLConnection connection = url.openConnection()
2.使用以下方法設置任意的請求屬性
setDoInput
setDoOutput //想獲得輸出流,需要調用
setIfModifyedSince //用於告訴連接你只對自某個特定時期以來被修改的時間
setUseCaches //用於命令瀏覽器首先檢查它的緩存
setAllowUserInteraction //用於在訪問有密碼保護的資源時彈出對話框
setRequestProperty //設置對特定協議起作用的任何“名-值(name/value)對”
setConnectTimeout
setReadTimeout

3.調用connect方法連接遠程資源
Connection.connect();
4.與服務器建立連接後,可以查詢頭信息
5.訪問資源數據

package socket;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class URLconnectionTest {
    public static void main(String[] args){
        try {
            String urlName;
            if(args.length > 0) urlName = args[0];
            else urlName = "http://horstmann.com";

            URL url = new URL(urlName);
            URLConnection connection = url.openConnection();

            if(args.length>2){
                String username = args[1];
                String password = args[2];
                String input = username + ":" + password;
                Base64.Encoder encoder = Base64.getEncoder();
                String encoding = encoder.encodeToString(input.getBytes(StandardCharsets.UTF_8));
                connection.setRequestProperty("Authorization","Basic"+encoding);
            }
            connection.connect();
            Map<String, List<String>> headers = connection.getHeaderFields();
            for(Map.Entry<String,List<String>> entry : headers.entrySet()){
                String key = entry.getKey();
                for(String value:entry.getValue())
                    System.out.println(key+":"+ value);
            }
            System.out.println("----------");
            System.out.println("getContentType: " + connection.getContentType());
            System.out.println("getContentLength: " + connection.getContentLength());
            System.out.println("getContentEncoding: " + connection.getContentEncoding());
            System.out.println("getDate: " + connection.getDate());
            System.out.println("getExpiration: " + connection.getExpiration());
            System.out.println("getLastModifed: " + connection.getLastModified());
            System.out.println("----------");

            String encoding = connection.getContentEncoding();
            if (encoding == null) encoding = "UTF-8";
            try (Scanner in = new Scanner(connection.getInputStream(), encoding))
            {
                // print first ten lines of contents

                for (int n = 1; in.hasNextLine() && n <= 10; n++)
                    System.out.println(in.nextLine());
                if (in.hasNextLine()) System.out.println(". . .");
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

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