首頁  >  文章  >  Java  >  Java網路程式設計由淺入深一圖文詳解

Java網路程式設計由淺入深一圖文詳解

黄舟
黄舟原創
2017-03-04 10:04:442694瀏覽

本文介紹網路相關理論和簡單入門的Java網路程式設計範例

#這篇文章主要介紹電腦網路的一個整體架構和每一層的作用。

  • 電腦網路的概念

  • #OSI參考模型

  • #TCP/IP參考模型

  • #IP協定

  • TCP協定與連接埠

  • Java網路程式入門程式


計算機網路的概念

網絡,就是不同節點之間經由連線互聯起來的一個事物。以此類推,電腦網絡,就是將不同地理位置的電腦透過通訊線路連接起來的一個具有強大功能的網路系統。在這個網路中每台電腦就是一個節點。

OSI參考模型

OSI(Open System Interconnection)是由ISO組織研究的一套網路體系結構。這名字起的好
各層的名稱和作用,當做了解:

#功能
物理層 不要理解錯了,這一層不包含什麼網路線、電纜的實體媒體。這裡只是規定網路線和電纜的介面類型,訊號電壓等。使用bit傳輸
資料鏈結層 負責兩個相鄰節點間的路線,以訊框為單位傳輸。典型設備交換器(Switch)
網路層 兩台電腦傳輸資料可能會經過許多資料鏈路,網路層的作用就是選擇最優的路線。典型設備就是路由器
傳輸層 提供兩個端系統的會話的建立、維護和取消傳輸連線的功能。使用封包傳輸
會話層 管理進程間的會話過程,也就是建立、管理、終止進程間的會話。使用封包傳輸
表示層 對資料的加解密、解壓縮和格式轉換等。
應用層 這層就是和使用者的具體應用互動。例如:收發E-mail等。

TCP/IP參考模型

因為OSI網路結構分層太多過於複雜,所以TCP/IP協定橫空出世。 TCP/IP協定同樣借助了OSI的分層思想,但只是分成四層:

主機網路層為上層提供一個存取介面網路互聯層把IP數據包發送到目標主機。這一層使用的是IP協議,IP協議規定了資料包的格式,並且規定了為資料包尋找路由的流程。 傳輸層使來源主機和目標主機的程序可以進行會話。這一層定義了兩種協定TCP和UDP協定。 應用層TCP/IP模型將OSI參考模型中的會話層和表現層功能合併到應用層。
#功能
#########

基於TCP協定的應用主要有以下幾種:

•   FTP:檔案傳輸協議,允許在網路上傳輸檔案。
•   TELNET:虛擬終端協議,允許從主機A登錄遠端主機B。
•   HTTP:超文本傳輸協議,允許網路是傳輸超文本。
•   HTTPS:安全超文本傳輸協定。
•   POP3:允許使用者存取和操作運程伺服器上的郵件和郵件夾。
•   IMAP4:訊息存取協定版本4,允許使用者存取和操作運送伺服器上的郵件和郵件夾。
•   SMTP:發送郵件的協定。

基於UDP協定的應用層協定:

•   SNMP:簡單網路管理協議,為管理本地和遠端的網路設備提供了一個標準化途徑,是分佈式環境中的集中化管理協定。
•   DNS:網域名稱系統協議,將主機的網域轉換為對應的IP位址。

IP協定

IP網路(採用IP協定的網路)中每一台主機都有唯一的IP位址,IP位址識別網路中的每個主機。 IP位址是一個32位元的二進位數序列。例如:192.168.3.4。 IP位址與子網路遮罩進行與運算得到的是網路位址。如果子網路遮罩為255.255.255.0 那網路位址就是:192.168.3.0

##傳送封包的程序

#IP是面向包的協議,即資料被分成若干小資料包,然後分別傳輸它們。 IP網路上的主機只能直接傳送封包至本地網路上的其他主機(也就是具有相通IP網址的主機)。主機實際上具有兩個不同性質的真實位址。主機A向同一個網路上的另一個主機B發包時,會透過位址解析協定(ARP,Address Resolution Protocol)取得對法的實體位址,然後把包給對方。 ARP協定的運作機制為,主機A在網路上廣播一個ARP訊息:”要找位址為192.166.3.5的主機”,具有這個IP位址的主機B就會作回應,把自身的實體位址告訴A。

