1. 程式人生 > >Java 網路程式設計 Java中的網路程式設計

Java 網路程式設計 Java中的網路程式設計

說道網路程式設計,瞭解socket程式設計,分為TCP和UPD,對於具體實現細節,就不知道。希望學完這一塊,自己能夠獨立完成一個socket的編寫。

 關於網際網路WEB相關的知識點,後面開始總結,今天不在此作介紹。

Socket套接字:網路上具有唯一標識的IP地址和埠組合在一起才能構成唯一能識別的識別符號套接字。

Socket原理機制:

通訊的兩端都有Socket,網路通訊其實就是Socket間的通訊,資料在兩個Socket間通過IO傳輸。

Java中的網路支援:針對網路通訊的不同層次,Java提供了不同的API,其提供的網路功能有四大類:

InetAddress:用於標識網路上的硬體資源,主要是IP地址

URL:統一資源定位符,通過URL可以直接讀取或寫入網路上的資料。

Sockets:使用TCP協議實現的網路通訊Socket相關的類

Datagram:使用UPD協議,將資料儲存在使用者資料中,通過網路進行通訊。

1:InetAddress

標識網路上的硬體資源,沒有構造方法(預設都沒有),標識網際網路協議IP地址

 1 package lesson1220Socket;
 2 
 3 import java.net.InetAddress;
 4 import java.net.UnknownHostException;
 5 
 6 public class InetAddressDemo {
7 8 public static void main(String[] args) throws UnknownHostException { 9 InetAddress address = InetAddress.getLocalHost(); 10 11 //InetAddress ad = new InetAddress(); The constructor InetAddress() is not visible 12 13 byte [] by = address.getAddress(); //實際上裡面存的值是[100, 98, 60, 87]
14 System.out.println(by); 15 System.out.println(address.getHostAddress()); 16 System.out.println(address.getHostName()); 17 return; 18 } 19 }

執行結果:

