本文介紹網絡相關理論和簡單入門的Java網絡編程例子
這篇文章主要介紹計算機網絡的一個整體架構和每一層的作用。
- 計算機網絡的概念
- OSI參考模型
- TCP/IP參考模型
- IP協議
- TCP協議和端口
- Java網絡編程入門程序
計算機網絡的概念
網絡,就是不同節點之間通過連線互聯起來的一個事物。以此類推,計算機網絡,就是將不同地理位置的計算機通過通信線路連接起來的一個具有強大功能的網絡系統。在這個網絡中每臺電腦就是一個節點。
OSI參考模型
OSI(Open System Interconnection)是由ISO組織研究的一套網絡體系結構。這名字起的好
各層的名稱和作用,當做瞭解:
名稱 | 功能 |
---|---|
物理層 | 不要理解錯了,這一層不包含什麼網線、電纜的物理介質。這裏只是規定網線和電纜的接口類型,信號電壓等。使用bit傳輸 |
數據鏈路層 | 負責兩個相鄰節點間的路線,以幀爲單位傳輸。典型設備交換機(Switch) |
網絡層 | 兩臺計算機傳輸數據可能會經過很多數據鏈路,網絡層的作用就是選擇最優的路線。典型設備就是路由器 |
傳輸層 | 提供兩個端系統的會話的建立、維護和取消傳輸連接的功能。使用報文傳輸 |
會話層 | 管理進程間的會話過程,即建立、管理、終止進程間的會話。使用報文傳輸 |
表示層 | 對數據的加解密、解壓縮和格式轉換等。 |
應用層 | 這層就是和用戶的具體應用交互。例如:收發E-mail等。 |
TCP/IP參考模型
因爲OSI網絡結構分層太多過於複雜,所以TCP/IP協議橫空出世。TCP/IP協議同樣藉助了OSI的分層思想,但是隻是分爲四層:
名稱 | 功能 |
---|---|
主機網絡層 | 爲上層提供一個訪問接口 |
網絡互聯層 | 把IP數據包發送到目標主機。這一層使用的是IP協議,IP協議規定了數據包的格式,並且規定了爲數據包尋找路由的流程。 |
傳輸層 | 使源主機和目標主機的進程可以進行會話。這一層定義了兩種協議TCP和UDP協議。 |
應用層 | TCP/IP模型將OSI參考模型中的會話層和表現層功能合併到應用層。 |
基於TCP協議的應用主要有以下幾種:
• FTP:文件傳輸協議,允許在網絡上傳輸文件。
• TELNET:虛擬終端協議,允許從主機A登入遠程主機B。
• HTTP:超文本傳輸協議,允許網絡是傳輸超文本。
• HTTPS:安全超文本傳輸協議。
• POP3:允許用戶訪問和操作運程服務器上的郵件和郵件夾。
• IMAP4:消息訪問協議版本4,允許用戶訪問和操作運程服務器上的郵件和郵件夾。
• SMTP:發送郵件的協議。
基於UDP協議的應用層協議:
• SNMP:簡單網絡管理協議,爲管理本地和遠程的網絡設備提供了一個標準化途徑,是分佈式環境中的集中化管理協議。
• DNS:域名系統協議,把主機的域名轉換爲對應的IP地址。
IP協議
IP網絡(採用IP協議的網絡)中每一臺主機都有唯一的IP地址,IP地址標識網絡中的每個主機。IP地址是一個32位的二進制數序列。例如:192.168.3.4
。IP地址與子網掩碼進行與運算得到的是網絡地址。如果子網掩碼爲255.255.255.0
那網絡地址就是:192.168.3.0
發送數據包的過程
IP是面向包的協議,即數據被分成若干小數據包,然後分別傳輸它們。IP網絡上的主機只能直接向本地網上的其他主機(也就是具有相同IP網址的主機)發送數據包。主機實際上具有兩個不同性質的真實地址。主機A向同一個網絡上的另一個主機B發包時,會通過地址解析協議(ARP,Address Resolution Protocol)獲得對法的物理地址,然後把包給對方。ARP協議的運行機制爲,主機A在網絡上廣播一個ARP消息:”要找地址爲192.166.3.5的主機”,具有這個IP地址的主機B就會作響應,把自身的物理地址告訴A。
當主機A向另外一個網絡的主機B發送包時:
主機A利用ARP協議找到本地網絡上的路由器的物理地址,把包轉給路由。路由器按照如下步驟處理數據包:
- 如果數據包的生命週期已到,則數據包被拋棄。
- 搜索路由表,優先搜索路由表中的主機,如果找到具有目標IP地址的主機,則將數據包發給該主機。
- 如果匹配主機失敗,則繼續搜索路由表,匹配子網的路由表,如果找到匹配的路由表,則將數據包轉發給該路由器。
- 如果匹配同子網的路由器失敗,則繼續搜索路由表,匹配同網絡的路由器,如果找到匹配的路由器,則將數據包轉發給該路由器。
- 如果以上匹配都失敗,就搜索默認路由,如果默認路由存在,則按照默認路由發送數據包,否則丟棄數據包。
流程圖如下:
域名
IP是一串數字沒有任何意義。域名就是與IP對應的有意義的一串字符或數字。例如:www.google.com
域名和IP的對應需要一個域名解析系統來實現將域名轉換成IP。DNS服務器就是就可以解決這個問題。
URL(統一資源定位符)
URL(Uniform Resource Location)是專門標識網絡上資源位置而設置的一種編址方式。URL一般由3個部分組成:
應用層協議://主機IP地址或域名/資源所在路徑/資源名
例如:http://blog.csdn.net/facekbook/article/details/54962975
其中http
指超文本傳輸協議,blog.csdn.net
是Web服務器的域名,/article/details/
是網頁所在路徑,54962975
這個纔是相應的網頁文件。
TCP協議和端口
IP協議在發送數據時,在數據傳輸過程中會出現各種問題。導致包丟失或包的順序不對。TCP協議使兩臺主機上的進程順利通信,不必擔心包丟失或包順序不對。TCP跟蹤包順序,如果包順序被搞亂時按照正確的順序進行重新組合。如果包丟失,則TCP會請求源主機重發包。
端口
TCP協議使兩臺主機上的進程順利通信,但是主機不止一個進程。TCP就採取端口來區分進程。端口不是物理設備,而是用於標識進程的邏輯地址。計算機的端口範圍是0到65535,其中0到1023的端口一般固定分配給一些服務。具體如下:
服務 | 端口 | 協議 |
---|---|---|
文件傳輸服務 | 21 | FTP |
遠程登錄服務 | 23 | TELENET |
郵件傳輸服務 | 25 | SMTP |
萬維網超文本傳輸服務 | 80 | HTTP |
訪問郵件遠程郵件服務 | 110 | POP3 |
互聯網消息存取服務 | 143 | IMAP4 |
安全的超文本傳輸服務 | 443 | HTTPS |
安全的遠程登錄服務 | 992 | TELNETS |
安全互聯網消息存取服務 | 993 | IMAPS |
Java網絡編程入門程序
Java網絡程序都建立在TCP/IP協議基礎上,在應用層實現。傳輸層嚮應用層提供了套接字Socket接口,Socket封裝了下層的數據傳細節,應用層的程序通過Socket來建立與遠程主機的連接,以及數據傳輸,如下圖所示:
在Java中,有3種套接字類:java.net.Socket
、java.net.ServerSocket
和 java.net.DatagramSocket
。其中Socket
和 ServerSocket
建立在TCP協議上,DatagramSocket
類建立在UDP協議基礎上。我們創建EchoServer和EchoClient兩個類,我們通過ServerSocket
和Socket
來編寫。
創建EchoServer類
在服務端通過一直監聽端口,來接收客戶程序的連接請求。在服務器程序中,先創建一個ServerSocket
對象,在構造方法中指定監聽的端口:
ServerSocket server = new ServerSocket(8080);
ServerSocket
構造器負責在操作系統中將當前進程註冊爲服務進程。服務器程序調用ServerSocket
的accept()
方法來監聽端口,等待客戶端的連接,如果接收到連接,則accept()
方法返回一個Socket
對象,這個Socket
對象與客戶端的Socket
對象形成了一條通信線路:
Socket socket = server.accept();
Socket提供了getInputStream()方法和getOutputStream()方法,分別返回輸入流InputStream對象和輸出流OutputStream對象。程序只需向輸出流寫入東西,就能向對方發送數據;只需從輸入流讀取數據,就能接收到數據。如下圖:
EchoServer
類代碼如下:
/**
* 服務端 服務端類
*
*/
public class EchoServer {
private ServerSocket serverSocket;
public EchoServer(int port) {
try {
this.serverSocket = new ServerSocket(port);
System.out.println("start server success,start port:"+port);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 獲取BufferedReader包裝類
*
* @param socket
* @return
* @throws IOException
*/
private BufferedReader getReader(Socket socket) throws IOException {
return new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
/**
* 獲取PrintWriter包裝類,
*
* @param socket
* @return
* @throws IOException
*/
private PrintWriter getWriter(Socket socket) throws IOException {
// 每寫一行自動刷新
return new PrintWriter(socket.getOutputStream(), true);
}
public void service() {
while (true) {
Socket socket = null;
try {
socket = serverSocket.accept();
System.out.println("new connect,address is:" + socket.getInetAddress() + " port is:" + socket.getPort());
BufferedReader reader = getReader(socket);
PrintWriter writer = getWriter(socket);
String msg = null;
while ((msg = reader.readLine()) != null) {
// 讀取一行
System.out.println("client request msg: " + msg);
writer.println(echo(msg));
if ("bye".equalsIgnoreCase(msg)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(socket!=null){
try {
//關閉會話連接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private String echo(String msg) {
return "get request msg is '" + msg+"'";
}
public static void main(String[] args) {
new EchoServer(8080).service();
}
}
EchoServer
類的最主要的方法就是service()
方法,它不斷登錄客戶的連接請求。當serverSocket.accept()
返回一個Socket
對象時,表示與一個客戶端建立了連接。
創建EchoClient
類
在EchoClient程序中,爲了與EchoClient通信,需要先創建一個Socket對象:
String host="localhost";
int port = 8080;
new Socket(host, port);
host表示Server進程所在服務器的地址,port表示Server進程監聽的端口。當參數host爲’localhost’時,表示服務端和客戶端在同一臺機器上。下面是EchoClient
類的源碼:
public class EchoClient {
private Socket socket;
public EchoClient(String host,int port){
try {
this.socket = new Socket(host, port);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 獲取BufferedReader包裝類
*
* @param socket
* @return
* @throws IOException
*/
private BufferedReader getReader(Socket socket) throws IOException {
return new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
/**
* 獲取PrintWriter包裝類,
*
* @param socket
* @return
* @throws IOException
*/
private PrintWriter getWriter(Socket socket) throws IOException {
// 每寫一行自動刷新
return new PrintWriter(socket.getOutputStream(), true);
}
public void talk(){
try {
BufferedReader reader = getReader(socket);
PrintWriter writer = getWriter(socket);
BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while((msg=localReader.readLine())!=null){
writer.println(msg);
System.out.println("server response msg:"+reader.readLine());
if("bye".equalsIgnoreCase(msg)){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(socket!=null){
try {
socket.close();
System.out.println("has been disconnected");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new EchoClient("localhost", 8080).talk();
}
}
在EchoClient類中最重要的是talk()方法,該方法不斷讀取用戶從控制檯輸入的字符串,然後將它發送到EchoServer,在把EchoServer返回的數據打印在控制檯。如果輸入’bye’字符串,就會結束與EchoServer的通信,調用socket.close()方法端口連接。
具體運行如下圖,一個是服務端一個是客戶端的控制檯:
總結
簡單介紹了一下網絡的理論知識和TCP/IP協議。並使用Java實現了一個網絡通信程序。