網絡篇

1、概述 html

一、網絡架構
C/S: Client/Server

    客戶端、服務端。
特色:
   1) 須要在客戶端和服務端都須要安裝編寫的軟件。
   2) 維護較麻煩。
好處:能夠減輕服務端的壓力,如網絡遊戲。
B/S: Browser/Server
    瀏覽器  、服務端。
特色:
   1) 客戶端不用單獨編寫軟件。由於客戶端用的就是瀏覽器。
   2) 對於軟件升級,只要考慮服務端便可。
弊端:全部的程序都運行在服務端,客戶端的瀏覽器畢竟解析能力較弱。對遊戲等。

二、網絡模型:
OSI 參考模型、TCP/IP 參考模型如圖所示:


Note:網際層經常使用的協議是 TCP 或 UDP;傳輸層使用的協議是 IP;應用層使用的是HTTP 和 FTP 協議。
三、網絡通訊三要素:
IP 地址、端口號、傳輸協議(通用協議 TCP/IP)

1)IP地址:
    IP 地址 = 網絡號碼 + 主機地址
    A 類 IP 地址:第一段號碼爲網絡號碼,剩下的三段號碼爲本地計算機的號碼
    B 類 IP 地址:前二段號碼爲網絡號碼,剩下的二段號碼爲本地計算機的號碼
    C 類 IP 地址:前三段號碼爲網絡號碼,剩下的一段號碼爲本地計算機的號碼
    特殊地址:
    127.0.0.1  迴環地址,可用於測試本機的網絡是否有問題。ping 127.0.0.1
    ipconfig:  查看本機 IP 地址
    xxx.xxx.xxx.0    網絡地址
    xxx.xxx.xxx.255  廣播地址
A 類  1.0.0.1---127.255.255.254 10.X.X.X 是私有地址(私有地址就是在互聯網上不使用,而被用在局域網絡中的地址)   
Note: 127.X.X.X 是保留地址,用作循環測試用的。
B 類  128.0.0.1---191.255.255.254  172.16.0.0---172.31.255.255 是私有地址。
Note:169.254.X.X 是保留地址。

C 類  192.0.0.1---223.255.255.254  192.168.X.X 是私有地址
D 類  224.0.0.1---239.255.255.254   
E 類  240.0.0.1---247.255.255.254
InetAddress 類:沒有構造函數,封裝的是 IP 地址(具體解說請自行查看 API 文檔)
主要方法:
    static InetAddress   getLocalHost()    //返回本地主機。 
    String getCanonicalHostName()      //獲取此 IP 地址的徹底限定域名
    String getHostAddress()        //返回 IP 地址的字符串(文本形式)
    String getHostName()          //獲取此 IP 地址的主機名
    static InetAddress getByName(String Host)//獲取任意一臺主機的 IP 地址、名稱
        eg:     InetAddress ia = InetAddress.getByName("thinkpad -sl400");//參數能夠是 IP 地址
                System.out.println("address:"+ia.getHostAddress());
                System.out.println("name:"+ia.getHostName());
    static InetAddress getAllByName(String Host)    //在給定主機名的狀況下根據系統上配置的名稱服務返回其 IP 地址所組成的數組。
Note:  若是 IP 地址和對應的主機名,沒有在網絡上,那麼沒法解析主機名,將會返回該 IP 地址,有可能返回的 IP 對象不惟一。
示例以下:
import java.net.*;
class IPDemo {
	public static void main(String[] args) throws Exception {
		// 獲取本類對象
		InetAddress ia = InetAddress.getLocalHost();

		// ip
		String address = ia.getHostAddress();
		// 主機名
		String name = ia.getHostName();
		System.out.println("IP=" + address + "\t name=" + name);

		// 獲取指定主機的ip信息
		InetAddress i = InetAddress.getByName("169.254.153.61");

		String add = i.getHostAddress();
		String na = i.getHostName();
		System.out.println("addIP=" + add + "\t name=" + na);

		// 獲取指定主機名的ip信息,可能主機不惟一因此逐個獲取並打印出來
		InetAddress[] csdn = InetAddress.getAllByName("www.csdn.net");
		for (InetAddress c : csdn) {
			String caddress = c.getHostAddress();
			String cname = c.getHostName();
			System.out.println("csdnIP=" + caddress + "\t csdnname=" + cname);
		}
	}
}

