麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > Java > 正文

java使用MulticastSocket實現基于廣播的多人聊天室

2024-07-14 08:43:29
字體:
來源:轉載
供稿:網友

使用MulticastSocket實現多點廣播:

(1)DatagramSocket只允許數據報發給指定的目標地址,而MulticastSocket可以將數據報以廣播的方式發送到多個客戶端。

(2)IP協議為多點廣播提供了這批特殊的IP地址,這些IP地址的范圍是:224.0.0.0至239.255.255.255..

(3)MulticastSocket類時實現多點廣播的關鍵,當MulticastSocket把一個DaragramPocket發送到多點廣播的IP地址時,該數據報將會自動廣播到加入該地址的所有MulticastSocket。MulticastSocket既可以將數據報發送到多點廣播地址,也可以接收其他主機的廣播信息。

(4)事實上,MulticastSocket是DatagramSocket的子類,也就是說,MulticastSocket是特殊的DatagramSocket。當要發送一個數據報時,可以使用隨機端口創建MulticastSocket,也可以在指定端口創建MulticastSocket。MulticastSocket提供了如下三個構造器:

public MulticastSocket() 使用本機默認地址,隨機端口來創建MulticastSocket對象 
public MulticastSocket(int portNumber) 用本機默認地址,指定端口來創建MulticastSocket對象 
public MulticastSocket(SocketAddress bindaddr) 用指定IP地址,指定端口來創建MulticastSocket對象

(5)創建MulticastSocket對象后,還需要將MulticastSocket加入到指定的多點廣播地址。MulticastSocket使用joinGroup()方法加入指定組;使用leaveGroup()方法脫離一個組。

joinGroup(InetAddress multicastAddr) 將該MulticastSocket加入到指定的多點廣播地址

leaveGroup(InetAddress multicastAddr) 將該MulticastSocket離開指定的多點廣播地址

(6)在某些系統中,可能有多個網絡接口,這可能為多點廣播帶來問題,這時候程序需要在一個指定的網絡接口上監聽,通過調用setInterface()方法可以強制MulticastSocket使用指定的網絡接口‘也可以使用getInterface()方法查詢MulticastSocket監聽的網絡接口。

(7)如果創建僅僅用于發送數據報的MulticastSocket對象,則使用默認地址,隨機端口即可。但如果創建接收用的MulticastSocket對象,'則該MulticastSocket對象必須有指定端口,否則無法確定發送數據報的目標端口。

(8)MulticastSocket用于發送接收數據報的方法與DatagramSocket完全一樣。但MulticastSocket比DatagramSocket多了一個setTimeToLive(int ttl)方法,該ttl用于設置數據報最多可以跨過多少個網絡。 
當ttl為0時,指定數據報應停留在本地主機 
當ttl為1時,指定數據報發送到本地局域網 
當ttl為32時,指定數據報發送到本站點的網絡上 
當ttl為64時,意味著數據報應該停留在本地區 
當ttl為128時,意味著數據報應保留在本大洲 
當ttl為255時,意味著數據報可以發送到所有地方 
默認情況下,ttl值為1.

程序實例:

下面程序使用MulticastSocket實現一個基于廣播的多人聊天室。程序只需要一個MulticastSocket,兩個線程,其中MulticastSocket既用于發送,也用于接收;一個線程負責鍵盤輸入,并向MulticastSocket發送數據;一個線程負責從MulticastSocket中讀取數據。

