1、概述 html
一、網絡架構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協議
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對象調用
具體步驟: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、服務端點。
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類
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)); } }二、域名解析
做用:對應的映射關係寫入hosts中,將IP地址改成本機的迴環地址,當訪問到該IP的時候就直接去hosts中尋址,代替類去公網服務器上訪問資源,以此來屏蔽惡意網站等等。
以上所述僅表明我的觀點,若有出入請諒解。