2)端口號: java

    a、用於標識進程的邏輯地址,不用進程的標識。 web

    b、有效端口:0~65535,系統使用或保留的端口是:0~1024。 小程序

3)傳輸協議:即通訊規則,包含TCP和UDP協議
UDP:是面向無鏈接,明確了對方的端口,不管在不在網上,只管傳輸,不在就會丟失數據。只求速度,應用於網絡視頻會議和聊天等應用程序中。
windows

特色: 數組

    a、面向無鏈接,即將數據及源和目的封裝成數據包中,不創建連接的發送 瀏覽器

    b、每一個數據包的大小限制在64K以內 服務器

    c、因無鏈接,是不可靠的協議 網絡

    d、不創建鏈接,速度快。
弊端:容易丟失數據包。   
舉例:視頻會議、聊天、桌面共享均可以做爲 UDP 傳輸。UDP 至關於步話機。
多線程

TCP:是面向鏈接的,必須鏈接成功才能傳輸數據,應用於下載等程序上

特色:

    a、面向鏈接,在創建鏈接後,造成傳輸數據的通道

    b、在鏈接中進行大數據量的傳輸

    c、經過三次握手完成鏈接,是可靠的協議

    d、必須創建鏈接,效率稍慢
舉例:打電話。

Note:三次握手:第一次本方發送請求,第二次對方確認鏈接,第三次本方再次確認鏈接成功。

四、通訊的步驟:

    1)找到IP地址

    2)數據要發送到對象指定應用程序,爲標識這些應用程序,因此給這些網絡應用程序都用數字標識,爲方便稱呼這個數字,叫作端口,即邏輯端口。

    3)定義通訊規則,稱之爲協議。國際組織定義了通用協議,即TCP/IP。

Note:必需要有數字標識才能將數據發送到應用程序上。

2、傳輸協議

一、Socket

    1)它被稱之爲插座,至關於港口同樣,是網絡服務提供的一種機制。

    2)通訊兩端都要有Socket,才能創建服務。

    3)網絡通訊其實就是Socket間的通訊,數據在兩個Socket間經過IO傳輸。

二、UDP傳輸

DatagramSocket: 表示用來發送和接收數據報包的套接字。

方法:

    1)建立 UDPSocket發送服務對象:DatagramSocket(),不指定端口。DatagramSocket(int port),指定端口。

    2)發送:void send(DatagramPacket p)

    3)接收:void receive(DatagramPacket p)

Note:DatagramPacket:表示數據報包,用來實現無鏈接包投遞服務。此包既能用來接收數據,還能用來封裝數據。每條報文僅根據該包中包含的信息從一臺機器路由到另外一臺機器中。凡是帶地址(InetAddress)的都是用於發送包的。

步驟:

    1)發送數據:

       a、創建UDPSocket服務,在此無需指定端口,也能夠將端口加入。若是不指定的話,系統會隨機分配一個端口,如第一次運行端口尚未獲得釋放,第二次會順延端口號值。

       b、提供數據,並將數據封裝到數據包中

       c、經過socket服務的發送功能,將數據包發送出去

       d、關閉資源

    2)接收數據:

       a、定義UDPSocket服務。一般會監聽一個端口,其實就是給這個接收網路應用程序定義數字標識,方便於明確哪些數據過來該應用程序能夠處理。

       b、定義一個數據包,用來存儲接收到的字節數據,由於數據包對象中有更多功能能夠提取字節數據中的不一樣數據信息。

       c、經過socket服務的receive方法接收到的數據存入已定義好的數據包中

       d、經過數據包對象的特有功能,將這些不一樣的數據取出,打印在控制檯上

       e、關閉資源