package com.talk;import java.io.IOException;import java.net.DatagramPacket;import java.net.InetAddress;import java.net.MulticastSocket;import java.util.Scanner;//讓該類實現Runnable接口,該類的實例可以作為線程的targetpublic class MulticastSocketTest implements Runnable{  //使用常量作為本程序多點廣播的IP地址  private static final String BROADCAST_IP="230.0.0.1";  //使用常量作為本程序的多點廣播的目的地端口  public static final int BROADCAST_PORT=3000;  //定義每個數據報大小最大為4kb  private static final int DATA_LEN=4096;  //定義本程序的MulticastSocket實例  private MulticastSocket socket=null;  private InetAddress broadcastAddress=null;  private Scanner scan=null;  //定義接收網絡數據的字節數組  byte[] inBuff=new byte[DATA_LEN];  //以指定字節數組創建準備接收數據的MulticastSocket對象  private DatagramPacket inPacket =new DatagramPacket(inBuff, inBuff.length);  //定義一個用于發送的DatagramPacket對象  private DatagramPacket outPacket=null;  public void init() throws IOException{   //創建鍵盤輸入流   Scanner scan=new Scanner(System.in);   //創建用于發送、接收數據的MulticastSocket對象,由于該MulticastSocket需要接收數據,所以有指定端口   socket=new MulticastSocket(BROADCAST_PORT);   broadcastAddress=InetAddress.getByName(BROADCAST_IP);   //將該socket加入到指定的多點廣播地址   socket.joinGroup(broadcastAddress);   //設置本MulticastSocket發送的數據報會被回送到自身   socket.setLoopbackMode(false);   //初始化發送用的DatagramSocket,它包含一個長度為0的字節數組   outPacket =new DatagramPacket(new byte[0], 0, broadcastAddress, BROADCAST_PORT);   //啟動本實例的run()方法作為線程執行體的線程   new Thread(this).start();   //不斷的讀取鍵盤輸入   while(scan.hasNextLine()){    //將鍵盤輸入的一行字符轉換成字節數組    byte [] buff=scan.nextLine().getBytes();    //設置發送用的DatagramPacket里的字節數據    outPacket.setData(buff);    //發送數據報    socket.send(outPacket);   }   socket.close();  }  public void run() {   // TODO Auto-generated method stub   while(true){    //讀取Socket中的數據,讀到的數據放入inPacket所封裝的字節組里    try {      socket.receive(inPacket);      //打印從socket讀取到的內容      System.out.println("聊天信息:"+new String(inBuff,0,inPacket.getLength()));    } catch (IOException e) {      // TODO Auto-generated catch block      e.printStackTrace();    }    if(socket!=null){      //讓該socket離開多點IP廣播地址      try {       socket.leaveGroup(broadcastAddress);       //關閉socket對象       socket.close();      } catch (IOException e) {       // TODO Auto-generated catch block       e.printStackTrace();      }    }    System.exit(1);   }  }  public static void main(String[] args) {   try {    new MulticastSocketTest().init();   } catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }  }}

下面將結合MulticastSocket和DatagramSocket開發一個簡單的局域網即時通訊工具,局域網內每個用戶啟動該工具后,就可以看到該局域網內所有的在線用戶,該用戶也會被其他用戶看到:

該程序的思路是:每個用戶都啟動兩個Socket,即MulticastSocket和DatagramSocket。其中MulticastSocket會周期性的向230.0.0.1發送在線信息,且所有的MulticastSocket都會加入到230.0.0.1這個多點廣播IP中,這樣每個用戶都會收到其他用戶的在線信息,如果系統在一段時間內沒有收到某個用戶廣播的在線信息,則從用戶列表中刪除該用戶。除此之外,該MulticastSocket還用于向其他用戶發送廣播信息。

DatagramSocket主要用于發送私聊信息,當用戶收到其他用戶廣播來的DatagramSocket時,即可獲得該用戶MulticastSocket對應的SocketAddress.這個SocketAddress將作為發送私聊信息的重要依據。—本程序讓MulticastSocket在30000端口監聽,而DatagramSocket在30001端口監聽,這樣程序就可以根據其他用戶廣播來的DatagramPacket得到他的DatagramSocket所在的地址。

本系統提供了一個UserInfo類,該類封裝了用戶名、圖標、對應的SocketAddress以及該用戶對應的交談窗口,失去聯系的次數等信息:

