<b id="yt35u"></b>
  • <b id="yt35u"></b>

  • <tt id="yt35u"><form id="yt35u"></form></tt>
    <button id="yt35u"></button>

    <button id="yt35u"></button>

    <strike id="yt35u"><dfn id="yt35u"></dfn></strike>

    <i id="yt35u"></i>
    1. <tt id="yt35u"></tt>
      <b id="yt35u"><sub id="yt35u"><tr id="yt35u"></tr></sub></b>

      教育路上

      全國站>Java>網絡編程>UDP 案例—聊天程序
      學員需求

      UDP 案例—聊天程序

      摘要:Java UDP 案例 聊天 程序 ,UDP網絡程序的基本過程。下面將多線程和Swing 的相關知識結合起來實現一個功能完善的聊天程序。。以下是我們為大家整理的,相信大家閱讀完后肯定有了自己的選擇吧。

      2022-05-18 16:39網絡推薦

      發布時間:
      2022-05-18 16:39
      信息來源:
      網絡推薦
      瀏覽次數:
      1353
      UDP 案例—聊天程序

      通過上面的講解,大家應該掌握了編寫UDP網絡程序的基本過程。下面將多線程和Swing 的相關知識結合起來實現一個功能完善的聊天程序。 在實現案例之前,首先分析一下功能需求?,F在所要編寫的 UDP 聊天程序主要是想通 過監聽指定的端口號,目標 IP 地址和目標端口號,實現消息的發送和接收功能,并把聊天 內容顯示出來。程序的用戶圖形界面如圖 13-12 所示

      from shengerguan


      在實際開發中,為了使程序條理清晰,通常會將一個大問題分
      決,這里為了使大家更容易理解,把聊天程序分為以下步驟來實現:
      1.界面實現
      對于界面的實現,首先定義一個類 GuiChat 繼承自 JFram 類,類中聲明成員變量,成員變
      量包括組成用戶圖形界面的各個組件以及 DatagramSocket 等,如例 13-4 所示。
      例 13-4 GuiChat.java
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import java.io.IOException;
      import java.net.*;
      public class GuiChat extends JFrame {
      private static final int DEFAULT_PORT = 8899;
      // 把主窗口分為 NORTH、CEMTER 和 SOUTH 三個部分
      private JLabel stateLB; // 顯示監聽狀態
      private JTextArea centerTextArea; // 顯示聊天記錄
      private JPanel southPanel; // 最下面的面板
      private JTextArea inputTextArea; // 聊天輸入框
      private JPanel bottomPanel; // 放置 IP 輸入框,按鈕等
      private JTextField ipTextField; // IP 輸入框
      private JTextField remotePortTF; // 端口號輸入框
      private JButton sendBT; // 發送按鈕
      private JButton clearBT; // 清除聊天記錄按鈕
      private DatagramSocket datagramSocket; // 用于后面功能的實現
      }
      接下來在 GuiChat 中定義一個 setUpUI()方法,實現用戶圖形界面的設置,如例 10-5 所
      示。
      例 10-5 setUpUl( )方法
      private void setUpUI() { // 初始化 Swing 窗口
      // 初始化窗口
      setTitle("GUI 聊天");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setSize(400, 400); // 設置窗口的大小
      setResizable(false); // 窗口大小不可調整
      setLocationRelativeTo(null); // 窗口居中
      // 窗口的 NORTH 部分
      stateLB = new JLabel("當前還未啟動監聽");
      stateLB.setHorizontalAlignment(JLabel.RIGHT);
      // 窗口的 CENTER 部分
      centerTextArea = new JTextArea(); // 聊天記錄顯示區域
      centerTextArea.setEditable(false);
      centerTextArea.setBackground(new Color(211, 211, 211));
      // 窗口的 SOUTH 部分
      southPanel = new JPanel(new BorderLayout());
      inputTextArea = new JTextArea(5, 20);// 內容輸入區域
      bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
      ipTextField = new JTextField("127.0.0.1", 8);
      remotePortTF = new JTextField(String.valueOf(DEFAULT_PORT), 3);
      sendBT = new JButton("發送");
      clearBT = new JButton("清屏");
      bottomPanel.add(ipTextField);
      bottomPanel.add(remotePortTF);
      bottomPanel.add(sendBT);
      bottomPanel.add(clearBT);
      southPanel.add(new JScrollPane(inputTextArea), BorderLayout.CENTER);
      southPanel.add(bottomPanel, BorderLayout.SOUTH);
      // 添加窗口 NORTH、CENTER、SOUTH 部分的組件
      add(stateLB, BorderLayout.NORTH);
      add(new JScrollPane(centerTextArea), BorderLayout.CENTER);
      add(southPanel, BorderLayout.SOUTH);
      setVisible(true);
      }
      在 setUpUI 方法中,使用 Borderlayou 布局管理器將圖形用戶界面分為 NORTH(代碼的 9~10
      行)、CENTER(代碼的 12~ 14 行)、SOUTH(代碼的 16~28 行)三部分。NORTH 部分放置一個
      JLabel 標簽 stateLB,用來顯示監聽狀態信息;CENTER 部分放置了一個 JTextArea 文本域,用來
      顯示聊天內容;SOUTH 部分放置了一個 JPanel 面板 southPanel,在 southPanel 中又放置了一
      一個JTextArea 文本域inputTextArea和一個JPanel 面板bottomPanel,inputTextArea 用來顯示
      用戶輸入的聊天內容,bottomPanel 中放置四個組件,ipTextField 和 remotePortTF 文本框分
      別用來填寫目標計算機的 IP 地址和端口號,sendBT 和 clearBT 按鈕分別用于發送聊天位息和
      清除 centerTextArea 文本域中顯示的聊天內容。

      2.編寫事件處理器(發送信息)
      界面開發完成后,還需要為界面上的按鈕添加監聽事件,在 GuiChat 類中,sendBT 和 clearBT
      按鈕的監聽事件封裝在 setListener( )方法中,如例 13-6 所示。
      例 13-6 setListener( )方法
      private void setListener() {
      // 為 sendBT 按鈕添加事件監聽器
      sendBT.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
      // 獲取發送的目標 ip 地址和端口號
      final String ipAddress = ipTextField.getText();
      final String remotePort = remotePortTF.getText();
      // 判斷 ip 地址和端口號是否為空
      if (ipAddress == null || ipAddress.trim().equals("")
      || remotePort == null || remotePort.trim().equals("")) {
      JOptionPane.showMessageDialog(GuiChat.this, "請輸入 IP 地址和端口
      號");
      return;
      }
      if (datagramSocket == null || datagramSocket.isClosed()) {
      JOptionPane.showMessageDialog(GuiChat.this, "監聽不成功");
      return;
      }
      // 獲得需要發送的內容
      String sendContent = inputTextArea.getText();
      byte[] buf = sendContent.getBytes();
      try {
      // 將發送的內容顯示在自己的聊天記錄中
      centerTextArea.append("我對 " + ipAddress + ":" + remotePort
      + " 說:\n" + inputTextArea.getText() + "\n\n");
      // 添加內容后,使滾動條自動滾動到最底端
      centerTextArea.setCaretPosition(centerTextArea.getText()
      .length());
      // 發送數據
      datagramSocket.send(new DatagramPacket(buf, buf.length,
      InetAddress.getByName(ipAddress), Integer
      .parseInt(remotePort)));
      inputTextArea.setText("");
      } catch (IOException e1) {
      JOptionPane.showMessageDialog(GuiChat.this, "出錯了,發送不成功");
      e1.printStackTrace();
      }
      };
      });
      // 為 clearBT 按鈕添加事件監聽器
      clearBT.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
      centerTextArea.setText(""); // 清空聊天記錄的內容
      }
      });
      }
      代碼的第 3~38 行為 sendBT 按鈕添加點擊事件監聽器,在監聽器中首先分別從文本框
      ipTetField 和 remotePort 中獲取目標 IP 和端口號,判斷它們是否為 null 或者空字符串"",若
      不為空,則從 inputTextArea 中獲取要發送的數據,把數據、IP 地址和端口號封裝到
      DatagramPacket 數據包,通過 datagramSocket 的 send () 方法發送,同時在 centerTextArea 中
      顯示出發送的內容。
      代碼的第 40~44 行為 clearBT 按鈕添加點擊事件監聽器,當點擊 clearBT 按鈕時,會將
      centerTextArea 文本域中顯示的聊天內容清空。
      3.DatagramSocket 的啟動監聽(接收信息)
      UDP 通信時,需要使用 DatagramSocket 啟動監聽,DatagramSocket 監聽的代碼定
      義在 GuiChat 類的 initSocket()方法中,initSocket()方法需要實現兩個功脂第一個是接收用戶填
      寫程序監聽的端口號,如例 13-7 所示。
      例 13-7 DatagramSocket 的啟動監聽
      private void initSocket() {
      int port = DEFAULT_PORT;
      while (true) {
      try {
      if (datagramSocket != null && !datagramSocket.isClosed()) {
      datagramSocket.close();
      }
      try { // 判斷端口號是否在 1-65535 之間
      port = Integer.parseInt(JOptionPane.showInputDialog(this,
      "請輸入端口號", "端口號",
      JOptionPane.QUESTION_MESSAGE));
      if (port < 1 || port > 65535) {
      throw new RuntimeException("端口號超出范圍");
      }
      } catch (Exception e) {
      JOptionPane.showMessageDialog(null,
      "你輸入的端口不正確,請輸入 1-65535 之間的數");
      continue; // 端口不正確重新填寫
      }
      // 啟動 DatagramSocket
      datagramSocket = new DatagramSocket(port);
      startListen(); // 調用 startListen 方法
      // 在 stateLB 中顯示程序監聽的端口號
      stateLB.setText("已在 " + port + " 端口監聽");
      break;
      } catch (SocketException e) { // 端口號被占用重新填寫
      JOptionPane.showMessageDialog(this, "端口已被占用,請重新設置端
      口");
      stateLB.setText("當前還未啟動監聽");
      }
      }
      }
      例 13—7 中,initSocket( )方法使用了 while(true)循環,目的是為了當用戶填寫的
      監聽口號不滿足要求時,反復地彈出輸入窗口,讓用戶重新輸人端口號,其過程如下:
      首先彈一個輸入窗口,接收用戶輸入的監聽端口號,如果端口號不在 1~65535 之中,會
      拋出一個異常,在 catch()塊中捕獲異常后,會彈出窗口提示"你輸人的端口不正確,
      請輸人 1-655353 之間的數"的信息,同時執行 continue 語句,重新開始循環,如果用
      戶輸人的監聽端口號在 1~65535 之間,就使用該端口號創建 DatagramSocket 對象。本
      節在"腳下留心"中講過,如果 DatagramSocke 監聽的端口號被其他程序占用,也會拋
      出一個異常,在 25~28 行的 catch()代碼塊中會捕獲這個異常,并彈出窗口提示"端口
      已被占用,請重新設置端口"的信息,然后繼續執行循環。只有填寫的監聽端口號正確
      并且未被占用時,才會成功創建 DatagramSocket 對象,之后調用 startListen()方法,
      執行 break 語句退出 while 循環。
      initSocket()方法還有一個功能是接收消息,這個功能封裝在 startListen()方法中,
      為了避免在接收消息時 AWT 線程發生阻塞,需要在 startListen()方法中開啟一個新的
      線程,把接收消息的實現放在新線程的 run()方法中,如例 13-8 所示。
      例 13-8 startListen()方法
      private void startListen() {
      new Thread() {
      private DatagramPacket p;
      public void run() {
      byte[] buf = new byte[1024];
      // 創建 DatagramPacket
      p = new DatagramPacket(buf, buf.length);
      while (!datagramSocket.isClosed()) {
      try {
      datagramSocket.receive(p); // 接收聊天消息
      // 添加到聊天記錄框
      centerTextArea.append(p.getAddress().getHostAddress()
      + ":"
      + ((InetSocketAddress) p.getSocketAddress())
      .getPort() + " 對我說:\n"
      + new String(p.getData(), 0, p.getLength())
      + "\n\n");
      // 使滾動條自動滾動到最底端
      centerTextArea.setCaretPosition(centerTextArea
      .getText().length());
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      }.start();
      }
      例 13-8 中,startListen()方法很簡單,在該方法中開啟了一個新的線程,在 run()方法中使
      用 while 循環,判斷 DatagramSocket 對象有沒有關閉,如果沒有關閉就不停地接收消息,并
      顯示在 centerTextArea 文本域中。
      4.功能測試
      至此,所有的功能模塊都已實現,在 GuiChat 的構造方法中分別調用 setUpUl()、
      initSocket()與 setListener()方法,就完成了 UDP 聊天程序,如例 13-9 所示。
      例 13-9 GuiChat 的構造方法
      public GuiChat() {
      setUpUI();
      initSocket();
      setListener();
      }
      public static void main(String[] args) {
      new GuiChat();
      }
      例 13-9 中,在 GuiChat 類的 main()方法中創建 GuiChat 實例對象,就可以運行這個 UDP 聊
      天程序。這里啟動兩個聊天程序的窗口,分別填寫對方的 IP 地址和監聽的端口號,測試程
      序的聊天功能,如圖 13-13 所示。



      from shengerguan


      由于兩個聊天程序都在本機啟動,從圖 13-13 中可以看到,IP 地址填寫的都是本地回環 地址 127.0.0.1,而且只要保證發送端填寫的目標端口號和接收端口號一致,就能實現兩個 窗口正常的聊天功能。


      上一篇:
      UDP 網絡程序案例
      下一篇:
      Java TCP 通信
      標簽:
      網友評論
      發布評論

      訪客的評論 2024/07/10 12:43

      文中描述的是準確的嗎,如何報名!

      相關推薦
      我也來發表評價關閉
      我對該內容的評價:
      0
      評價500
      驗證碼: 看不清 換一張
      提交 (匿名發布,無須擔心別人知道您的身份)
      學校免費發布信息關閉
      我們審核后會盡快展示,如有圖片請發郵件到:edu63@foxmail.com

      姓      名:

      內      容:

      手機號碼:

      驗  證  碼:  換一張

      確認提交
      填寫需求信息關閉
      我們會根據您的需求匹配并審核留言

      姓      名:

      意向城市:

      留      言:

      手機號碼:

      驗  證  碼:  換一張

      確認提交
      完善補充本文信息關閉
      非常感謝您幫助完善補充本文信息


       換一張

      確認提交
      女班长给我看她的小内内

        <b id="yt35u"></b>
    1. <b id="yt35u"></b>

    2. <tt id="yt35u"><form id="yt35u"></form></tt>
      <button id="yt35u"></button>

      <button id="yt35u"></button>

      <strike id="yt35u"><dfn id="yt35u"></dfn></strike>

      <i id="yt35u"></i>
      1. <tt id="yt35u"></tt>
        <b id="yt35u"><sub id="yt35u"><tr id="yt35u"></tr></sub></b>