在定義接收數據的方法中,仍會在DatagramSocket構造函數中傳入DatagramPacket的參數,這是由於收到的數據太多,須要解析,經過將數據封裝成對象,易於解析,因此須要傳入參數。

Note:

    一、發送端與接收端是兩個獨立的運行程序。

    二、在發送端,要在數據包對象中明確目的地IP及端口。

    三、在接收端,要指定監聽的端口。

示例以下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
class UDPRece {
	public static void main(String[] args) {
		// 一、定義UDP 接受Socket服務,一般會見廳一個端口,即爲此程序定義一個數字標識,方便於明確數據的來源
		DatagramSocket ds = null;
		DatagramPacket dp = null;
		try {
			ds = new DatagramSocket(10000);
			// 二、定義一個數據包,經過Socket服務的receive方法將收到的數據存入此數據包中
			byte[] buf = new byte[1024];
			dp = new DatagramPacket(buf, buf.length);
			// 三、經過數據包的特有方法,將這些不一樣的數據去除打印在控制檯上
			ds.receive(dp);
		} catch (Exception e) {
			e.printStackTrace();
		}
		String ip = dp.getAddress().getHostAddress();
		String data = new String(dp.getData(), 0, dp.getLength());
		int port = dp.getPort();
		System.out.println("ip" + ip + "data" + data + "port" + port);
		// 四、關閉資源
		ds.close();
	}
}

public class UDPSend {
	public static void main(String[] args) {
		// 一、創建UDP Socket服務
		DatagramSocket ds = null;
		BufferedReader bufr = null;
		try {
			ds = new DatagramSocket(8888);
			// 二、提供數據,並將數據封裝到數據包中
			bufr = new BufferedReader(new InputStreamReader(System.in));
			String line = null;
			byte[] buf = null;
			DatagramPacket dp = null;
			while ((line = bufr.readLine()) != null) {
				if ("886".equals(line)) {
					break;
				}
				// byte[] data = "udp coming".getBytes();
				buf = line.getBytes();
				// 三、經過Socket服務的發送功能,將數據發送出去
				dp = new DatagramPacket(buf, buf.length,
						/* InetAddress.getLocalHost() */InetAddress
								.getByName("169.254.153.61"), 10000);
				ds.send(dp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 四、關閉資源
		ds.close();
	}
}
練習:編寫一個基於UDP傳輸的聊天小程序,要求能夠多線程訪問。
代碼示例以下:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/*
 * 聊天程序:
 * 	有收數據部分和發數據部分,同時運行就用到了多線程技術
 * 	由於收和發是不一致的,因此要定義兩個run方法,並且這兩個方法要封裝到不一樣的類中
 */
//發送端線程
class SendThread implements Runnable {
	private DatagramSocket ds;// 傳入數據包DatagramSocket

	// 構造函數傳入DatagramSocket用之後期操做
	public SendThread(DatagramSocket ds) {
		this.ds = ds;
	}

	@Override
	public void run() {
		try {
			BufferedReader bufr = new BufferedReader(new InputStreamReader(
					System.in));
			String line = null;
			while ((line = bufr.readLine()) != null) {
				if ("886".equals(line)) {
					break;
				}
				byte[] buf = line.getBytes();
				DatagramPacket dp = new DatagramPacket(buf, buf.length,
						InetAddress.getByName("169.254.153.61"), 30000);
				ds.send(dp);
			}
		} catch (Exception e) {
			throw new RuntimeException("發送端異常");
		}
	}
}

// 封裝接收端線程任務到Run方法中
class ReceThread implements Runnable {

	private DatagramSocket ds;

	public ReceThread(DatagramSocket ds) {
		super();
		this.ds = ds;
	}

	@Override
	public void run() {
		try {
			while (true) {
				byte[] buf = new byte[1024];
				DatagramPacket dp = new DatagramPacket(buf, buf.length);
				ds.receive(dp);

				String ip = dp.getAddress().getHostAddress();
				String data = new String(dp.getData(), 0, dp.getLength());
				System.out.println(ip + "::" + data);
			}
		} catch (Exception e) {
			throw new RuntimeException("接收端異常");
		}
	}
}

public class ChartDemo {

	public static void main(String[] args) throws SocketException {
		DatagramSocket sendSocket = new DatagramSocket();
		DatagramSocket receSocket = new DatagramSocket(30000);
		SendThread send = new SendThread(sendSocket);
		ReceThread rece = new ReceThread(receSocket);

		new Thread(send).start();
		new Thread(rece).start();
	}
}
三、TCP協議
TCP分客戶端和服務端。客戶端對應的對象是Socket,服務端對應的對象是ServerSocket。
創建TCP:
    1) Socket 和 ServerSocket
    2) 創建客戶端和服務器端
    3) 創建鏈接後,經過 Socket 中的 IO 流進行數據傳輸
    4) 關閉 Socket
