天天看點

Java中的網絡程式設計(UDP、TCP/IP協定)1.網絡程式設計概述2.IP類3.UDP協定4.TCP協定

1.網絡程式設計概述

1.1 C/S和B/S

C/S

用戶端——伺服器軟體結構
服務提供商給予使用者服務需要準備的内容(如:本地軟體更新)
           

B/S

浏覽器——伺服器軟體結構
服務提供商隻要提供資料服務以及前端資料展示方式。
           

1.2 網絡通信協定

協定

protocol協定
網絡通信協定是要求雙方傳遞資料的計算機必須遵守的,按照對應的網絡傳輸協定,才可以進入資料的互動和傳遞。
           

常見的協定:

應用層	HTTP、HTTPS、FTP、SMTP、SNMP、DNS
傳輸層	TCP、UDP
網絡層	JCMP、IGMP、IP、ARP、PARP
資料鍊路層	Wi-Fi、GPS、以太網
實體層	以太網、數據機
           

1.3 UDP和TCP/IP差別

UDP使用者資料報協定

類似于廣播
面向無連接配接,資料傳遞不算特别安全
因為無連接配接,傳輸速度快
因為無連接配接,資料傳遞存在丢包問題
UDP沒有用戶端和伺服器端差別,都可以作為發送端和接收端
UDP協定使用場景:直播、遊戲
           

TCP/IP傳輸控制協定

面向連接配接,資料傳遞較為安全
因為有連接配接,是以傳遞速度較慢
但資料傳遞有保障
TCP/IP協定是有明确的用戶端和伺服器端概念
TCP/IP協定使用場景:用戶端登陸,資料下載下傳,檔案傳輸
           

1.4 網絡程式設計的三要素

(1)協定

兩個在有網絡的情況下的計算機資料傳遞,都需要對應的協定來完成
           

(2)IP位址

Internet Protocol Address
目前計算機在網絡中的一個位址編号,類似于手機号碼
IPv4是一個32位的二進制數,通常展示效果是a.b.c.d 如:192.168.1.1。abcd各代表0~255的數字,目前已使用完。

IPv6是足夠使用。
128位位址長度,16位元組一組,8組,0x0 ~ 0xFFFF
           

(3)端口号

端口号是目前應用程式在計算機中的一個編号。可以讓計算機明确知道,目前的資料是給予哪一個程式使用,或者資料從哪一個程式出現。
端口号是一個short類型 0~65535
0~1024不能用于自定義端口号使用,特定的系統端口号。
           

2.IP類

SUN公司提供給開發使用的IP位址類(InetAddress)

常用方法

InetAddress getLocalhost();
擷取本機IP位址類對象
InetAddress getByName(String str);
根據指定的主機名擷取對應的IP位址對象
InetAddress[] getAllByName(String str);
擷取指定主機名,或者域名對應的所有IP位址類對象
           

代碼示範

import java.net.InetAddress;
import java.net.UnknownHostException;

/*
 * IP類示範
 */
public class Demo1 {
	public static void main(String[] args) throws UnknownHostException {
		InetAddress localHost = InetAddress.getLocalHost();
		System.out.println(localHost);
		
		InetAddress byName = InetAddress.getByName("DESKTOP-M89SDP7");
		System.out.println(byName);
		
		InetAddress byName2 = InetAddress.getByName("www.4399.com");
		System.out.println(byName2);
		
		System.out.println("----------------------------------");
		
		InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
		for (InetAddress inetAddress : allByName) {
			System.out.println(inetAddress);
		}
		
		System.out.println("----------------------------------");
		InetAddress[] allByName1 = InetAddress.getAllByName("www.taobao.com");
		for (InetAddress inetAddress : allByName1) {
			System.out.println(inetAddress);
		}
		
		System.out.println("----------------------------------");
		InetAddress[] allByName2 = InetAddress.getAllByName("www.jd.com");
		for (InetAddress inetAddress : allByName2) {
			System.out.println(inetAddress);
		}
	}
}
           

3.UDP協定

3.1 UDP資料傳輸方式

UDP:User Datagram Protocol 使用者資料報協定

資料傳遞采用資料包方式傳遞,所有的資料要進行打包操作,并且沒有對應的用戶端伺服器概念,有且隻有發送端和接收端。
           

Socket套接字

