10 - JavaSE之網絡編程

網絡編程java

網絡通訊協議分層思想編程

爲何要分層呢?由於整個網絡協議很是複雜,要涉及到方方面面的知識,並且還有對底層硬件的操做,利用分層的思想,咱們能夠將複雜的通訊協議分割成一層層的形式,上一層能夠調用下一層,而與再下一層不發生關係,各層之間互不影響,便於系統的開發。咱們把用戶程序做爲最高層,把物理通訊線路做爲最底層,高層到底層一步步封裝,咱們不須要直接操做底層,而是操做最簡單的最高層,這就是分層的意義。服務器


參考模型網絡

  1. OSI七層模型

物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層socket

  1. TCP/IP參考模型

應用層、傳輸層(TCP/UDP層)、網絡層(IP層)、數據鏈路層、物理層.net

咱們今天要講的主要是傳輸層。3d


IP協議code

IP層:給咱們作的最大貢獻就是提供了獨一無二的IP地址。server

IP TCP UDP 網關 內網 子網掩碼對象

  • TCP
  1. TCP是Transfer Control Protocol(傳輸控制協議)的簡稱,是一種面向鏈接的保證可靠傳輸的協議。一個TCP鏈接必需要通過三次「對話」才能創建起來。
  2. 在TCP/IP協議中,IP層主要負責網絡主機的定位,數據傳輸的路由,由IP地址能夠惟一肯定Internet上的一臺主機。而TCP層則提供面向應用的可靠的或非可靠的數據傳輸機制,這是網絡編程的主要對象,通常不須要關心IP層是如何處理數據的。
  3. 發送方和接收方的成對的兩個socket之間必須創建鏈接,以便在TCP協議的基礎上進行通訊。當一個socket(一般都是serversocket)等待創建鏈接時,另外一個socket能夠要求進行鏈接,一旦這兩個socket鏈接起來,它們就能夠進行雙向數據傳輸,雙方均可以進行發送或接收操做。
  • UDP

UDP是User Datagram Protocol的簡稱,是一種無鏈接的協議。UDP是從一臺計算機向另外一臺計算機發送稱爲數據報的獨立數據包的協議,該協議並不保證數據報是否能正確地到達目的地,它是一個非面向鏈接的協議。每一個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,所以可否到達目的地,到達時間以及內容的正確性都是不能保證的。

  • TCP和UDP的比較
  1. 使用UDP時,每一個數據報中都給出了完整的地址信息,所以無需創建發送方和接收方的鏈接。對於TCP協議,因爲它是一個面向鏈接的協議,在socket之間進行數據傳輸以前必然要創建鏈接,因此在TCP中多了一個鏈接創建的時間。
  2. 使用UDP傳輸數據時是有大小限制的,每一個被傳輸的數據報必須限定在64KB以內。TCP沒有這方面的限制,一旦鏈接創建起來,雙方的socket就能夠按統一的格式傳輸大量的數據。
  3. UDP是一個不可靠的協議,發送方所發送的數據報並不必定以相同的次序到達接收方;TCP是一個可靠的協議,它確保接收方徹底正確地獲取發送方所發送的所有數據。
  4. 可靠的傳輸是要付出代價的,對數據內容正確性的檢驗必然佔用計算機的處理時間和網絡的帶寬。所以TCP傳輸的效率不如UDP高。
  5. TCP在網路通訊上有極強的生命力,例如遠程鏈接(Telnet)和文件傳輸(FTP)都須要不定長度的數據被可靠地傳輸。相比之下UDP操做簡單,並且僅須要較少的監護,所以一般用於局域網高可靠性的分散系統中client/server應用程序。
  • Socket
  1. 兩個 Java 應用程序能夠經過一個雙向的網絡通訊鏈接實現數據交換,這個雙向鏈路的一端稱爲一個Socket。
  2. Socket 一般用來實現 client-server 鏈接。
  3. java.net 包中定義的兩個類 Socket 和 ServerSocket ,分別用來實現雙向鏈接的 client 和 server 端。
  4. 創建鏈接時所需的尋址信息爲遠程計算機的 IP 地址和端口號(Port)

端口:用於區分不一樣的網絡應用程序 ,佔兩個字節,因此共有 65535 個端口號。不過系統會隨時徵用 1024 如下端口。

端口又分TCP和UDP端口,各有 65535 個端口。


TCP Socket 通訊模型

示例1:最簡單的Socket模型:Client寫數據務器讀數據

