21.1 網絡程序設計基礎
Java網絡程序設計基礎涉及使用Java編程語言創建網絡應用程序。這通常涉及到使用Java的網絡API,如java.net包,以建立客戶端和服務器之間的通信。
基本步驟包括:
1.創建服務器: 使用ServerSocket類創建服務器,并通過accept()方法等待客戶端連接請求。
2.創建客戶端: 使用Socket類創建客戶端,并連接到服務器。
3.建立輸入輸出流: 使用InputStream和OutputStream類創建輸入和輸出流,以在客戶端和服務器之間傳遞數據。
4.處理數據: 在服務器端,通過輸入流接收客戶端發送的數據,并通過輸出流將響應發送回客戶端。
5.關閉連接: 當通信完成時,關閉連接,釋放資源。
21.1局域網與互聯網?
局域網(LAN)和互聯網(Internet)是兩種不同范圍的網絡,它們在覆蓋范圍、連接設備和應用方面有一些區別。
為了實現兩臺計算機的通信,必須用一個網絡線路連接兩臺計算機
21.1.2 網絡協議?
網絡協議是計算機網絡中用于在通信實體之間進行數據交換的一套規則和約定。它定義了數據的格式、傳輸方式、錯誤檢測等規范,確保在網絡中的設備能夠正確地進行通信。以下是一些常見的網絡協議:
TCP/IP協議: Transmission Control Protocol/Internet Protocol,是互聯網上的基本通信協議。包括TCP用于可靠數據傳輸和IP用于數據包路由。
HTTP協議: HyperText Transfer Protocol,用于在Web瀏覽器和Web服務器之間傳輸超文本的協議。通常用于獲取網頁、圖像等資源。
UDP協議: User Datagram Protocol,是一種無連接的傳輸協議,提供了不可靠的數據傳輸。常用于實時應用,如語音通話和視頻流。
21.1.3 端口與套接字
一般而言,一臺計算機只有單一的連到網絡的物理連接 (Physical Connection),所有的數據都通過此連接對內、對外送達特定的計算機,這就是端口。網絡程序設計中的端口(pot)并非真實的物理存在,而是一個假想的連接裝置。端口被規定為一個在0~65535 的整數。HTTP 服務一般使用 80 端口FTP服務使用21端口。假如一臺計算機提供了HTTP、FTP 等多種服務,那么客戶機會通過不同的端口來確定連接到服務器的哪項服務上,如圖21.3 所示。
通常,0~1023 的端口數用于一些知名的網絡服務和應用,用戶的普通網絡應用程序應該使用 1024以上的端口數,以避免端口號與另一個應用或系統服務所用端口沖突。
網絡程序中的套接字(Socket)用于將應用程序與端口連接起來。套接字是一個假想的連接裝置就像插座一樣可連接電器與電線,如圖 21.4所示。Java 將套接字抽象化為類,程序設計者只需創建 Socket類對象,即可使用套接字。
21.2 TCP程序?
TCP網絡程序設計是指利用 Socket 類編寫通信程序利用TCP協議進行通信的兩個應用程序是有主次之分的,一個稱為服務器程序,另一個稱為客戶機程序,兩者的功能和編寫方法大不一樣。服務系著與客戶端的交互過程如圖21.5 所示:
21.2.1?InetAddress類?
java.net 包中的 InetAddress 類是與 IP 地址相關的類,利用該類可以獲取 IP 地址、主機地址等信息.
InetAddress 類的常用方法如表 21.1 所示。
例題21.1:獲取計算機的本機名與IP地址?
package 二十一;import java.net.InetAddress;
import java.net.UnknownHostException;public class Address {public static void main(String[] args) {InetAddress ip;try {ip = InetAddress.getLocalHost();String localname = ip.getHostName();String localip = ip.getHostAddress();System.out.println("本機名:" + localname);System.out.println("本機IP地址:" + localip);}catch(UnknownHostException e){e.printStackTrace();}}}
21.2.2?ServerSocket類?
ServerSocket類是Java中用于實現服務器端套接字的類,用于監聽并接受客戶端的連接請求。以下是對ServerSocket的簡要概述:
1.創建服務器套接字: 通過構造函數可以創建一個服務器套接字,需要指定服務器端口號。
2.等待連接請求: 使用accept()方法阻塞等待客戶端連接請求。一旦有客戶端連接,該方法返回一個Socket對象,用于和該客戶端進行通信。
3.獲取輸入輸出流: 通過Socket對象獲取輸入流和輸出流,以便與客戶端進行數據交換。
4.關閉服務器套接字: 當不再接受新的連接時,使用close()方法關閉服務器套接字。
5.異常處理: 可能會拋出IOException等異常,需要進行適當的異常處理。
6.可選的構造函數: 除了上述基本的構造方法,還提供了一些其他構造方法,允許開發者指定綁定的IP地址、backlog(等待連接隊列的最大長度)等參數。
ServerSocket類通常作為服務器應用程序的入口點,通過它可以實現基于TCP協議的服務器,與客戶端進行雙向通信。這對于構建網絡應用程序,特別是服務器端的網絡服務是至關重要的。
?21.2.3 TCP網絡程序設計
明白了TCP 程序工作的過程,就可以編寫 TCP 服務器程序了。在網絡編程中,如果只要求客戶機疆務器發送消息,不要求服務器向客戶機發送消息,稱為單向通信。客戶機套接字和服務器套接字接成功后,客戶機通過輸出流發送數據,服務器則通過輸入流接收數據。下面是簡單的單向通信的實例
例題21.2:創建TCP/IP協議服務器
package 二十一;
import java.io.*;
import java.net.*;public class MyServer {private ServerSocket server; // 服務器套接字private Socket socket; // 客戶端套接字void start() {// 啟動服務器try {server = new ServerSocket(8998); // 服務器啟用8998端口System.out.println("服務器套接字已經創建成功");while (true) {System.out.println("等待客戶端的連接");socket = server.accept(); // 服務器監聽客戶端連接// 根據套接字字節流創建字符輸入流BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));while (true) {// 循環接受信息String message = reader.readLine();// 讀取一行文本if ("exit".equals(message)) {// 如果客戶端發來的內容為“exit”System.out.println("客戶端退出");break;// 停止接受信息}System.out.println("客戶端:" + message);}reader.close(); // 關閉流socket.close(); // 關閉套接字}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {MyServer tcp = new MyServer();tcp.start(); // 啟動服務器}
}
?
package 二十一;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.Socket;
import javax.swing.*;public class MyCllent extends JFrame {private PrintWriter writer;// 根據套接字字節流創建的字符輸出流Socket socket; // 客戶端套接字private JTextArea area = new JTextArea();// 展示信息的文本域private JTextField text = new JTextField(); // 發送信息的文本框public MyCllent() {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) {writer.println(text.getText().trim()); // 將文本框中的信息寫入流area.append(text.getText() + '\n'); // 將文本框中的信息顯示在文本域中text.setText(""); // 將文本框清空}});}private void connect() { // 連接服務器方法area.append("嘗試連接\n"); // 文本域中提示信息try {socket = new Socket("127.0.0.1", 8998); // 連接本地計算機的8998端口writer = new PrintWriter(socket.getOutputStream(), true);area.append("完成連接\n");} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {MyCllent clien = new MyCllent();clien.setSize(200, 200); // 窗體大小clien.setVisible(true); // 顯示窗體clien.connect(); // 連接服務器}
}
?
21.3 UDP程序?
用戶數據報協議(UDP) 是網絡信息傳輸的另一種形式。基于 UDP 的通信和基于 TCP 的通信不同,基于 UDP的信息傳遞更快,但不提供可靠性保證。使用 UDP 傳遞數據時,用戶無法知道數據能否正確地到達主機,也不能確定到達目的地的順序是否和發送的順序相同。雖然 UDP 是一種不可靠的協議,但如果需要較快地傳輸信息,并能容忍小的錯誤,可以考慮使用 UDP。
21.3.1?DatagramPacket類
DatagramPacket類是Java中用于表示數據報包的類,用于在UDP(用戶數據報協議)通信中傳輸數據。UDP是一種無連接的、不可靠的傳輸協議,適用于一些對實時性要求較高的應用,如音頻和視頻傳輸。
21.3.2?DatagramSocket類?
DatagramSocket與DatagramPacket一起使用,通過DatagramSocket發送和接收UDP數據報。該類提供了一種簡單而直接的方式來實現基于UDP的網絡通信。在使用時,通常先創建一個DatagramSocket對象,然后通過該對象創建DatagramPacket并進行數據的發送和接收。
21.3.3 UDP網絡程序設計
根據前面所講的網絡編程的基本知識以及 UDP 網絡編程的特點,下面創建一個廣播數據報程序廣播數據報是一項較新的技術,其原理類似于電臺廣播。廣播電臺需要在指定的波段和頻率上廣播信息,收聽者也要將收音機調到指定的波段、頻率,才可以收聽廣播內容
例題21.3:創建UDP協議廣播電臺程序
package 二十一;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;public class Notification extends Thread {String weather = "節目預報:八點有大型晚會,請收聽";int port = 9898;InetAddress iaddress = null;MulticastSocket socket = null;Notification() {try {iaddress = InetAddress.getByName("224.255.10.0");socket = new MulticastSocket(port);socket.setTimeToLive(1);socket.joinGroup(iaddress);}catch(IOException e){e.printStackTrace();}}public void run() {while(true) {DatagramPacket packet = null;byte data[] = weather.getBytes();packet = new DatagramPacket(data, data.length,iaddress,port);System.out.println(weather);try {socket.send(packet);sleep(3000);}catch(IOException e) {e.printStackTrace();}catch(InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {// TODO Auto-generated method stubNotification w = new Notification();w.start();}}
?
?
?
package 二十一;import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.net.*;
import javax.swing.*;public class Receive extends JFrame implements Runnable,ActionListener {int port;InetAddress group=null;MulticastSocket socket=null;JButton inceBtn=new JButton("開始接收");JButton stopBtn=new JButton("停止接收");JTextArea inceAr=new JTextArea(10,10);JTextArea inced=new JTextArea(10,10);Thread thread;boolean stop=false;public Receive() {setTitle("廣播數據報");setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);thread=new Thread(this);inceBtn.addActionListener(this);stopBtn.addActionListener(this);inceAr.setForeground(Color.blue);JPanel north=new JPanel();north.add(inceBtn);north.add(stopBtn);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();port=9898;try {group=InetAddress.getByName("224.255.10.0");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 data[]=new byte[1024];DatagramPacket packet=null;packet=new DatagramPacket(data,data.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()==inceBtn) {inceBtn.setBackground(Color.red);stopBtn.setBackground(Color.yellow);if(!(thread.isAlive())) {thread=new Thread(this);}thread.start();stop=false;}if(e.getSource()==stopBtn) {inceBtn.setBackground(Color.yellow);stopBtn.setBackground(Color.red);stop=true;}}public static void main(String[] args) {Receive rec=new Receive();rec.setSize(460,200);}
}
?結束力