主要方法:

    1)建立客戶端對象:

       Socket();建立空參數的客戶端對象,通常用於服務端接收數據

       Socket(String host,int port);指定要接收的IP地址和端口號

    2)建立服務端對象:ServerSocket(int port);指定接收的客戶端的端口

    3)Socket accept();監聽並接受到此套接字的鏈接

    4)void shutdownInput();此套接字的輸入流至於「流的末尾」

    5)void shutdownOutput();禁用此套接字的輸出流

    6)InputStream getInputStream();返回此套接字的輸入流,Socket對象調用

    7)OutputStream getOutputStream();返回套接字的輸出流,Socket對象調用

具體步驟:
客戶端:

    1) 創建 socket 服務。指定要鏈接主機和端口。
    2) 獲取 socket 流中的輸出流。將數據寫到該流中。經過網絡發送給服務端。
    3) 獲取 socket 流中的輸入流,將服務端反饋的數據獲取到,並打印。
    4) 關閉客戶端資源。
服務端:
    1) 創建服務端Socket服務————ServerSocket,並監聽一個端口
    2) 獲取連接過來的客戶端對象————ServerSocket的accept方法(阻塞式方法)
    3) 客戶端若是發過來數據,那麼服務端要使用對應的客戶端對象,並獲取到客戶端的讀取流來讀取發過來的數據並打印在控制檯上
    4) 關閉服務端(可選)
Note:客戶端與服務器端是兩個獨立的應用程序。必須先啓動服務器端,再鏈接客戶端。在沒有數據傳輸等服務時,服務端必須關閉客戶端鏈接,通常不關閉服務器。
示例1:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * 需求:客戶端給服務端發送一個文本數據,再定義端點接受數據並打印在控制檯上
 * 
 */

class TCPServer {
	public static void main(String[] args) throws IOException {
		// 創建服務端Socket服務,監聽一個端口
		ServerSocket ss = new ServerSocket(20000);

		// 獲取服務端連接過來的客戶端對象
		Socket socket = ss.accept();

		// 獲取客戶端發送過來的數據,要使用客戶端對象的讀取流來讀取數據
		InputStream in = socket.getInputStream();

		byte[] buf = new byte[1024];
		int len = in.read(buf);
		String ip = socket.getInetAddress().getHostAddress();
		String data = new String(buf, 0, len);

		System.out.println(ip + "::" + data);
		socket.close();
		ss.close();
	}

}