// Server
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(6666); // 已經開始監聽6666端口了      
        while(true) {
            Socket s = ss.accept(); // ss創建一個插座Socket,接受和客戶端s的鏈接(阻塞式鏈接),鏈接成功,至關於服務器和客戶端之間鏈接了兩根管道。讀的管道(InputStream)和寫的管道(OutputStream)。
            System.out.println("A Client has Connected!");
            DataInputStream dis = new DataInputStream(s.getInputStream());
            System.out.println(dis.readUTF());// 因此先獲取管道,要說就獲取寫的管道,要聽就獲取讀的管道。
            dis.close();
            s.close();
        }
    }
}

// Client
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("127.0.0.1", 6666);// 申請和ss創建鏈接   
        DataOutputStream dos = new DataOutputStream(s.getOutputStream());       
        dos.writeUTF("Hello TCP."); // 鏈接好以後開始說話,經過管道流的方式來講話,因此先獲取管道,要說就獲取寫的管道,要聽就獲取讀的管道。   
        dos.flush();
        dos.close();
        s.close();
    }
}

Client 端的 IP 地址不能隨意指定,不知爲什麼。

示例2:服務器向客戶端發送數據,客戶端接收數據

// Server
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(6666);       
            while(true) {
                Socket s = ss.accept();
                System.out.println("A Client has Connected!");
                DataOutputStream dos = new DataOutputStream(s.getOutputStream());
                dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I'm Server.");
                dos.close();
                s.close();
            }
        } catch (IOException e) {
            System.out.println("Server Error!!!");
            e.printStackTrace();
        }
    }
}

// Client
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) {
        try {
            Socket s = new Socket("127.0.0.1", 6666);       
            DataInputStream dis = new DataInputStream(s.getInputStream());      
            System.out.println(dis.readUTF());  
            dis.close();
            s.close();
        } catch(IOException e) {
            System.out.println("Client Error!!!");
            e.printStackTrace();
        }
    }
}
//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15944], I'm Server.

//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15953], I'm Server.

//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15954], I'm Server.

//I:\Java\Demo>java Client
//Hi [#IP:/127.0.0.1 #Port:15955], I'm Server.

示例3:服務器和客戶端同時讀寫數據(固然一個先讀一個先寫嘍,若是兩個都讀或都寫的話就卡死啦)

// Server
// 服務器先接收客戶端的數據,而後再發送數據給客戶端
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(6666);
            Socket s = ss.accept();
            
            System.out.println("A Client has Connected!");
            
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            
            String str = null;
            if((str=dis.readUTF()) != null)
            {
                System.out.println("I'm reseaving message...");
                Thread.sleep(3000);
                dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I hava reseaved: " + str);
            }
            
            dis.close();
            dos.close();
            s.close();
        } catch (IOException e) {
            System.out.println("Server Error!!!");
            e.printStackTrace();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


// Client
// 客戶端先發送數據給服務器,再接收服務器的回覆。
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) {
        try {
            Socket s = new Socket("localhost", 6666);
            
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            
            System.out.println("Hi Server, I'm sending message to you...");
            
            Thread.sleep(2000);
            
            dos.writeUTF("Hello HYJ.");
            System.out.println(dis.readUTF());
            
            dis.close();
            s.close();
        } catch(UnknownHostException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

注意:這裏面使用的是 Socket s = new Socket("localhost", 6666);

最後要 catch(UnknownHostException e),UnknownHostException 小於 IOException 因此要放前面。


UDP 通訊模型

示例:

// UDPServer 接收並打印來自客戶端的數據
import java.net.*;
import java.io.*;

public class UDPServer {
    public static void main(String[] args) {
        try {
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            DatagramSocket ds = new DatagramSocket(8888);
            while(true) {
                ds.receive(dp);
                //ByteArrayInputStream bais = new ByteArrayInputStream(buf);
                //DataInputStream dis = new DataInputStream(bais);
                //System.out.println("UDPClient: " + dis.readUTF());
               System.out.println("UDPClient: " + new String(buf, 0, dp.getLength()));
            }           
        } catch (IOException e) {
            System.out.println("UDPServer Error!!!");
            e.printStackTrace();
        }
    }
}


// UDPClient 發送數據給服務器
import java.net.*;
import java.io.*;

public class UDPClient {
    public static void main(String[] args) {
        try {
            //ByteArrayOutputStream baos = new ByteArrayOutputStream();         
            //DataOutputStream dos = new DataOutputStream(baos);
            
            //dos.writeUTF("Hello HYJ!");
            //dos.flush();

            //byte[] buf = baos.toByteArray();
           byte[] buf = (new String("Hello HYJ!")).getBytes();
            System.out.println("buf.length = " + buf.length);
            
            DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress("127.0.0.1", 8888));
            DatagramSocket ds = new DatagramSocket(7777);
            
            ds.send(dp);
            ds.close();
            
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}
相關文章
相關標籤/搜索