[[email protected]
100.98.60.87
CN00204505

2、URL類

統一資源定位符,標識Internet上某一資源的地址,

 

Java中的網路程式設計

 Java中的網路程式設計主要是Java的Socket程式設計,屬於JavaEE中的高階的部分,以下內容是對java網路程式設計的一個小結,程式碼都是經過編譯除錯的

 

  C/S程式應用:客戶/伺服器模式,如QQ客戶端,客戶端連到伺服器上,一個C/S模式的應用必須有兩套程式,一個是客戶端的程式,一個是伺服器程式。

  B/S程式應用:瀏覽器/伺服器模式,如當下的各種網站都是B/S模式,所有的程式程式碼都在伺服器上,使用者通過瀏覽器去訪問。

 

C/S程式分為兩種:

        基於TCP協議:Socket(套接字), 可靠的程式設計: A->B 如打電話先建立連線

        基於UDP協議:不可靠,如簡訊功能。

如果編寫一個TCP程式需要JAVA的兩個包支援:

        java.net.*: 主要提供網路支援;

                |-ServerSocket類:伺服器端程式

                |-Socket類:客戶端程式

        java,io.*:傳遞資訊流

3、TCP程式設計

TCP協議是面向連線的、可靠的、有序的、以位元組流的方式傳送資料。通過三次握手方式建立連線。形成傳輸資料的通道。在連線中進行大量資料的傳輸,效率會稍低。

Java中基於TCP協議實現網路通訊的類:客戶端是Socket, 伺服器端是ServerSocket。

 看上面圖,可以看出Socket通訊步驟:建立ServerSocket和Socket,開啟連線到Socket的輸入輸出流,按照協議對Socket進行讀寫操作,關閉輸入輸出流,關閉Socket。

3.1 伺服器端:

a:建立ServerScoket,並繫結埠

b:呼叫accept()開始監聽埠

c:建立連線後,通過輸入流獲取客戶端傳送的請求資訊

d:通過輸出流向客戶端返回響應資訊

e:關閉Socket等相關資源

3.2 客戶端:

a:建立Socket,並指定需要連線的伺服器的IP和埠

b:建立連線後,通過輸出流向伺服器端傳送資訊

c:通過輸入流獲取伺服器返回的響應資訊

d:關閉Socket等資源

例子如下:

  1 package lesson1220Socket;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.InputStreamReader;
  7 import java.io.OutputStream;
  8 import java.io.PrintWriter;
  9 import java.net.ServerSocket;
 10 import java.net.Socket;
 11 
 12 import com.sun.org.apache.xalan.internal.xsltc.trax.OutputSettings;
 13 
 14 //基於TCP/IP協議的Socket,使用者實現登入伺服器端
 15 public class ServeSocketDemo {
 16     public static void main(String[] args) throws Exception {
 17         
 18         //1、建立一個ServerSocket服務端,指定繫結的埠,並監聽埠
 19         ServerSocket ss = new ServerSocket(10086);   //1024-65535的某個值
 20         System.out.println("伺服器端開始監聽10086埠.....");
 21         //2、呼叫accept方法開始監聽埠
 22         Socket socket = ss.accept();
 23         
 24         //3、獲取輸入流,並讀取客戶端資訊
 25         InputStream is = socket.getInputStream();
 26         InputStreamReader isr = new InputStreamReader(is);   //InputStreamReader
 27         BufferedReader br = new BufferedReader(isr);
 28         
 29         String info = null;
 30         while((info = br.readLine())!=null){
 31             System.out.println("我是伺服器,客戶端說:"+info);            
 32         }
 33         socket.shutdownInput();
 34         
 35         //4、獲取輸出流,響應客戶端請求
 36         OutputStream os = socket.getOutputStream();
 37         PrintWriter pw = new PrintWriter(os);
 38         pw.write("歡迎您");        
 39         pw.flush();
 40         System.out.println("給客戶端迴響應.....");
 41         
 42         //5、關閉資源
 43         pw.close();
 44         os.close();
 45         br.close();
 46         isr.close();
 47         is.close();
 48         socket.close();
 49         ss.close();
 50         
 51     }
 52 
 53 }
 54 
 55 
 56 package lesson1220Socket;
 57 
 58 import java.io.BufferedReader;
 59 import java.io.IOException;
 60 import java.io.InputStream;
 61 import java.io.InputStreamReader;
 62 import java.io.OutputStream;
 63 import java.io.PrintWriter;
 64 import java.net.Socket;
 65 import java.net.UnknownHostException;
 66 
 67 public class ClientSocketDemo {
 68 
 69     public static void main(String[] args) throws UnknownHostException, IOException {
 70         //1、建立客戶端Socket,指定伺服器和埠
 71         Socket cs = new Socket("127.0.0.1", 10086);
 72         System.out.println("與服務端建立連線.....");
 73         
 74         //2、獲取輸出流,向伺服器傳送資訊
 75         OutputStream os = cs.getOutputStream();//直接輸出流
 76         PrintWriter pw = new PrintWriter(os);
 77         pw.write("使用者名稱:admin,密碼:123");
 78         pw.flush();
 79         cs.shutdownOutput();
 80         System.out.println("向服務端傳送資訊.....");
 81         
 82         //3、獲取輸入流,得到伺服器響應資訊
 83         InputStream is = cs.getInputStream();
 84         InputStreamReader isr = new InputStreamReader(is);
 85         BufferedReader br = new BufferedReader(isr);
 86         String info;
 87         while((info = br.readLine())!=null){
 88             System.out.println("我是客戶端,服務端響應資訊:"+info);            
 89         }
 90         
 91         //4、關閉資源
 92         br.close();
 93         isr.close();
 94         is.close();
 95         pw.close();
 96         os.close();
 97         cs.close();            
 98 
 99     }
100 
101 }

上面先執行服務端:ServeSocketDemo,再啟動客戶端:ClientSocketDemo

執行結果如下:

ServeSocketDemo:

伺服器端開始監聽10086埠.....
我是伺服器,客戶端說:使用者名稱:admin,密碼:123
給客戶端迴響應.....
ClientSocketDemo:

與服務端建立連線.....
向服務端傳送資訊.....
我是客戶端,服務端響應資訊:歡迎您

 

 

 

 

 

4、UDP程式設計

前面介紹的Socket程式設計都是基於TCP/IP協議的,現在來看一下基於UDP協議程式設計。

UPD協議(使用者資料報協議)是無連線的、不可靠的、無序的,速度快。進行資料傳輸時,首先將要傳輸的資料定義成資料報(Datagram),大小限制在64k,在資料報中指明資料索要達到的Socket(主機地址和埠號),然後再將資料報傳送出去。UDP協議的主要作用就是完成網路資料流和資料包之間的轉換-------在資訊傳送端,UDP協議將網路資料流封裝到資料報,然後被資料報傳送出去;在資訊接收端,UDP協議將資料報轉換成實際資料內容。

1>首先在UDP網路程式設計中沒有伺服器和客戶端這種說法,兩個Socket之間沒有虛擬鏈路。只是接收和傳送報文

2>這裡面有兩個重要的類:DatagramSocket和DatagramPacket.

DatagramSocket的兩個建構函式:

public DatagramSocket():構造資料報套接字並將其繫結到本地主機上任何可用的埠。

public DatagramSocket(int port):建立資料報套接字並將其繫結到本地主機上的指定埠。

在我們下面的DEMO中,UDPServerTest類中先發送資料報,使用的是套接字的無參構造器,而UDPClientTest類中先接收資料報,必須監聽某一個埠,所以使用的是套接字的有參構造器。

DatagramPacket的建構函式:

public DatagramPacket(byte buf[], int length):用來接收長度為length的資料包

public DatagramPacket(byte buf[], int length, InetAddress address, int port):用來將長度為length的包傳送到指定主機上的指定埠號。

package lesson1220Socket;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UDPServer2 {

    public static void main(String[] args) throws Exception {
        DatagramSocket ds = new DatagramSocket();
        String str = "hello world";
        //構造用於傳送的資料包,指定主機和埠號
        DatagramPacket packet = new DatagramPacket(str.getBytes(),
                str.length(), InetAddress.getByName("localhost"), 5555);
        ds.send(packet);
        
        //讀取從客戶端傳送過來的響應
        byte[] buffer = new byte[1024];
        DatagramPacket packet2 = new DatagramPacket(buffer,buffer.length);
        ds.receive(packet2);
        System.out.println("address: " + packet2.getAddress() + " port: "+ packet2.getPort());
        String str2 = new String(buffer,0,packet2.getLength());
        System.out.println(str2);
        ds.close();
    }

}

package lesson1220Socket;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UDPClient2 {

    public static void main(String[] args) throws Exception {
        DatagramSocket ds = new DatagramSocket(5555);
        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        ds.receive(packet);
        System.out.println("address: " + packet.getAddress() + " port: "+ packet.getPort());
        String str = new String(buffer, 0, packet.getLength());
        System.out.println(str);

        // 接收到資料包之後,客戶端返回響應回去
        String str2 = "welcome";
        DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2
                .length(), packet.getAddress(), packet.getPort());
        ds.send(packet2);
        ds.close();
    }

}

