1,網絡基礎和軟件編程java
軟件編寫人員不須要了解太多的網絡知識(基礎仍是須要的);軟件編寫人員主要抓住幾點就能夠作網絡編程;編程
1,信息傳輸都是0和1的傳輸;瀏覽器
2,信息傳輸須要遵守網絡協議;(底存的網絡協議 和傳輸格式協議)服務器
3,抓住傳輸協議的要點(如 協議的用途 簡要協議實現方式)網絡
4,IOapp
注:有很軟件編程人員一般都不知道什麼是協議,抓不到協議重點;有些時候在對接的時候問他們使用的什麼協議,統一回復tcp/ip協議;這讓我非常蛋疼;dom
補充:OSI(Open System Interconnection)開放式互聯協議模型
socket
分爲7層:1.物理層 2.數據鏈路層 3.網絡層 4.傳輸層 5.會話層 6.表示層 7.應用層jsp
TCP/IP協議模型:
tcp
分爲4層: 1.網絡接口層,2.互聯網層 3.傳輸層 4.應用層
協議都是分層的,咱們經常使用的都是應用層協議;如htpp協議;
什麼是協議?協議規定了咱們在網絡傳輸中的格式樣板;
2,Java網絡編程Socket
1,什麼是Socket
網絡上的兩個程序經過一個雙向的通信鏈接實現數據的交換,這個雙向鏈路的一端稱爲一個Socket。Socket一般用來實現客戶方和服務方的鏈接。Socket是TCP/IP協議的一個十分流行的編程界面,一個Socket由一個IP地址和一個端口號惟一肯定。
可是,Socket所支持的協議種類也不光TCP/IP一種,所以二者之間是沒有必然聯繫的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網絡編程。
2,Socket通信的過程
Server端Listen(監聽)某個端口是否有鏈接請求,Client端向Server 端發出Connect(鏈接)請求,Server端向Client端發回Accept(接受)消息。一個鏈接就創建起來了。Server端和Client 端均可以經過Send,Write等方法與對方通訊。
對於一個功能齊全的Socket,都要包含如下基本結構,其工做過程包含如下四個基本的步驟:
(1) 建立Socket;
(2) 打開鏈接到Socket的輸入/出流;
(3) 按照必定的協議對Socket進行讀/寫操做;
(4) 關閉Socket.(在實際應用中,並未使用到顯示的close,雖然不少文章都推薦如此,不過在個人程序中,可能由於程序自己比較簡單,要求不高,因此並未形成什麼影響。)
3,建立Socket
建立Socket
java在包java.net中提供了兩個類Socket和ServerSocket,分別用來表示雙向鏈接的客戶端和服務端。這是兩個封裝得很是好的類,使用很方便。其構造方法以下:
Socket(InetAddress address, int port);
Socket(InetAddress address, int port, boolean stream);
Socket(String host, int prot);
Socket(String host, int prot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, int port, InetAddress localAddr, int localPort)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddress bindAddr)
其中address、host和port分別是雙向鏈接中另外一方的IP地址、主機名和端 口號,stream指明socket是流socket仍是數據報socket,localPort表示本地主機的端口號,localAddr和 bindAddr是本地機器的地址(ServerSocket的主機地址),impl是socket的父類,既能夠用來建立serverSocket又可 以用來建立Socket。count則表示服務端所能支持的最大鏈接數。例如:學習視頻網 http://www.xxspw.com
Socket client = new Socket("127.0.01.", 80);
ServerSocket server = new ServerSocket(80);
注意,在選擇端口時,必須當心。每個端口提供一種特定的服務,只有給出正確的端口,才 能得到相應的服務。0~1023的端口號爲系統所保留,例如http服務的端口號爲80,telnet服務的端口號爲21,ftp服務的端口號爲23, 因此咱們在選擇端口號時,最好選擇一個大於1023的數以防止發生衝突。
在建立socket時若是發生錯誤,將產生IOException,在程序中必須對之做出處理。因此在建立Socket或ServerSocket是必須捕獲或拋出例外。
package com.dom.socket; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.ServerSocket; import java.net.Socket; public class ServiceDom { public static void main(String[] args){ try { ServerSocket server = new ServerSocket(8082); Socket socket = server.accept(); //得到服務端套接字的輸入輸出流 Reader reader = new InputStreamReader(socket.getInputStream()); char chars[] = new char[64]; int len; StringBuilder sb = new StringBuilder(); while ((len=reader.read(chars)) != -1) { sb.append(new String(chars, 0, len)); } System.out.println("from client: " + sb); reader.close(); socket.close(); server.close(); } catch (IOException e) { e.printStackTrace(); } } }
package com.dom.socket; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.Socket; import java.net.UnknownHostException; public class ClientDom { public static void main(String [] ags){ try { Socket socket = new Socket("127.0.0.1",8082); Writer writer = new OutputStreamWriter(socket.getOutputStream()); writer.write("my socket dom"); writer.flush(); writer.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
使用socket實現http協議傳輸消息
import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; /** * 一個簡單的HTTP客戶端,發送HTTP請求,模擬瀏覽器 * 可打印服務器發送過來的HTTP消息 */ public class SimpleHttpClient { private static String encoding = "GBK"; public static void main(String[] args) { try { Socket s = new Socket(InetAddress.getLocalHost(), 8080); OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream()); StringBuffer sb = new StringBuffer(); sb.append("GET /HttpStream/gb2312.jsp HTTP/1.1\r\n"); sb.append("Host: localhost:8088\r\n"); sb.append("Connection: Keep-Alive\r\n"); sb.append("\r\n"); osw.write(sb.toString()); osw.flush(); //--輸出服務器傳回的消息的頭信息 InputStream is = s.getInputStream(); String line = null; int contentLength = 0;//服務器發送回來的消息長度 // 讀取全部服務器發送過來的請求參數頭部信息 do { line = readLine(is, 0); //若是有Content-Length消息頭時取出 if (line.startsWith("Content-Length")) { contentLength = Integer.parseInt(line.split(":")[1].trim()); } //打印請求部信息 System.out.print(line); //若是遇到了一個單獨的回車換行,則表示請求頭結束 } while (!line.equals("\r\n")); //--輸消息的體 System.out.print(readLine(is, contentLength)); //關閉流 is.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /* * 這裏咱們本身模擬讀取一行,由於若是使用API中的BufferedReader時,它是讀取到一個回車換行後 * 才返回,不然若是沒有讀取,則一直阻塞,直接服務器超時自動關閉爲止,若是此時還使用BufferedReader * 來讀時,由於讀到最後一行時,最後一行後不會有回車換行符,因此就會等待。若是使用服務器發送回來的 * 消息頭裏的Content-Length來截取消息體,這樣就不會阻塞 * * contentLe 參數 若是爲0時,表示讀頭,讀時咱們仍是一行一行的返回;若是不爲0,表示讀消息體, * 時咱們根據消息體的長度來讀完消息體後,客戶端自動關閉流,這樣不用先到服務器超時來關閉。 */ private static String readLine(InputStream is, int contentLe) throws IOException { ArrayList lineByteList = new ArrayList(); byte readByte; int total = 0; if (contentLe != 0) { do { readByte = (byte) is.read(); lineByteList.add(Byte.valueOf(readByte)); total++; } while (total < contentLe);//消息體讀還未讀完 } else { do { readByte = (byte) is.read(); lineByteList.add(Byte.valueOf(readByte)); } while (readByte != 10); } byte[] tmpByteArr = new byte[lineByteList.size()]; for (int i = 0; i < lineByteList.size(); i++) { tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue(); } lineByteList.clear(); return new String(tmpByteArr, encoding); } }
上面都是採用的是io;由於NIO的緣故 這些代碼都不是本身寫的;後面準備本身寫NIO的實現;(就這一點東東就花了了我一天時間 真心傷不起呀;基礎 基礎 基礎夯實真的很重要) 在此記錄以備後用