當主機A傳送封包給另一個網路的主機B:

主機A利用ARP協定找到本地網路上的路由器的實體位址,把封包轉給路由。路由器依照下列步驟處理封包:

  1. 如果封包的生命週期已到,則封包被拋棄。

  2. 搜尋路由表,優先搜尋路由表中的主機,如果找到具有目標IP位址的主機,則將封包傳送給該主機。

  3. 如果符合主機失敗,則繼續搜尋路由表,符合子網路的路由表,如果找到符合的路由表,則將封包轉送給該路由器。

  4. 如果符合同子網路的路由器失敗,則繼續搜尋路由表,符合相同網路的路由器,如果找到符合的路由器,則將封包轉送給該路由器。

  5. 如果以上匹配都失敗,就搜尋預設路由,如果預設路由存在,則按照預設路由發送資料包,否則丟棄資料包。

    流程圖如下:

    Java網路程式設計由淺入深一圖文詳解

網域

IP是一串數字沒有任何意義。網域名稱就是與IP對應的有意義的一串字元或數字。例如:

www.google.com 網域和IP的對應需要一個網域解析系統來實現將網域轉換成IP。 DNS伺服器就是就可以解決這個問題。

URL(統一資源定位器)

URL(Uniform Resource Location)是一種專門識別網路上資源位置而設定的一種編址方式。 URL一般由3個部分組成:

应用层协议://主机IP地址或域名/资源所在路径/资源名

例如:

http://www.php.cn/ 其中http 指超文本傳輸協議, blog.csdn.net 是Web伺服器的域名,/article/details/ 是網頁所在路徑,54962975 這個才是對應的網頁檔案。

TCP協定和連接埠

IP協定在傳送資料時,在資料傳輸過程中會出現各種問題。導致包遺失或包的順序不對。 TCP協定使兩台主機上的進程順利通信,不必擔心包遺失或包順序不對。 TCP追蹤包順序,如果包順序被搞亂時按照正確的順序進行重新組合。如果包遺失,則TCP會請求來源主機重發包。

連接埠

TCP協定讓兩台主機上的行程順利通信,但是主機不只一個行程。 TCP就採取連接埠來區分進程。連接埠不是實體設備,而是用來標識進程的邏輯位址。電腦的連接埠範圍是0到65535,其中0到1023的連接埠一般固定分配給一些服務。具體如下:

服务 端口 协议
文件传输服务 21 FTP
远程登录服务 23 TELENET
邮件传输服务 25 SMTP
万维网超文本传输服务 80 HTTP
访问邮件远程邮件服务 110 POP3
互联网消息存取服务 143 IMAP4
安全的超文本传输服务 443 HTTPS
安全的远程登录服务 992 TELNETS
安全互联网消息存取服务 993 IMAPS

Java网络编程入门程序

Java网络程序都建立在TCP/IP协议基础上,在应用层实现。传输层向应用层提供了套接字Socket接口,Socket封装了下层的数据传细节,应用层的程序通过Socket来建立与远程主机的连接,以及数据传输,如下图所示:
Java網路程式設計由淺入深一圖文詳解

在Java中,有3种套接字类:java.net.Socketjava.net.ServerSocketjava.net.DatagramSocket 。其中SocketServerSocket 建立在TCP协议上,DatagramSocket 类建立在UDP协议基础上。我们创建EchoServer和EchoClient两个类,我们通过ServerSocketSocket来编写。

创建EchoServer类

在服务端通过一直监听端口,来接收客户程序的连接请求。在服务器程序中,先创建一个ServerSocket对象,在构造方法中指定监听的端口:

ServerSocket server = new ServerSocket(8080);

ServerSocket构造器负责在操作系统中将当前进程注册为服务进程。服务器程序调用ServerSocketaccept()方法来监听端口,等待客户端的连接,如果接收到连接,则accept()方法返回一个Socket对象,这个Socket对象与客户端的Socket对象形成了一条通信线路:

Socket socket = server.accept();