上面的例子,要先執行UDPClient2(接收端先啟動) ,然後再執行UDPServer2

執行結果如下:

UDPServer2

address: /127.0.0.1 port: 5555
welcome

UDPClient2

address: /127.0.0.1 port: 54071
hello world

1、上面的程式中,第一步是伺服器端(暫且以這種叫法來區分這兩個類)建立一個UDP套接字,沒有指定埠,使用的是系統分配的埠。然後構建了一個數據包,包中指定      了目標機器的ip和埠號。

2、作為客戶端,建立了一個UDP套接字,並且綁定了埠,如果想要接收到服務端傳送過來的報文,繫結的埠必須和伺服器端傳送的包中指定的埠一致。

3、客戶端列印了包中的內容之後,想要返回一些內容回去。這個時候,伺服器端的ip和埠號可以從之前傳送過來的資料包中獲取。

     DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2.length(), packet.getAddress(), packet.getPort());

4、在伺服器接收資料包的時候,已經不需要再像客戶端建立套接字一樣去繫結埠了,因為目前監聽的埠和客戶端傳送的包中指定的埠是一樣的。

5、列印看下伺服器端的ip和監聽的埠號:(注意理解下這個地方埠號,不是5555)

serverIp =/127.0.0.1;serverPort=54071

6、其中DatagramSocket的receive(DatagramPacket p)方法在接收到資料包前一直阻塞。

 

