網絡程序設計基礎
? ? ? ? 網絡程序設計編寫的是與其他計算機進行通信的程序。Java 已經將網絡程序所需要的元素封
裝成不同的類,用戶只要創建這些類的對象,使用相應的方法,即使不具備有關的網絡支持,也可
以編寫出高質量的網絡通信程序。
局域網與互聯網
? ? ? ? 為了實現兩臺計算機的通信,必須用一個網絡線路連接兩臺算計。
?服務器是指提供信息的計算機程序
客戶機是指請求信息的計算機或程序
網絡用于連接服務器與客戶機,實現兩者的相互通信。但是,有時在某個網絡中很難將服務器與客戶機區分開。局域網 (LAN) 是一群通過一定形式連接起來的計算機,它可以由兩臺計算機組成,也可以由同一區域內地上千臺計算機組成。將 LAN 延伸到更大的范圍,這樣的網絡成為廣域網(WAN)。互聯網是由無數的 LAN 和 WAN 組成的。
網絡協議
? ? ? ? 網絡協議規定了計算機之間連接的物理、機械(網絡與網卡的連接規定)、電氣(有效的電平范圍)等特征,計算機之間的相互尋址規則,數據發送沖突的解決方式,長數據如何分段傳送與接收等內容。
? IP協議
? ? ? ? IP 是 Internet Protocol 的簡稱,是一種網絡協議。Internet 網絡采用的協議是 TCP/IP協議。TCP/IP 模式是一種層次結構,共分為 4 層,分別為應用層、傳輸層、互聯網層和網絡層。各層實現特定的功能,提供特定服務和訪問接口,并具有相對的獨立性。
TCP/IP 協議
在TCP/IP 協議棧中有兩個高級協議 :
傳輸控制協議(TCP)
用戶數據報協議(UDP)
端口域套接字
? ? ? ? 一般而言,一臺計算機只有單一的連接到網絡的物理連接,所以的數據讀通過此連接對內、
對外送達特定的計算機,這就是端口。網絡程序設計的端口(port)并非真實的物理存在,而是一
個假想的連接裝置。
? ? ? ? 網絡程序中的套接字(Socket)用于將應用程序 與端口連接起來。套接字是一個假想的連接裝置,就像插座一樣可以連接電器與電線。
TCP 程序
????????TCP 網絡程序設計是利用 Socket 類編寫通信程序。利用 TCP 協議進行通信的兩個應用程序是有主次之分的,一個稱為服務器程序,另一個稱為客戶機程序,兩者的功能和編寫方法大不一樣。
InterAddress 類
? ? ? ? java.net 包中的?InterAddress 類是與 IP 地址相關的類,利用該類可以獲取 IP 地址、主機地址等信息。
例題21.1:
import java.net.*;public class Demo21_1 {public static void main(String[] args) {InetAddress ip;//創建InetAddress對象try {//捕捉異常ip=InetAddress.getLocalHost();//實例化對象String ming=ip.getHostName();//獲取本機名String dizi=ip.getHostAddress();//獲取本機地址System.out.println("本機名:"+ming);//輸出本機名System.out.println("本機IP地址:"+dizi);//將本機IP地址輸出} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();//輸出異常}}}
結果:
ServerSocket 類
? ? ? ? ? java.net 包中的 ServerSocket 類用于表示服務器套接字,其主要功能是等待來自網絡上的
“請求”,它可以通過指定的端口來等待連接的套接字。服務器套接字一次可以與一個套接字。如果
多臺客戶機同時提供出連接請求,服務器套接字會將請求連接的客戶機存入列隊中,然后從中取出
一個套接字,與服務器新建的套接字連接起來。若請求連接大于最大容納數,則多出的連接請求被
拒絕。隊列的默認大小是 50。
? ? ? ? ServerSocket 類的構造方法通常會拋出 IOException 異常,具體有以下幾種形式:
- ServerSocket(): 創建非綁定服務器套接字。
- ServerSocket(int port): 創建綁定到特定端口的服務器套接字。
- ServerSocket(int port,int backlog): 利用指定的 backlog 創建服務器套接字,并將其綁定到指定的本地端口號上。
- ServerSocket(int port,int backlog,InetAddress bindAddress): 使用指定的端口、偵聽 backlog 和要綁定到的本地 IP 地址創建服務器。這種情況適用于計算機上有多塊網卡和多個IP 地址的情況,用戶可以明確規定 ServerSocket 在哪塊網卡或哪個 IP 地址上等待客戶的連接請求。
TCP 網絡程序設計
例題21.2:創建 TCP/IP 協議服務器,本實例是一個 TCP服務器端程序。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Demo21_2 {private ServerSocket s;//服務器套接字private Socket sk;//客戶端套接字void start() {//啟動服務器try {s=new ServerSocket(8998);//服務器啟用8998端口System.out.println("服務器套接字已經創建成功");while(true) {System.out.println("等待客戶機的接入");sk=s.accept();//監聽客戶機的連接BufferedReader r=new BufferedReader(new InputStreamReader(sk.getInputStream()));while(true) {//循環接收信息String m=r.readLine();//讀取一行文本if("退出".equals(m)) {//如果客戶機發來的內容為退出System.out.println("客戶機退出");break;//停止接收信息}System.out.println("客戶機"+m);}r.close();//關閉流sk.close();//關閉套接字}}catch(IOException e) {e.printStackTrace();}}public static void main(String[] args) {Demo21_2 tcp=new Demo21_2();tcp.start();//啟動服務器}}
結果:
運行服務器端程序,將輸出提示信息,等待客戶呼叫。下面再來看一下客戶端程序。
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;public class Demo21_2_2 extends JFrame{private PrintWriter w;//字符輸出流Socket s;//客戶端套接字private JTextArea area=new JTextArea();//文本域private JTextField text=new JTextField();//文本框public Demo21_2_2() {setTitle("向服務器送數據");setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Container c=getContentPane();//主容器JScrollPane scrollPane=new JScrollPane(area);//滾動面板getContentPane().add(scrollPane,BorderLayout.CENTER);c.add(text,"South");//將文本框放到窗體下部text.addActionListener(new ActionListener() {//文本框觸發回車事件public void actionPerformed(ActionEvent e) {w.println(text.getText().trim());//將文本框的信息寫入流area.append(text.getText()+"\n");//將文本框的信息顯示在文本域中text.setText("");//將文本框清空}});}public void c() {//連接服務器方法area.append("嘗試連接\n");//文本域中提示信息try {s=new Socket("127.0.0.1",8998);//連接本地計算機的端口8998w=new PrintWriter(s.getOutputStream(),true);area.append("完成連接\n");}catch(IOException e) {e.printStackTrace();}}public static void main(String[] args) {Demo21_2_2 c=new Demo21_2_2();c.setSize(200, 200);//窗體大小c.setVisible(true);//是否顯示c.c();//連接服務器}}
結果:
UDP 程序
? ? ? ? 用戶數據報協議 (UDP) 是網絡信息傳輸的另一種形式。基于 UDP 的通信和基于 TCP 的通信基于 UDP的信息傳遞更快,但不提供可靠性保證。使用 UDP 傳遞數據時,用戶無法知道數據能否正確地到達主機,也不能確定到達目的地的順序是否和發送相同。雖然 UDP 是一種不可靠的員議,但如果需要較快地傳輸信息,并能容忍小的錯誤,可以考慮使用 UDP。
? ? ? ? 基于 UDP 通信的基本模式如下:
將數據打包 (稱為數據包),然后將數據包發往目的地。
?接收別人發來的數據包,然后查看數據包。
? ? ? ? ?發送數據包的步驟如下:
使用 DatagramSocket() 創建一個數據包套接字。
使用 DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)創建要發送的
數據包。
使用 DatagramSocket 類的 send() 方法發送數據包。
? ? ? ? 接收數據包的步驟如下:
使用 DatagramSocket(int port) 創建數據包套接字,綁定到指定的端口。
使用 DatagramPacket(byte[]buf,int length) 創建字節數組來接收數據包。
使用 DatagramPacket 類的 receive() 方法接收UDP包。
DatagramPacket 類
? ? ? ? java.net 包的 DatagramPacket 類用來表示數據包。DatagramPacket 類的構造方法如下:
DatagramPacket(byte[] buf, int length)
DatagramPacket(byte[] buf, int length, InetAddress address, int port).
? ? ? ? ?第一種構造方法在創建 DatagramPacket 對象時,指定了數據包的內存空間和大小。第二種構造方法不僅指定了數據包的內存空間和大小,還指定了數據包的目標地址和口、在發送數據時,必須指定接收方的 Socket 地址和端口號,因此使用第二種構造方法可創建發送數據的 DamgramPacket 對象。
DatagramSocket 類
? ? ? ? javanet 包中的 DatagramSocket 類用于表示發送和接收數據包的套接字。該類的構造方法如下:
DatagramSocket()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress addr)
? ? ? ? 第一種構造方法創建 DatagramSocket 對象,構造數據報套接字,并將其綁定到本地主機任何可用的端口上。第二種構造方法創建 DatagramSocket 對象,創建數據報套字,并將其綁定到本地主機的指定端口上。第三種構造方法創建 DatagramSocket 對象,創建數據報套接字,并將其綁定到指定的端口和指定的本地地址上。第三種構造函數適用于有多塊網卡和多個 IP 地址的情況。?
UDP 網絡程序設計
例題21.3:創建 UDP 協議廣播電臺程序,廣播主機程序不斷地向外播出信息。
?
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class Demo21_3 extends Thread{String weather="節目預報:八點有大型晚會,請收聽";int port=9898;InetAddress iaddress=null;MulticastSocket socket=null;Demo21_3(){try {iaddress=InetAddress.getByName("224.225.10.1");socket=new MulticastSocket(port);socket.setTimeToLive(1);socket.joinGroup(iaddress);}catch(IOException e) {e.printStackTrace();}}public void run() {while(true) {DatagramPacket packet=null;byte date[]=weather.getBytes();packet=new DatagramPacket(date,date.length,iaddress,port);System.out.println(weather);try {socket.send(packet);sleep(3000);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}public static void main(String[] args) {Demo21_3 w=new Demo21_3();w.start();}}
結果:
接收數據程序。代碼如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;public class Demo21_3_2 extends JFrame implements Runnable,ActionListener{int port=9898;InetAddress group=null;MulticastSocket socket=null;JButton inceBth=new JButton("開始接收");JButton stopBth=new JButton("停止接收");JTextArea inceAr=new JTextArea(10,10);JTextArea inced=new JTextArea(10,10);Thread thread;boolean stop=false;public Demo21_3_2() {setTitle("廣播數據");setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);thread=new Thread(this);inceBth.addActionListener(this);stopBth.addActionListener(this);inceAr.setForeground(Color.blue);JPanel north=new JPanel();north.add(inceBth);north.add(stopBth);add(north,BorderLayout.NORTH);JPanel center=new JPanel();center.setLayout(new GridLayout(1,2));center.add(inceAr);center.add(inced);add(center,BorderLayout.CENTER);validate();try {group=InetAddress.getByName("224.225.10.1");socket=new MulticastSocket(port);socket.joinGroup(group);}catch(IOException e) {e.printStackTrace();}setBounds(100,50,360,380);setVisible(true);}public void run() {while(!stop) {byte date[] = new byte[1024];DatagramPacket packet=null;packet=new DatagramPacket(date,date.length,group,port);try {socket.receive(packet);String message=new String(packet.getData(),0,packet.getLength());inceAr.setText("正在接收內容:\n"+message);inced.append(message+"\n");}catch(IOException e) {e.printStackTrace();}}}public void actionPerformed(ActionEvent e) {if(e.getSource()==inceBth) {inceBth.setBackground(Color.red);stopBth.setBackground(Color.yellow);if(!(thread.isAlive())) {thread=new Thread(this);}thread.start();stop=false;}if(e.getSource()==stopBth) {inceBth.setBackground(Color.yellow);stopBth.setBackground(Color.red);stop=true;}}public static void main(String[]args) {Demo21_3_2 rec=new Demo21_3_2();rec.setSize(460, 200);}
}