資料需要進行傳遞操作,在資料傳遞的兩台計算機當中必須有對應的Socket。這裡采用UDP協定,那麼必須有一個UDP協定的Socket。

構造方法:
DatagramSocket();
建立一個發送端UDP協定Socket對象
DatagramSocket(int port);
建立一個接收端UDP協定的Socket對象,這裡需要【監聽指定端口】
           

發送端的資料包打包方式:

DatagramPacket DatagramPacket(byte[] buf, int length, InetAddress address, int port);
buf:需要傳遞資料的位元組數組
length:是目前位元組數組中資料容量位元組數
address:接收端IP位址對象
port:接收端對應的端口号
           

接收端的資料包接受方式:

這裡需要準備一個空的資料包
DatagramPacket DatagramPacket(byte[] buf, int length);
buf:位元組緩沖數組,通常是1024整數倍
length:目前位元組緩沖數組的容量
           

3.2發送端流程

流程

建立UDP伺服器對應的發送端Socket
準備對應資料包,需要帶有指定資料
發送資料包 send
關閉UDP發送端
           

代碼示範

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SenderDemo1 {
	public static void main(String[] args) throws IOException {
		System.out.println("發送端啟動");
		// 建立對應的Socket
		DatagramSocket socket = new DatagramSocket();
		
		// 準備資料包
		byte[] bytes = "今天中午吃蒸羊羔...".getBytes();
		DatagramPacket packet = new DatagramPacket(bytes,  // 位元組數組資料
				bytes.length,  // 位元組數組資料長度
				InetAddress.getLocalHost(),  // 指定接收端IP位址
				8848); // 8848對應端口号
		
		// 發送資料包
		socket.send(packet);
		// 關閉UDP發送端
		socket.close();
	}
}
           

3.3接收端流程

流程

打開UDP服務,并且監聽指定端口
建立新的空資料包
通過Socket接受資料
關閉UDP服務接收端
           

代碼示範

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveDemo1 {
	public static void main(String[] args) throws IOException {
		// 建立Socket監聽端口
		DatagramSocket socket = new DatagramSocket(8848);
		
		// 準備空資料包
		byte[] buf = new byte[1024];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);
		
		// 接收資料
		socket.receive(packet);
		
		// 确定接收到的位元組長度
		int length = packet.getLength();
		
		System.out.println(new String(buf, 0, length));
		
		// 關閉socket
		socket.close();
		
	}
}
           

3.4UDP資料傳遞丢失問題

網絡不夠好,穩定性不行,帶寬不夠
電腦性能不好

以上都會導緻資料傳遞丢失
           

3.5FeiQ

網絡傳輸都有自己的傳輸規格,如果軟體接收到的資料是自己的規格,那麼可以讀取資料,否則丢棄!!

如FeiQ:

version:time:sender:ip:flag:content
版本:時間:發送者名字:發送人IP:标記:内容
資料是一個String類型
而且使用的協定是UDP協定
           

代碼示範

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class FeiQ {
	public static void main(String[] args) throws IOException {
		DatagramSocket socket = new DatagramSocket();
		
		//getData方法,将字元串資料轉換為指定格式
		String data = getData("Welcome to Java World!!!");
		DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(), data.getBytes().length
				, InetAddress.getByName("192.168.31.255"), 2425);
		
		socket.send(datagramPacket);
		
		socket.close();
		
	}
	
	/**
	 * 傳入資料,轉換成FeiQ可以識别的資料
	 * version:time:sender:ip:flag:content
	 * 
	 * @param message 字元串類型内容
	 * @return 符合FeiQ格式要求的字元串
	 */
	public static String getData(String message) {
		StringBuilder stb = new StringBuilder();
		
		stb.append("1.0:");
		stb.append(System.currentTimeMillis() + ":");
		stb.append("Anonymous:");
		stb.append("10.1.1.1:");
		stb.append("32:");
		stb.append(message);
		
		return stb.toString();
	} 
}
           

4.TCP協定

4.1 TCP概述

TCP相對于UDP比較穩定,存在三次握手機制,保證連接配接狀态,同時有明确的用戶端和伺服器之分
TCP服務中需要伺服器端先啟動,需要監聽指定端口,等待用戶端連接配接。
用戶端主動連接配接伺服器,和伺服器連接配接之後,才可以進行資料互動,伺服器不能主動連接配接用戶端。
           