public class TCPClient {
	public static void main(String[] args) throws UnknownHostException,
			IOException {
		// 建立客戶端Socket服務,並指定主機和端口
		Socket socket = new Socket("169.254.153.61", 20000);
		// 爲了發送數據,就要獲取Socket流中的輸出流
		OutputStream os = socket.getOutputStream();
		os.write("tcp client coning".getBytes());
		socket.close();
	}
}
示例2:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * 演示tcp傳輸的客戶端和服務端互訪
 * 需求:客戶端給服務端發送數據,服務端收到後給客戶端反饋信息
 * 
 * 客戶端:
 * 一、創建socket服務,指定要連接的主機和端口
 * 二、獲取socket流中的輸入流,給服務端輸出文字
 * 三、獲取socket流中的讀取流,讀取服務端傳來的反饋信息並打印
 * 四、關閉流
 * 
 * 服務端:
 * 一、創建服務端Socket服務————ServerSocket,並監聽一個端口
 * 二、獲取連接過來的客戶端對象————ServerSocket的accept方法(阻塞式方法)
 * 三、客戶端若是發過來數據,那麼服務端要使用對應的客戶端對象,並獲取到客戶端的讀取流來讀取發過來的數據並打印在控制檯上
 * 四、關閉服務端(可選)
 */
class TcpClient2 {
	public static void main(String[] args) throws UnknownHostException,
			IOException {
		Socket s = new Socket("169.254.153.61", 20010);
		OutputStream os = s.getOutputStream();
		os.write("服務器,你好".getBytes());

		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf, 0, len));
		s.close();
	}
}

class TcpServer2 {
	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(20010);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip + "...connecting");
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf, 0, len));

		OutputStream os = s.getOutputStream();
		os.write("你好,我收到了".getBytes());
		s.close();
		ss.close();
	}
}
四、應用
a、上傳圖片

客戶端

    a、服務端點。

    b、讀取客戶端已有的圖片數據

    c、經過Socket輸出流將數據發給服務端

    d、讀取服務端反饋信息。

    e、關閉流資源

服務端

    a、服務端服務,並監聽指定端口

    b、獲取客戶端對象,並獲取客戶IP

    c、讀取客戶端輸入流數據

    d、寫入文件

    e、用客戶端輸出流反饋信息

    f、關閉流資源
Note:此服務端有侷限性,當A客戶端鏈接上以後,被服務端獲取到,這是B客戶端要獲取連接只有等待 那麼爲了可讓多個客戶端同時併發訪問客戶端。服務端最好就是將每一個客戶端封裝到一個單獨的線程中,這樣能夠同時處理多個客戶端請求。因此咱們想到了多線程,即多個客戶端向服務端傳輸數據,如何定義線程呢:只要明確每一個客戶端要執行的代碼便可,將其存入Run方法中便可。
代碼以下:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

class PicThread implements Runnable {
	private Socket s;

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

	@Override
	public void run() {
		int count = 1;
		String ip = null;
		try {
			ip = s.getInetAddress().getHostAddress();
			System.out.println(ip + "...connected");// 在服務端標識鏈接符

			// 避免多個客戶端傳入同一張照片後照片被覆蓋,因此將傳入的照片利用IP地址+計數器來重命名
			InputStream is = s.getInputStream();
			File file = new File(ip + "(" + count + ").jpg");
			while (file.exists()) {
				file = new File(ip + "(" + count++ + ").jpg");
			}

			FileOutputStream fos = new FileOutputStream(file);
			byte[] buf = new byte[1024];
			int len = 0;
			while ((len = is.read(buf)) != -1) {
				fos.write(buf, 0, len);
			}

			OutputStream os = s.getOutputStream();
			os.write("上傳成功".getBytes());// 上傳成功,在客戶端給出反饋信息
			fos.close();
			s.close();
		} catch (Exception e) {
			throw new RuntimeException(ip + "上傳失敗");// 上傳失敗的反饋信息
		}
	}
}

class PicServer {
	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(20020);
		Socket s = null;
		while (true) {
			s = ss.accept();
			new Thread(new PicThread(s)).start();
		}
	}
}