Socket提供了getInputStream()方法和getOutputStream()方法,分别返回输入流InputStream对象和输出流OutputStream对象。程序只需向输出流写入东西,就能向对方发送数据;只需从输入流读取数据,就能接收到数据。如下图:
Java網路程式設計由淺入深一圖文詳解
EchoServer 类代码如下:

/**
 * 服务端 服务端类
 *
 */public class EchoServer {


    private ServerSocket serverSocket;    
    public EchoServer(int port) {        
    try {            this.serverSocket = new ServerSocket(port);
            System.out.println("start server success,start port:"+port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }    /**
     * 获取BufferedReader包装类
     * 
     * @param socket
     * @return
     * @throws IOException
     */
    private BufferedReader getReader(Socket socket) throws IOException {        
    return new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }    /**
     * 获取PrintWriter包装类,
     * 
     * @param socket
     * @return
     * @throws IOException
     */
    private PrintWriter getWriter(Socket socket) throws IOException {        
    // 每写一行自动刷新
        return new PrintWriter(socket.getOutputStream(), true);
    }    public void service() {        while (true) {
            Socket socket = null;            try {
                socket = serverSocket.accept();
                System.out.println("new connect,address is:" + socket.getInetAddress() + " port is:" + socket.getPort());
                BufferedReader reader = getReader(socket);
                PrintWriter writer = getWriter(socket);
                String msg = null;                
                while ((msg = reader.readLine()) != null) {                    
                // 读取一行
                    System.out.println("client request  msg: " + msg);
                    writer.println(echo(msg));                    
                    if ("bye".equalsIgnoreCase(msg)) {                        
                    break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally{                
            if(socket!=null){                    
            try {                        
            //关闭会话连接
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }    private String echo(String msg) {        return "get request msg is '" + msg+"'";
    }    public static void main(String[] args) {        new EchoServer(8080).service();
    }
}

EchoServer类的最主要的方法就是service()方法,它不断登录客户的连接请求。当serverSocket.accept()返回一个Socket对象时,表示与一个客户端建立了连接。

创建EchoClient

在EchoClient程序中,为了与EchoClient通信,需要先创建一个Socket对象:

String host="localhost";int port = 8080;new Socket(host, port);

host表示Server进程所在服务器的地址,port表示Server进程监听的端口。当参数host为’localhost’时,表示服务端和客户端在同一台机器上。下面是EchoClient类的源码:

public class EchoClient {
    private Socket socket;    
    public EchoClient(String host,int port){        
    try {            this.socket = new Socket(host, port);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }    /**
     * 获取BufferedReader包装类
     * 
     * @param socket
     * @return
     * @throws IOException
     */
    private BufferedReader getReader(Socket socket) throws IOException {        
    return new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }    /**
     * 获取PrintWriter包装类,
     * 
     * @param socket
     * @return
     * @throws IOException
     */
    private PrintWriter getWriter(Socket socket) throws IOException {        
    // 每写一行自动刷新
        return new PrintWriter(socket.getOutputStream(), true);
    }    public void talk(){        try {
            BufferedReader reader = getReader(socket);
            PrintWriter writer = getWriter(socket);
            BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
            String msg = null;            
            while((msg=localReader.readLine())!=null){
                writer.println(msg);
                System.out.println("server response msg:"+reader.readLine());                
                if("bye".equalsIgnoreCase(msg)){                    
                break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{            
        if(socket!=null){                
        try {
                    socket.close();
                    System.out.println("has been disconnected");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }    public static void main(String[] args) {        
    new EchoClient("localhost", 8080).talk();
    }
}

在EchoClient类中最重要的是talk()方法,该方法不断读取用户从控制台输入的字符串,然后将它发送到EchoServer,在把EchoServer返回的数据打印在控制台。如果输入’bye’字符串,就会结束与EchoServer的通信,调用socket.close()方法端口连接。
具体运行如下图,一个是服务端一个是客户端的控制台:
Java網路程式設計由淺入深一圖文詳解

总结

简单介绍了一下网络的理论知识和TCP/IP协议。并使用Java实现了一个网络通信程序。

 以上就是Java网络编程由浅入深一图文详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn