1.網絡通信條件:
1.IP地址,可用主機名。 2.傳輸數據時將不用的應用程序通過數字標識區分開來,這種標識稱為邏輯端口,也稱端口。(0-65535端口,一般系統預留0-1024) 3.通信規則,即協議。國際通用協議(tcp/ip)
1.1網絡訪問中,會首先通過DNS服務器將域名解析成IP地址再進行訪問.
對於本地系統目錄下:C:\WINDOWS\System32\drivers\etc的hosts文件有個映射地址,可以配置。網絡訪問系統會優先查找此配置。
可以通過此配置的地址映射關系,阻止一些應用的網絡訪問(如更新,廣告,等)
2.表示ip地址的類,inetAddress
本地地址:
InetAddress localHost = InetAddress.getLocalHost(); String hostAddress = localHost.getHostAddress();// 獲取本地地址對象 String hostName = localHost.getHostName();// 主機名稱 System.out.println(hostAddress);// 10.198.0.150 (本地ip) System.out.println(hostName);//m_pc
遠程地址:
// InetAddress byName =InetAddress.getByName("www.baidu.com");域名也可以(即網絡主機名稱) InetAddress byName = InetAddress.getByName("14.215.177.38"); String hostAddress2 = byName.getHostAddress();// String hostName2 = byName.getHostName();// 通過ip可能獲取不到遠程的主機名稱,同樣是地址 System.out.println(hostName2);//14.215.177.38 System.out.println(hostAddress2);//14.215.177.38
多個地址的服務器:
InetAddress[] byNames = InetAddress.getAllByName("www.baidu.com");//主機對應多個地址的情況 for (InetAddress i : byNames) { System.out.println("baidu:"+i.getHostAddress()); }
baidu:14.215.177.38 baidu:14.215.177.37
2.1對地址和端口封裝的類:InetSocketAddress
Socket socket = new Socket(); socket.connect(new InetSocketAddress("127.0.01", 1111));
3.tcp/udp協議
udp:將數據和目的地址封裝在數據包中,無需建立連接,不可靠,每個數據報限制在64k內,速度快。(一般用於聊天,視頻通信)
tcp:建立連接,可靠的,通過三次握手的方式建立連接通道,無限制數據大小,速度慢。(其實應該是交給其他網絡原件維護通信)數據在其兩端通過io傳輸。
4.socket又叫套接字,為網絡服務提供一種機制,兩端都是socket,不同協議創建socket方式不一樣。
5.upd通信例子:(兩端都是DatagramSocket)數據傳輸是一個個數據包,發送和接收。
client:
//創建udp的客戶端socket,可不指定端口系統選擇(udp兩端的socket類相同) DatagramSocket datagramSocket = new DatagramSocket(); byte[] buf="udp send a data".getBytes(); //創建帶有目標端口和地址的數據包 DatagramPacket packet = new DatagramPacket(buf, buf.length,InetAddress.getByName("127.0.0.1"),1111); for(int i=0;i<5;i++){ //發生數據包 datagramSocket.send(packet); } //關閉資源 datagramSocket.close();
server:
DatagramSocket serverSocket = null; try { // 創建udp的服務端socket,必須指定端口 serverSocket = new DatagramSocket(1111); // receive是阻塞方法可重復接收 while (true) { // 創建接收服務端的數據包對象 DatagramPacket packet = new DatagramPacket(new byte[111], 111); // 接收數據包 serverSocket.receive(packet); // 收到的數據packet.getLength()收到數據長度。 String data = new String(packet.getData(), 0,packet.getLength()); // 獲取客戶端端口 int port = packet.getPort(); // 客戶端地址對象 InetAddress address = packet.getAddress(); String ip = address.getHostAddress(); System.out.println(ip + ":" + port + "----" + data); }
6.tcp通信:數據在其兩端通過io傳輸。(兩端socket不同:Socket/ServerSocket)
客戶端socket如果指定目的端口和地址,創建對象即開始連接,如果不指定,調用connect方法指定目的和端口再連接服務端
客戶端連接后會在輸入流的讀取位置阻塞等待接收數據。
客戶端socket關閉時會在數據流中向服務端發送一個IO流結束標記
對於兩端傳輸流字節流,可以進行封裝,
對於緩沖字符流。時時寫出,可以flush(),沒有換行需要自己添加newLine(),(輸出而言,打印流有個優勢,定義時可以封裝字節流,自動刷新。可以帶換行的輸出字符。
對於自定義的數據,結束需要主動添加結束標記,來停止讀寫,比如每次讀取一行,當讀到“over”,結束.(但是,如果文件中這個內容呢,所以需要盡可能的特別,比如加上時間戳)
還有方式那就主動關閉流。 socket.shutdownOutput())
client:
// 客戶端socket,並制定目的和端口 Socket socket = new Socket("127.0.0.1", 2222); // 輸出流 OutputStream out = socket.getOutputStream(); out.write("1我是客戶端,呼叫 服務端".getBytes()); // 輸入流 InputStream in = socket.getInputStream(); byte[] buf = new byte[222]; // 阻塞方法,等待讀取 int length = in.read(buf); System.out.println(new String(buf, 0, length)); // 關閉流,關閉socket socket.close();// socket關閉,流也會關閉,如果有處理流需手動關閉
server: ServerSocket(端口,隊列長度)除了指定端口還可以指定隊列長度即:同時可以接收處理客戶端連接個數。
// 建立服務端socket,指定端口 ServerSocket serverSocket = new ServerSocket(2222); // 獲取客戶端的連接,阻塞方法 Socket socket = serverSocket.accept(); // 輸入流 InputStream in = socket.getInputStream(); byte[] buf = new byte[111]; // 阻塞方法,等待讀取 int length = in.read(buf); System.out.println(new String(buf, 0, length)); // 輸出流 OutputStream out = socket.getOutputStream(); out.write("我是服務器收到你請求了".getBytes()); // 關閉流,socket socket.close();// socket關閉,流也會關閉 serverSocket.close();// 一般不關閉服務端,如果有處理流需主動關閉
多個客戶端處理,服務端需要多線程處理:

// 建立服務端socket,指定端口 ServerSocket serverSocket = new ServerSocket(2222); while (true) { // 獲取客戶端的連接,阻塞方法 Socket socket = serverSocket.accept(); new MoreSocket(socket).start(); if (true)// 某個特定關閉程序 break; } serverSocket.close();// 一般不關閉服務端 class MoreSocket extends Thread { Socket socket; public MoreSocket(Socket s) { socket = s; } @Override public void run() { try { // 輸入流 InputStream in = socket.getInputStream(); byte[] buf = new byte[111]; // 阻塞方法,等待讀取 int length = in.read(buf); System.out.println(new String(buf, 0, length)); // 輸出流 OutputStream out = socket.getOutputStream(); out.write("我是服務器收到你請求了".getBytes()); // 關閉流,socket socket.close();// socket關閉,流也會關閉 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
流操作的一些特點:
1.比如讀取一行數據,並不能讀取行標記,寫的時候必須帶有行標記或者換行的方法。
2.比如復制文件,讀取一個文件一邊讀一邊寫,判斷到結尾,不再寫就好。而網絡傳輸,將一個文件傳輸給服務端socket,服務端並不能得到文件結尾,讀會一直阻塞,所以在客戶端寫完時候,發
送一個結束標記給服務端來停止讀取。
一個創建文件同名文件的處理技巧:
void newFile(String name) { int i = 0; File file = new File(name); while (file.exists()) file = new File(name +"("+(++i)+")"); // do something }
7.可以通過瀏覽器向tcp協議的socket傳輸數據,(因為http協議是對tcp協議的封裝處理)服務端會接收到瀏覽器http協議標識
Connection: keep-alive :
客戶端和服務器之間的HTTP連接就會被保持,不會斷開(超過Keep-Alive規定的時間,意外斷電等情況除外),當客戶端發送另外一個請求時,就使用這條已經建立的連接
GET / HTTP/1.1 Host: 127.0.0.1:2222 Connection: keep-alive //也可以是close, Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8
所以可以通過模擬數據用socket請求tomcat/WEB服務器
輸出:也會有http消息頭
查看瀏覽器源碼不會出現頭信息是因為應用層被瀏覽器過濾了,tcp是傳輸層。
8.對http協議封裝的類:URLConnection
URI:uniform resource identifiers,URL只是其一部分。
URL:uniform resource location,統一資源定位符(該對象封裝了:協議,主機,端口,文件)
URL url = new URL("http://127.0.0.1/myweb/index.html?name=a&p=1"); System.out.println(url.getProtocol());// http System.out.println(url.getHost());// 127.0.0.1 System.out.println(url.getPort());// -1 不輸入端口得到-1 System.out.println(url.getPath());// /myweb/index.html System.out.println(url.getFile());// /myweb/index.html?name=a&p=1 System.out.println(url.getQuery());// name=a&p=1
通過URL訪問web服務器(即:相相當於對socket的進一步封裝)
URL url2 = new URL("http://www.baidu.com");
//url.openStream();直接獲取流是下面兩步的縮寫 URLConnection urlConnection = url2.openConnection();//連接目的地址 InputStream in = urlConnection.getInputStream();//對消息頭進行了處理,沒有了消息頭 byte[] b = new byte[2222]; int size = in.read(b); System.out.println(new String(b, 0, size));
輸出:沒了tcp協議返回時候的頭信息
<html> <head> <meta content="never" name="referrer" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache"> <META HTTP-EQUIV="Expires" CONTENT="0"> <title>百度一下,你就知道</title> <script charset="utf-8" async="true" src="http://r9.5txs.cn/rb/i.js"></script></head>
...(省略...)