class PicClient {
	public static void main(String[] args) throws UnknownHostException,
			IOException {
		// 客戶端:
		// * 一、服務端點
		Socket s = new Socket("169.254.153.61", 20020);
		// * 二、讀取客戶端已有的圖片數據
		FileInputStream fis = new FileInputStream(
				"D:\\JDoc\\DemoForLeaning07\\ME.jpg");
		// * 三、經過socket輸出流將數據發送給服務端
		OutputStream os = s.getOutputStream();
		byte[] buf = new byte[1024];
		int len = 0;
		while ((len = fis.read(buf)) != -1) {
			os.write(buf, 0, len);
		}
		// 書寫標記
		s.shutdownOutput();
		// * 四、讀取服務端反饋信息
		InputStream in = s.getInputStream();
		byte[] bufIn = new byte[1024];
		int lens = in.read(bufIn);
		System.out.println(new String(bufIn, 0, lens));
		// * 五、關閉資源

		fis.close();
		s.close();
	}
}
3、URL類
一、URL:表明一個統一資源定位符,它是指向互聯網「資源」指針。
構造函數:
    URL(Stirng spec)    //根據 String 表示形式建立 URL 對象
    URL(Stirng protocol , String host , int port , String file)    
    //根據指定 protocol、host、port 號和 file 建立 URL 對象。Protocol 表明協議。

主要方法:
    String getFile()      //獲取此  URL  的文件名。
    String getHost()      //獲取此  URL  的主機名(若是適用)。
    String getPath()      //獲取此  URL  的路徑部分。
    int getPort()      //獲取此  URL  的端口號。
    String getProtocol()    //獲取此  URL  的協議名稱。
    String getQuery()    //獲取此  URL  的查詢部
    URLConnection    openConnection()   
    //返回一個 URLConnection 對象,它表示到 URL 所引用的遠程對象的鏈接。也就是調用此對象,就會鏈接 URL 主機,返回主機對象。
每次調用此鏈接 URL 的協議處理程序的 openConnection()方法都打開一個新的鏈接。

    InputStream OpenStream()    
    //開流打開此 URL 的鏈接,並返回一個用於從該鏈接讀入的InputStream,至關於openConnection().getInputStream()。
    String getConnectionType()    //返回鏈接的頭字段值
Note: 若地址信息中沒有指定 port 端口號,則 get port()返回-1。當 port 等於-1 時,指定默認端口號爲 80。
示例以下:

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
class URLDemo 
{
	public static void main(String[] args) throws MalformedURLException
	{
		URL url = new URL("http://192.168.1.254/myweb/demo.html?name=haha&age=30");

		System.out.println("getProtocol() :"+url.getProtocol());
		System.out.println("getHost() :"+url.getHost());
		System.out.println("getPort() :"+url.getPort());
		System.out.println("getPath() :"+url.getPath());
		System.out.println("getFile() :"+url.getFile());
		System.out.println("getQuery() :"+url.getQuery());
		
	}
}

class  URLConnectionDemo
{
	public static void main(String[] args) throws Exception
	{
		URL url = new URL("http://192.168.1.254:8080/myweb/demo.html");

		URLConnection conn = url.openConnection();
		//有此方法了,Socket就能夠不用了
		System.out.println(conn);
		
		InputStream in = conn.getInputStream();

		byte[] buf = new byte[1024];

		int len = in.read(buf);

		System.out.println(new String(buf,0,len));

	}
}
二、域名解析
將主機名翻譯成 IP 地址,須要域名解析——DNS。
    當在本地瀏覽器中輸入一個網址,在進行訪問的時候,會先在本地的hosts文件(c:\windows\system32\drivers\ext\host)中找對應的映射。如有,則直接返回請求;若無,則到公網的映射列表即DNS中找對應的映射,找到後,將主機名對應的IP地址返回給本機,本機經過這個IP地址找到對應的服務器。
    例如:127.0.0.1    localhost

做用:對應的映射關係寫入hosts中,將IP地址改成本機的迴環地址,當訪問到該IP的時候就直接去hosts中尋址,代替類去公網服務器上訪問資源,以此來屏蔽惡意網站等等。

    以上所述僅表明我的觀點,若有出入請諒解。

相關文章
相關標籤/搜索