對于TCP,Java中提供了兩個Socket

(1)服務端Socket
	java.net.ServerSocket;
	建立對應的ServerSocket開啟伺服器,等待用戶端連接配接
(2)用戶端Socket
	java.net.Socket;
	建立用戶端Socket,并且連接配接伺服器,同時将Socket發送給伺服器綁定注冊。
           

三次握手機制

Java中的網絡程式設計(UDP、TCP/IP協定)1.網絡程式設計概述2.IP類3.UDP協定4.TCP協定

4.2 用戶端Socket

給用戶端提供資料傳輸的符合TCP/IP要求的Socket對象

構造方法

Socket(String host, int port);
	host:是伺服器IP位址
	port:對應伺服器程式的端口号
	通過指定的【伺服器IP位址】和【端口号】,擷取TCP連接配接對象
           

成員方法

InputStream getInputStream();
	擷取Socket對象輸入位元組流,可以【從伺服器擷取】對應的資料
	InputStream是一個資源,需要在程式退出時關閉
OutputStream getOutputStream();
	擷取Socket對象輸出位元組流,可以【發送資料】到伺服器
	須在退出時關閉
void close();
	關閉用戶端Socket
void shutdownOutput();
	禁止目前Socket發送資料

TCP/IP協定對應的Socket是基于IO流實作的。
           

4.3 服務端Socket(ServerSocket)

構造方法

ServeSocket(int port);
	開啟ServeSocket伺服器,并且明确目前服務端口是誰
           

成員方法

Socket accept();
	監聽并且連接配接,得到一個Socket對象,同時該方法是一個阻塞方法,會處于一個始終監聽的狀态
	傳回的是Socket,也就是用戶端Socket對象,擷取到目前Socket對象,相當于擷取到用戶端連接配接,同時使用的Socket和用戶端一緻。
           

4.4 TCP協定示範

Java中的網絡程式設計(UDP、TCP/IP協定)1.網絡程式設計概述2.IP類3.UDP協定4.TCP協定
4.4.1伺服器流程

流程:

(1)建立ServerSocket伺服器,同時監聽指定端口
(2)通過accept方法擷取Socket連接配接,得到用戶端Socket對象
(3)通過Socket對象,擷取InputStream,讀取用戶端發送資料
(4)通過Socket對象,擷取OutputStream,發送資料給用戶端
(5)關閉服務
           

代碼示範:

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

/*
流程:
	1. 建立ServerSocket伺服器,同時監聽指定端口
	2. 通過accept方法擷取Socket連接配接,得到用戶端Socket對象
	3. 通過Socket對象,擷取InputStream,讀取用戶端發送資料
	4. 通過Socket對象,擷取OutputStream,發送資料給用戶端
	5. 關閉服務 
 */
public class TcpServer1 {
	public static void main(String[] args) throws IOException {
		System.out.println("伺服器啟動");
		System.out.println("-----------------------");
		// 1. 建立ServerSocket伺服器,同時監聽指定端口
		ServerSocket serverSocket = new ServerSocket(8848);
	
		// 2. 通過accept方法擷取Socket連接配接,得到用戶端Socket對象
		Socket socket = serverSocket.accept();
		
		// 3. 通過Socket對象,擷取InputStream,讀取用戶端發送資料
		InputStream inputStream = socket.getInputStream();
		
		// IO流操作
		byte[] buf = new byte[1024];
		int length = inputStream.read(buf);
		System.out.println(new String(buf, 0, length));
        
		// 4. 通過Socket對象,擷取OutputStream,發送資料給用戶端
		OutputStream outputStream = socket.getOutputStream();
		String str = "歡迎來到德萊聯盟";
		
		outputStream.write(str.getBytes());
		
		// 5. 關閉Socket服務 同時關閉目前Socket使用的輸入位元組流和輸出位元組流	
		// Closing this socket will also close the socket's InputStream and OutputStream. 
		socket.close();	
	}
}
           
4.4.2用戶端流程

流程:

(1)建立Socket服務,同時明确連接配接伺服器的IP位址和對應端口号
(2)通過Socket對象,擷取對應的OutputStream對象,發送資料給伺服器
(3)通過Socket對象,擷取對應的InputStream對象,接受伺服器發送的資料
(4)關閉該服務
           

代碼示範

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