看下面這個例子:各自互動三次:

 1 package lesson1220Socket;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6 import java.net.SocketException;
 7 
 8 public class UDPServer {
 9 
10     public static void main(String[] args) throws Exception {
11         //1:建立伺服器端Socket,指定埠
12         DatagramSocket ds = new DatagramSocket(8888);
13         //2、建立資料報,用於接收客戶端傳送的資訊
14         byte [] data = new byte[1024];        
15         DatagramPacket dp = new DatagramPacket(data, data.length);
16         //3、接收客戶端傳送的資料
17         System.out.println("開始接收資料1111!");
18         ds.receive(dp);        
19         
20         //4、讀取資料
21         String info = new String(data, 0, dp.getLength());
22         System.out.println("我是服務端,收到客戶端的資訊是: "+info);
23         
24         
25         //5、像客戶端響應資料
26         //定義客戶端的地址、埠號和資料
27         InetAddress ia = dp.getAddress();
28         int port = dp.getPort();
29         System.out.println("dp ia: " + ia + " port: " + port);
30         //組裝傳送資料報
31         byte []data2 = "你好客戶端!".getBytes();
32         DatagramPacket dp2 = new DatagramPacket(data2, data2.length, ia, port);        
33         //響應客戶端
34         System.out.println("開始傳送資料2222!");
35         ds.send(dp2);
36         
37         
38         //6、接收客戶端第二次傳送的資料
39         System.out.println("開始接受資料3333!");
40         ds.receive(dp);
41         System.out.println("dp ia: " + dp.getAddress() + " port: " + dp.getPort());
42         
43         //7、讀取資料
44         info = new String(data, 0, dp.getLength());
45         System.out.println("我是服務端,收到第二次客戶端的資訊是: "+info);
46         
47         
48         ds.close();
49     }
50 
51 }
52 
53 package lesson1220Socket;
54 
55 import java.io.IOException;
56 import java.net.DatagramPacket;
57 import java.net.DatagramSocket;
58 import java.net.InetAddress;
59 import java.net.SocketException;
60 
61 import sun.io.ByteToCharCp1006;
62 
63 public class UDPClient {
64 
65     public static void main(String[] args) throws Exception {
66         
67         InetAddress ia = InetAddress.getLocalHost();
68         
69         //1:建立客戶端端Socket,指定埠和地址
70         DatagramSocket ds = new DatagramSocket();
71         //2、建立資料報,用於向伺服器端傳送資訊
72         byte [] data = "服務端你好".getBytes();        
73         DatagramPacket dp = new DatagramPacket(data, data.length, ia, 8888);        
74         //3、向伺服器端傳送資料
75         System.out.println("A開始傳送資料1111!");
76         ds.send(dp);
77         
78         
79         //4、讀取資料
80         byte [] data2 = new byte[1024];        
81         DatagramPacket dp2 = new DatagramPacket(data2, data2.length);
82         System.out.println("A開始接收資料2222!");
83         ds.receive(dp2);
84         
85         System.out.println("dp2 ia: " + dp2.getAddress() + " port: " + dp2.getPort());
86         String info = new String(data2, 0, dp2.getLength());
87         System.out.println("我是客戶端,伺服器回的資訊是: "+info);
88        
89         //5、第二次傳送資料
90         DatagramPacket dp3 = new DatagramPacket(data, data.length, dp2.getAddress(), dp2.getPort());    
91         System.out.println("A開始傳送資料3333!");
92         ds.send(dp3);
93         
94         ds.close();
95         
96     }
97 
98 }

上面這個程式先執行UDPServer, 再執行UDPClient。

執行結果:

UDPServer:

開始接收資料1111!
我是服務端,收到客戶端的資訊是: 服務端你好
dp ia: /100.98.19.103 port: 56013
開始傳送資料2222!
開始接受資料3333!
dp ia: /100.98.19.103 port: 56013
我是服務端,收到第二次客戶端的資訊是: 服務端你好

 UDPClient:

A開始傳送資料1111!
A開始接收資料2222!
dp2 ia: /100.98.19.103 port: 8888
我是客戶端,伺服器回的資訊是: 你好客戶端!
A開始傳送資料3333!

 

參考帖子:

https://www.cnblogs.com/dongguacai/p/5747603.html

https://www.cnblogs.com/dongguacai/p/5747397.html

 https://www.cnblogs.com/rocomp/p/4790340.html-------基礎講解

https://www.cnblogs.com/Qian123/tag/java%E5%9F%BA%E7%A1%80/default.html?page=3

 

https://www.cnblogs.com/yiwangzhibujian/p/7107785.html

https://blog.csdn.net/facekbook/article/details/55506347

其他基礎:

https://blog.csdn.net/hguisu/article/category/1122753

https://www.cnblogs.com/dolphin0520/category/602384.html

 

關於TCP/IP中更多的例子請看另一篇關於Socket多執行緒程式設計!