package com.talk;import java.net.SocketAddress;import com.bank.ChatFrame;public class UserInfo{  // 該用戶的圖標  private String icon;  // 該用戶的名字  private String name;  // 該用戶的MulitcastSocket所在的IP和端口  private SocketAddress address;  // 該用戶失去聯系的次數  private int lost;  // 該用戶對應的交談窗口  private ChatFrame chatFrame;  public UserInfo(){}  // 有參數的構造器  public UserInfo(String icon , String name   , SocketAddress address , int lost)  {   this.icon = icon;   this.name = name;   this.address = address;   this.lost = lost;  }  // 省略所有成員變量的setter和getter方法  // icon的setter和getter方法  public void setIcon(String icon)  {   this.icon = icon;  }  public String getIcon()  {   return this.icon;  }  // name的setter和getter方法  public void setName(String name)  {   this.name = name;  }  public String getName()  {   return this.name;  }  // address的setter和getter方法  public void setAddress(SocketAddress address)  {   this.address = address;  }  public SocketAddress getAddress()  {   return this.address;  }  // lost的setter和getter方法  public void setLost(int lost)  {   this.lost = lost;  }  public int getLost()  {   return this.lost;  }  // chatFrame的setter和getter方法  public void setChatFrame(ChatFrame chatFrame)  {   this.chatFrame = chatFrame;  }  public ChatFrame getChatFrame()  {   return this.chatFrame;  }  // 使用address作為該用戶的標識,所以根據address作為  // 重寫hashCode()和equals方法的標準  public int hashCode()  {   return address.hashCode();  }  public boolean equals(Object obj)  {   if (obj != null && obj.getClass() == UserInfo.class)   {    UserInfo target = (UserInfo)obj;    if (address != null)    {      return address.equals(target.getAddress());    }   }   return false;  }}

通過UserInfo的封裝,所有客戶端只需要維護該UserInfo類的列表,程序就可以實現廣播、發送私聊信息等功能。本程序的底層通信類則需要一個MulticastSocket和一個DatagramSocket,該工具類的代碼如下:

package com.talk;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.MulticastSocket;import java.net.SocketAddress;import java.util.ArrayList;import javax.swing.JOptionPane;public class ComUtil{  // 定義本程序通信所使用的字符集  public static final String CHARSET = "utf-8";  // 使用常量作為本程序的多點廣播IP地址  private static final String BROADCAST_IP   = "230.0.0.1";  // 使用常量作為本程序的多點廣播目的的端口  // DatagramSocket所用的的端口為該端口+1。  public static final int BROADCAST_PORT = 30000;  // 定義每個數據報的最大大小為4K  private static final int DATA_LEN = 4096;  // 定義本程序的MulticastSocket實例  private MulticastSocket socket = null;  // 定義本程序私聊的Socket實例  private DatagramSocket singleSocket = null;  // 定義廣播的IP地址  private InetAddress broadcastAddress = null;  // 定義接收網絡數據的字節數組  byte[] inBuff = new byte[DATA_LEN];  // 以指定字節數組創建準備接受數據的DatagramPacket對象  private DatagramPacket inPacket =   new DatagramPacket(inBuff , inBuff.length);  // 定義一個用于發送的DatagramPacket對象  private DatagramPacket outPacket = null;  // 聊天的主界面程序  private LanTalk lanTalk;  // 構造器,初始化資源  public ComUtil(LanTalk lanTalk) throws Exception  {   this.lanTalk = lanTalk;   // 創建用于發送、接收數據的MulticastSocket對象   // 因為該MulticastSocket對象需要接收,所以有指定端口   socket = new MulticastSocket(BROADCAST_PORT);   // 創建私聊用的DatagramSocket對象   singleSocket = new DatagramSocket(BROADCAST_PORT + 1);   broadcastAddress = InetAddress.getByName(BROADCAST_IP);   // 將該socket加入指定的多點廣播地址   socket.joinGroup(broadcastAddress);   // 設置本MulticastSocket發送的數據報被回送到自身   socket.setLoopbackMode(false);   // 初始化發送用的DatagramSocket,它包含一個長度為0的字節數組   outPacket = new DatagramPacket(new byte[0]    , 0 , broadcastAddress , BROADCAST_PORT);   // 啟動兩個讀取網絡數據的線程   new ReadBroad().start();   Thread.sleep(1);   new ReadSingle().start();  }  // 廣播消息的工具方法  public void broadCast(String msg)  {   try   {    // 將msg字符串轉換字節數組    byte[] buff = msg.getBytes(CHARSET);    // 設置發送用的DatagramPacket里的字節數據    outPacket.setData(buff);    // 發送數據報    socket.send(outPacket);   }   // 捕捉異常   catch (IOException ex)   {    ex.printStackTrace();    if (socket != null)    {      // 關閉該Socket對象      socket.close();    }    JOptionPane.showMessageDialog(null      , "發送信息異常,請確認30000端口空閑,且網絡連接正常!"      , "網絡異常", JOptionPane.ERROR_MESSAGE);    System.exit(1);   }  }  // 定義向單獨用戶發送消息的方法  public void sendSingle(String msg , SocketAddress dest)  {   try   {    // 將msg字符串轉換字節數組    byte[] buff = msg.getBytes(CHARSET);    DatagramPacket packet = new DatagramPacket(buff      , buff.length , dest);    singleSocket.send(packet);   }   // 捕捉異常   catch (IOException ex)   {    ex.printStackTrace();    if (singleSocket != null)    {      // 關閉該Socket對象      singleSocket.close();    }    JOptionPane.showMessageDialog(null      , "發送信息異常,請確認30001端口空閑,且網絡連接正常!"      , "網絡異常", JOptionPane.ERROR_MESSAGE);    System.exit(1);   }  }  // 不斷從DatagramSocket中讀取數據的線程  class ReadSingle extends Thread  {   // 定義接收網絡數據的字節數組   byte[] singleBuff = new byte[DATA_LEN];   private DatagramPacket singlePacket =    new DatagramPacket(singleBuff , singleBuff.length);   public void run()   {    while (true)    {      try      {       // 讀取Socket中的數據。       singleSocket.receive(singlePacket);       // 處理讀到的信息       lanTalk.processMsg(singlePacket , true);      }      // 捕捉異常      catch (IOException ex)      {       ex.printStackTrace();       if (singleSocket != null)       {        // 關閉該Socket對象        singleSocket.close();       }       JOptionPane.showMessageDialog(null        , "接收信息異常,請確認30001端口空閑,且網絡連接正常!"        , "網絡異常", JOptionPane.ERROR_MESSAGE);       System.exit(1);      }    }   }  }  // 持續讀取MulticastSocket的線程  class ReadBroad extends Thread  {   public void run()   {    while (true)    {      try      {       // 讀取Socket中的數據。       socket.receive(inPacket);       // 打印輸出從socket中讀取的內容       String msg = new String(inBuff , 0        , inPacket.getLength() , CHARSET);       // 讀到的內容是在線信息       if (msg.startsWith(YeekuProtocol.PRESENCE)        && msg.endsWith(YeekuProtocol.PRESENCE))       {        String userMsg = msg.substring(2          , msg.length() - 2);        String[] userInfo = userMsg.split(YeekuProtocol          .SPLITTER);        UserInfo user = new UserInfo(userInfo[1]          , userInfo[0] , inPacket.getSocketAddress(), 0);        // 控制是否需要添加該用戶的旗標        boolean addFlag = true;        ArrayList<Integer> delList = new ArrayList<>();        // 遍歷系統中已有的所有用戶,該循環必須循環完成        for (int i = 1 ; i < lanTalk.getUserNum() ; i++ )        {          UserInfo current = lanTalk.getUser(i);          // 將所有用戶失去聯系的次數加1          current.setLost(current.getLost() + 1);          // 如果該信息由指定用戶發送過來          if (current.equals(user))          {           current.setLost(0);           // 設置該用戶無須添加           addFlag = false;          }          if (current.getLost() > 2)          {           delList.add(i);          }        }        // 刪除delList中的所有索引對應的用戶        for (int i = 0; i < delList.size() ; i++)        {          lanTalk.removeUser(delList.get(i));        }        if (addFlag)        {          // 添加新用戶          lanTalk.addUser(user);        }       }       // 讀到的內容是公聊信息       else       {        // 處理讀到的信息        lanTalk.processMsg(inPacket , false);       }      }      // 捕捉異常      catch (IOException ex)      {       ex.printStackTrace();       if (socket != null)       {        // 關閉該Socket對象        socket.close();       }       JOptionPane.showMessageDialog(null        , "接收信息異常,請確認30000端口空閑,且網絡連接正常!"        , "網絡異常", JOptionPane.ERROR_MESSAGE);       System.exit(1);      }    }   }  }}

本程序的一個主類,LanTalk ,該類使用DefaultListModel來維護用戶列表,該類里的每個列表項就是一個UserInfo。該類還提供了一個ImageCellRenderer,該類用于將列表項繪制出用戶圖標和用戶名字。

package com.talk;import java.awt.Color;import java.awt.Component;import java.awt.Dimension;import java.awt.Font;import java.awt.Graphics;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.net.DatagramPacket;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.text.DateFormat;import java.util.Date;import javax.swing.DefaultListModel;import javax.swing.ImageIcon;import javax.swing.JFrame;import javax.swing.JList;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.ListCellRenderer;import com.bank.ChatFrame;import com.bank.LoginFrame;public class LanTalk extends JFrame{  private DefaultListModel<UserInfo> listModel   = new DefaultListModel<>();  // 定義一個JList對象  private JList<UserInfo> friendsList = new JList<>(listModel);  // 定義一個用于格式化日期的格式器  private DateFormat formatter = DateFormat.getDateTimeInstance();  public LanTalk()  {   super("局域網聊天");   // 設置該JList使用ImageCellRenderer作為單元格繪制器   friendsList.setCellRenderer(new ImageCellRenderer());   listModel.addElement(new UserInfo("all" , "所有人"    , null , -2000));   friendsList.addMouseListener(new ChangeMusicListener());   add(new JScrollPane(friendsList));   setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   setBounds(2, 2, 160 , 600);  }  // 根據地址來查詢用戶  public UserInfo getUserBySocketAddress(SocketAddress address)  {   for (int i = 1 ; i < getUserNum() ; i++)   {    UserInfo user = getUser(i);    if (user.getAddress() != null      && user.getAddress().equals(address))    {      return user;    }   }   return null;  }  // ------下面四個方法是對ListModel的包裝------  // 向用戶列表中添加用戶  public void addUser(UserInfo user)  {   listModel.addElement(user);  }  // 從用戶列表中刪除用戶  public void removeUser(int pos)  {   listModel.removeElementAt(pos);  }  // 獲取該聊天窗口的用戶數量  public int getUserNum()  {   return listModel.size();  }  // 獲取指定位置的用戶  public UserInfo getUser(int pos)  {   return listModel.elementAt(pos);  }  // 實現JList上的鼠標雙擊事件的監聽器  class ChangeMusicListener extends MouseAdapter  {   public void mouseClicked(MouseEvent e)   {    // 如果鼠標的擊鍵次數大于2    if (e.getClickCount() >= 2)    {      // 取出鼠標雙擊時選中的列表項      UserInfo user = (UserInfo)friendsList.getSelectedValue();      // 如果該列表項對應用戶的交談窗口為null      if (user.getChatFrame() == null)      {       // 為該用戶創建一個交談窗口,并讓該用戶引用該窗口       user.setChatFrame(new ChatFrame(null , user));      }      // 如果該用戶的窗口沒有顯示,則讓該用戶的窗口顯示出來      if (!user.getChatFrame().isShowing())      {       user.getChatFrame().setVisible(true);      }    }   }  }  /**  * 處理網絡數據報,該方法將根據聊天信息得到聊天者,  * 并將信息顯示在聊天對話框中。  * @param packet 需要處理的數據報  * @param single 該信息是否為私聊信息  */  public void processMsg(DatagramPacket packet , boolean single)  {   // 獲取該發送該數據報的SocketAddress   InetSocketAddress srcAddress = (InetSocketAddress)    packet.getSocketAddress();   // 如果是私聊信息,則該Packet獲取的是DatagramSocket的地址,   // 將端口減1才是對應的MulticastSocket的地址   if (single)   {    srcAddress = new InetSocketAddress(srcAddress.getHostName()      , srcAddress.getPort() - 1);   }   UserInfo srcUser = getUserBySocketAddress(srcAddress);   if (srcUser != null)   {    // 確定消息將要顯示到哪個用戶對應窗口上。    UserInfo alertUser = single ? srcUser : getUser(0);    // 如果該用戶對應的窗口為空,顯示該窗口    if (alertUser.getChatFrame() == null)    {      alertUser.setChatFrame(new ChatFrame(null , alertUser));    }    // 定義添加的提示信息    String tipMsg = single ? "對您說:" : "對大家說:";    try{      // 顯示提示信息      alertUser.getChatFrame().addString(srcUser.getName()       + tipMsg + "......................("       + formatter.format(new Date()) + ")/n"       + new String(packet.getData() , 0 , packet.getLength()       , ComUtil.CHARSET) + "/n");    } catch (Exception ex) { ex.printStackTrace(); }    if (!alertUser.getChatFrame().isShowing())    {      alertUser.getChatFrame().setVisible(true);    }   }  }  // 主方法,程序的入口  public static void main(String[] args)  {   LanTalk lanTalk = new LanTalk();   new LoginFrame(lanTalk , "請輸入用戶名、頭像后登錄");  }}// 定義用于改變JList列表項外觀的類class ImageCellRenderer extends JPanel  implements ListCellRenderer<UserInfo>{  private ImageIcon icon;  private String name;  // 定義繪制單元格時的背景色  private Color background;  // 定義繪制單元格時的前景色  private Color foreground;  @Override  public Component getListCellRendererComponent(JList list   , UserInfo userInfo , int index   , boolean isSelected , boolean cellHasFocus)  {   // 設置圖標   icon = new ImageIcon("ico/" + userInfo.getIcon() + ".gif");   name = userInfo.getName();   // 設置背景色、前景色   background = isSelected ? list.getSelectionBackground()    : list.getBackground();   foreground = isSelected ? list.getSelectionForeground()    : list.getForeground();   // 返回該JPanel對象作為單元格繪制器   return this;  }  // 重寫paintComponent方法,改變JPanel的外觀  public void paintComponent(Graphics g)  {   int imageWidth = icon.getImage().getWidth(null);   int imageHeight = icon.getImage().getHeight(null);   g.setColor(background);   g.fillRect(0, 0, getWidth(), getHeight());   g.setColor(foreground);   // 繪制好友圖標   g.drawImage(icon.getImage() , getWidth() / 2 - imageWidth / 2    , 10 , null);   g.setFont(new Font("SansSerif" , Font.BOLD , 18));   // 繪制好友用戶名   g.drawString(name, getWidth() / 2 - name.length() * 10    , imageHeight + 30 );  }  // 通過該方法來設置該ImageCellRenderer的最佳大小  public Dimension getPreferredSize()  {   return new Dimension(60, 80);  }}

除了以上主要的代碼,還有YeekuProtocol   ChatFrame   LoginFrame等類:

package com.talk;public interface YeekuProtocol{  String PRESENCE = "⊿⊿";  String SPLITTER = "▓";}
package com.bank;import java.awt.Dimension;import java.awt.Font;import java.awt.GridLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JComboBox;import javax.swing.JComponent;import javax.swing.JDialog;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JTextField;import com.talk.ComUtil;import com.talk.LanTalk;import com.talk.YeekuProtocol;// 登錄用的對話框public class LoginFrame extends JDialog{  public JLabel tip;  public JTextField userField = new JTextField("錢鐘書" , 20);  public JComboBox<Integer> iconList = new JComboBox<>(   new Integer[]{1, 2, 3, 4, 5 , 6, 7, 8 ,9 ,10});  private JButton loginBn = new JButton("登錄");  // 聊天的主界面  private LanTalk chatFrame;  // 聊天通信的工具實例  public static ComUtil comUtil;  // 構造器,用于初始化的登錄對話框  public LoginFrame(LanTalk parent , String msg)  {   super(parent , "輸入名字后登錄" , true);   this.chatFrame = parent;   setLayout(new GridLayout(5, 1));   JPanel jp = new JPanel();   tip = new JLabel(msg);   tip.setFont(new Font("Serif" , Font.BOLD , 16));   jp.add(tip);   add(jp);   add(getPanel("用戶名" , userField));   iconList.setPreferredSize(new Dimension(224, 20));   add(getPanel("圖 標" , iconList));   JPanel bp = new JPanel();   loginBn.addActionListener(new MyActionListener(this));   bp.add(loginBn);   add(bp);   pack();   setVisible(true);  }  // 工具方法,該方法將一個字符串和組件組合成JPanel對象  private JPanel getPanel(String name , JComponent jf)  {   JPanel jp = new JPanel();   jp.add(new JLabel(name + ":"));   jp.add(jf);   return jp;  }  // 該方法用于改變登錄窗口最上面的提示信息  public void setTipMsg(String tip)  {   this.tip.setText(tip);  }  // 定義一個事件監聽器  class MyActionListener implements ActionListener  {   private LoginFrame loginFrame;   public MyActionListener(LoginFrame loginFrame)   {    this.loginFrame = loginFrame;   }   // 當鼠標單擊事件發生時   public void actionPerformed(ActionEvent evt)   {    try    {      // 初始化聊天通信類      comUtil = new ComUtil(chatFrame);      final String loginMsg = YeekuProtocol.PRESENCE + userField.getText()       + YeekuProtocol.SPLITTER + iconList.getSelectedObjects()[0]       + YeekuProtocol.PRESENCE;      comUtil.broadCast(loginMsg);      // 啟動定時器每20秒廣播一次在線信息      javax.swing.Timer timer = new javax.swing.Timer(1000 * 10       , event-> comUtil.broadCast(loginMsg));      timer.start();      loginFrame.setVisible(false);      chatFrame.setVisible(true);    }    catch (Exception ex)    {      loginFrame.setTipMsg("確認30001端口空閑,且網絡正常!");    }   }  }}
package com.bank;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.net.InetSocketAddress;import javax.swing.AbstractAction;import javax.swing.Action;import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.KeyStroke;import com.talk.LanTalk;import com.talk.UserInfo;// 定義交談的對話框public class ChatFrame extends JDialog{  // 聊天信息區  JTextArea msgArea = new JTextArea(12 , 45);  // 聊天輸入區  JTextField chatField = new JTextField(30);  // 發送聊天信息的按鈕  JButton sendBn = new JButton("發送");  // 該交談窗口對應的用戶  UserInfo user;  // 構造器,用于初始化交談對話框的界面  public ChatFrame(LanTalk parent , final UserInfo user)  {   super(parent , "和" + user.getName() + "聊天中" , false);   this.user = user;   msgArea.setEditable(false);   add(new JScrollPane(msgArea));   JPanel buttom = new JPanel();   buttom.add(new JLabel("輸入信息:"));   buttom.add(chatField);   buttom.add(sendBn);   add(buttom , BorderLayout.SOUTH);   // 發送消息的Action,Action是ActionListener的子接口   Action sendAction = new AbstractAction()   {    @Override    public void actionPerformed(ActionEvent evt)    {      InetSocketAddress dest = (InetSocketAddress)user.getAddress();      // 在聊友列表中,所有人項的SocketAddress是null      // 這表明是向所有人發送消息      if (dest == null)      {       LoginFrame.comUtil.broadCast(chatField.getText());       msgArea.setText("您對大家說:"        + chatField.getText() + "/n" + msgArea.getText());      }      // 向私人發送信息      else      {       // 獲取發送消息的目的       dest = new InetSocketAddress(dest.getHostName(),        dest.getPort() + 1);       LoginFrame.comUtil.sendSingle(chatField.getText(), dest);       msgArea.setText("您對" + user.getName() + "說:"        + chatField.getText() + "/n" + msgArea.getText());      }      chatField.setText("");    }   };   sendBn.addActionListener(sendAction);   // 將Ctrl+Enter鍵和"send"關聯   chatField.getInputMap().put(KeyStroke.getKeyStroke('/n'    , java.awt.event.InputEvent.CTRL_MASK) , "send");   // 將"send"與sendAction關聯   chatField.getActionMap().put("send", sendAction);   pack();  }  // 定義向聊天區域添加消息的方法  public void addString(String msg)  {   msgArea.setText(msg + "/n" + msgArea.getText());  }}

運行效果

java,MulticastSocket,多人聊天室

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 空姐一级毛片 | 色婷婷a v | 欧美三级欧美成人高清www | 超碰97人人艹| 成人午夜视频免费在线观看 | 毛片毛片 | 国产一区二区免费在线观看 | 欧美黄色大片免费观看 | 神马顶级推理片免费看 | 色悠悠久久久久 | 91成人免费视频 | 国产1区2区3区中文字幕 | 精品无吗乱吗av国产爱色 | 成人综合免费视频 | 黄网站免费观看视频 | 九九热在线视频免费观看 | 精品免费国产一区二区三区 | 九九热视频在线免费观看 | 欧美国产日韩在线观看成人 | 亚洲精品午夜电影 | 精品一二三区视频 | 91精品国产99久久久久久 | 日本黄色一级视频 | 欧美1区2区在线观看 | 欧美一级免费高清 | 久久成人综合视频 | 精精国产xxxx视频在线野外 | 中文日韩| 鸳鸯谱在线观看高清 | 意大利av在线 | 激情小说另类 | 精品亚洲夜色av98在线观看 | 亚洲午夜一区二区三区 | 草碰人人| 视频h在线| 亚洲欧美日韩中文在线 | 国产资源在线免费观看 | 国产男女 爽爽爽爽视频 | 国产精品久久久久久久久久久久午夜 | 午夜av男人的天堂 | 91精品国产乱码久 |