/*
流程:
	1. 建立Socket服務,同時明确連接配接伺服器的IP位址和對應端口号
	2. 通過Socket對象,擷取對應的OutputStream對象,發送資料給伺服器
	3. 通過Socket對象,擷取對應的InputStream對象,接收伺服器發送資料
	4. 關閉服務
 */
public class TcpClient1 {
	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("用戶端啟動");
		System.out.println("------------------------");
		// 1. 建立Socket服務,同時明确連接配接伺服器的IP位址和對應端口号
		Socket socket = new Socket("192.168.31.154", 8848);
		
		// 2. 通過Socket對象,擷取對應的OutputStream對象,發送資料給伺服器
		OutputStream outputStream = socket.getOutputStream();
		
		outputStream.write("你好伺服器!!!".getBytes());
		
		// 3. 通過Socket對象,擷取對應的InputStream對象,接收伺服器發送資料
		InputStream inputStream = socket.getInputStream();
		
		byte[] buf = new byte[1024];
		int length = inputStream.read(buf);
		System.out.println(new String(buf, 0, length));
		
		// 4. 關閉服務
		socket.close();
	}
}
           

4.5 檔案上傳操作

4.5.1分析過程
Java中的網絡程式設計(UDP、TCP/IP協定)1.網絡程式設計概述2.IP類3.UDP協定4.TCP協定
4.5.2 用戶端程式

流程:

(1)建立對應檔案的輸入位元組流操作,用緩沖
(2)啟動Socket
(3)擷取Socket輸出OutputStream對象,發送資料給伺服器
(4)邊讀邊發,而不是讀取完再統一發送
(5)檔檔案讀取結束時,發送完畢,關閉用戶端
           

代碼示範:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/*
流程:
	1. 建立對應檔案的輸入位元組流操作,這裡可以使用緩沖
	2. 啟動Socket,
	3. 擷取Socket輸出OutputStream對象,發送資料給伺服器
	4. 邊讀邊發
	5. 當檔案讀取結束,發送完畢,關閉用戶端
 */
public class TcpClient {
	public static void main(String[] args) throws IOException {
		// 1. 建立對應檔案的輸入位元組流操作,這裡可以使用緩沖
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(new File("D:/aaa/1.mp4")));
		
		// 2. 啟動Socket
		Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 8848);
		
		// 3. 擷取Socket輸出OutputStream對象,發送資料給伺服器
		OutputStream outputStream = socket.getOutputStream();
		
		int length = -1;
		byte[] buf = new byte[1024 * 8];
		
		
		// 4. 讀取資料,發送資料
		while ((length = bis.read(buf)) != -1) {
			outputStream.write(buf, 0, length);
		}
		
		// 5. 關閉資源
		socket.close();
		bis.close();
	}
}
           
4.5.3服務端程式

流程:

(1)開啟服務端服務,建立ServerSocket對象
(2)明确儲存檔案的位置,建立對應檔案夾的輸出緩沖位元組流
(3)讀取資料,寫入檔案
(4)關閉伺服器
           

代碼示範:

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/*
流程:
	1. 開啟服務端服務,建立ServerSocket對象
	2. 明确儲存檔案的位置,建立對應檔案夾的輸出緩沖位元組流
	3. 讀取資料,寫入檔案
	4. 關閉伺服器
 */
public class TcpServer {
	public static void main(String[] args) throws IOException {
		// 1. 開啟服務端服務,建立ServerSocket對象
		ServerSocket serverSocket = new ServerSocket(8848);
		
		Socket socket = serverSocket.accept();
		
		// 2. 明确儲存檔案的位置,建立對應檔案夾的輸出緩沖位元組流
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream(
						new File("D:/aaa/temp.mp4")));
		
		// 3. 擷取Socket對應的輸入流
		InputStream inputStream = socket.getInputStream();
		
		// 4. 邊讀邊寫
		int length = -1;
		byte[] buf = new byte[1024 * 8];
		
		while ((length = inputStream.read(buf)) != -1) {
			bos.write(buf, 0, length);
		}
		
		// 5. 關閉資源
		bos.close();
		socket.close();
	}
}
           
4.5.4 目前服務端代碼問題
(1)儲存的檔案名都是一緻的,無法儲存多個檔案夾。
(2)服務端代碼肯定不能執行完一個上傳功能就結束
(3)服務端代碼不可能隻有一個上傳檔案功能
(4)多線程