真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何在java項目中使用MulticastSocket

本篇文章為大家展示了如何在java項目中使用MulticastSocket,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

創(chuàng)新互聯(lián)建站專注于玉泉企業(yè)網(wǎng)站建設,響應式網(wǎng)站建設,商城網(wǎng)站建設。玉泉網(wǎng)站建設公司,為玉泉等地區(qū)提供建站服務。全流程定制網(wǎng)站制作,專業(yè)設計,全程項目跟蹤,創(chuàng)新互聯(lián)建站專業(yè)和態(tài)度為您提供的服務

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

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

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

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

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

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

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

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

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

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

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

程序?qū)嵗?/strong>

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

package com.talk;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Scanner;
//讓該類實現(xiàn)Runnable接口,該類的實例可以作為線程的target
public class MulticastSocketTest implements Runnable{

  //使用常量作為本程序多點廣播的IP地址
  private static final String BROADCAST_IP="230.0.0.1";
  //使用常量作為本程序的多點廣播的目的地端口
  public static final int BROADCAST_PORT=3000;
  //定義每個數(shù)據(jù)報大小最大為4kb
  private static final int DATA_LEN=4096;
  //定義本程序的MulticastSocket實例
  private MulticastSocket socket=null;
  private InetAddress broadcastAddress=null;
  private Scanner scan=null;

  //定義接收網(wǎng)絡數(shù)據(jù)的字節(jié)數(shù)組
  byte[] inBuff=new byte[DATA_LEN];
  //以指定字節(jié)數(shù)組創(chuàng)建準備接收數(shù)據(jù)的MulticastSocket對象
  private DatagramPacket inPacket =new DatagramPacket(inBuff, inBuff.length);

  //定義一個用于發(fā)送的DatagramPacket對象
  private DatagramPacket outPacket=null;

  public void init() throws IOException{
   //創(chuàng)建鍵盤輸入流
   Scanner scan=new Scanner(System.in);
   //創(chuàng)建用于發(fā)送、接收數(shù)據(jù)的MulticastSocket對象,由于該MulticastSocket需要接收數(shù)據(jù),所以有指定端口
   socket=new MulticastSocket(BROADCAST_PORT);
   broadcastAddress=InetAddress.getByName(BROADCAST_IP);

   //將該socket加入到指定的多點廣播地址
   socket.joinGroup(broadcastAddress);
   //設置本MulticastSocket發(fā)送的數(shù)據(jù)報會被回送到自身
   socket.setLoopbackMode(false);

   //初始化發(fā)送用的DatagramSocket,它包含一個長度為0的字節(jié)數(shù)組
   outPacket =new DatagramPacket(new byte[0], 0, broadcastAddress, BROADCAST_PORT);

   //啟動本實例的run()方法作為線程執(zhí)行體的線程
   new Thread(this).start();

   //不斷的讀取鍵盤輸入
   while(scan.hasNextLine()){
    //將鍵盤輸入的一行字符轉(zhuǎn)換成字節(jié)數(shù)組
    byte [] buff=scan.nextLine().getBytes();
    //設置發(fā)送用的DatagramPacket里的字節(jié)數(shù)據(jù)
    outPacket.setData(buff);
    //發(fā)送數(shù)據(jù)報
    socket.send(outPacket);
   }
   socket.close();
  }

  public void run() {
   // TODO Auto-generated method stub

   while(true){
    //讀取Socket中的數(shù)據(jù),讀到的數(shù)據(jù)放入inPacket所封裝的字節(jié)組里
    try {
      socket.receive(inPacket);
      //打印從socket讀取到的內(nèi)容
      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);
       //關(guān)閉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();
   }
  }
}

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

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

DatagramSocket主要用于發(fā)送私聊信息,當用戶收到其他用戶廣播來的DatagramSocket時,即可獲得該用戶MulticastSocket對應的SocketAddress.這個SocketAddress將作為發(fā)送私聊信息的重要依據(jù)?!境绦蜃孧ulticastSocket在30000端口監(jiān)聽,而DatagramSocket在30001端口監(jiān)聽,這樣程序就可以根據(jù)其他用戶廣播來的DatagramPacket得到他的DatagramSocket所在的地址。

本系統(tǒng)提供了一個UserInfo類,該類封裝了用戶名、圖標、對應的SocketAddress以及該用戶對應的交談窗口,失去聯(lián)系的次數(shù)等信息:

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;
  // 該用戶失去聯(lián)系的次數(shù)
  private int lost;
  // 該用戶對應的交談窗口
  private ChatFrame chatFrame;
  public UserInfo(){}
  // 有參數(shù)的構(gòu)造器
  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作為該用戶的標識,所以根據(jù)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類的列表,程序就可以實現(xiàn)廣播、發(fā)送私聊信息等功能。本程序的底層通信類則需要一個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;
  // 定義每個數(shù)據(jù)報的最大大小為4K
  private static final int DATA_LEN = 4096;
  // 定義本程序的MulticastSocket實例
  private MulticastSocket socket = null;
  // 定義本程序私聊的Socket實例
  private DatagramSocket singleSocket = null;
  // 定義廣播的IP地址
  private InetAddress broadcastAddress = null;
  // 定義接收網(wǎng)絡數(shù)據(jù)的字節(jié)數(shù)組
  byte[] inBuff = new byte[DATA_LEN];
  // 以指定字節(jié)數(shù)組創(chuàng)建準備接受數(shù)據(jù)的DatagramPacket對象
  private DatagramPacket inPacket =
   new DatagramPacket(inBuff , inBuff.length);
  // 定義一個用于發(fā)送的DatagramPacket對象
  private DatagramPacket outPacket = null;
  // 聊天的主界面程序
  private LanTalk lanTalk;
  // 構(gòu)造器,初始化資源
  public ComUtil(LanTalk lanTalk) throws Exception
  {
   this.lanTalk = lanTalk;
   // 創(chuàng)建用于發(fā)送、接收數(shù)據(jù)的MulticastSocket對象
   // 因為該MulticastSocket對象需要接收,所以有指定端口
   socket = new MulticastSocket(BROADCAST_PORT);
   // 創(chuàng)建私聊用的DatagramSocket對象
   singleSocket = new DatagramSocket(BROADCAST_PORT + 1);
   broadcastAddress = InetAddress.getByName(BROADCAST_IP);
   // 將該socket加入指定的多點廣播地址
   socket.joinGroup(broadcastAddress);
   // 設置本MulticastSocket發(fā)送的數(shù)據(jù)報被回送到自身
   socket.setLoopbackMode(false);
   // 初始化發(fā)送用的DatagramSocket,它包含一個長度為0的字節(jié)數(shù)組
   outPacket = new DatagramPacket(new byte[0]
    , 0 , broadcastAddress , BROADCAST_PORT);
   // 啟動兩個讀取網(wǎng)絡數(shù)據(jù)的線程
   new ReadBroad().start();
   Thread.sleep(1);
   new ReadSingle().start();
  }
  // 廣播消息的工具方法
  public void broadCast(String msg)
  {
   try
   {
    // 將msg字符串轉(zhuǎn)換字節(jié)數(shù)組
    byte[] buff = msg.getBytes(CHARSET);
    // 設置發(fā)送用的DatagramPacket里的字節(jié)數(shù)據(jù)
    outPacket.setData(buff);
    // 發(fā)送數(shù)據(jù)報
    socket.send(outPacket);
   }
   // 捕捉異常
   catch (IOException ex)
   {
    ex.printStackTrace();
    if (socket != null)
    {
      // 關(guān)閉該Socket對象
      socket.close();
    }
    JOptionPane.showMessageDialog(null
      , "發(fā)送信息異常,請確認30000端口空閑,且網(wǎng)絡連接正常!"
      , "網(wǎng)絡異常", JOptionPane.ERROR_MESSAGE);
    System.exit(1);
   }
  }
  // 定義向單獨用戶發(fā)送消息的方法
  public void sendSingle(String msg , SocketAddress dest)
  {
   try
   {
    // 將msg字符串轉(zhuǎn)換字節(jié)數(shù)組
    byte[] buff = msg.getBytes(CHARSET);
    DatagramPacket packet = new DatagramPacket(buff
      , buff.length , dest);
    singleSocket.send(packet);
   }
   // 捕捉異常
   catch (IOException ex)
   {
    ex.printStackTrace();
    if (singleSocket != null)
    {
      // 關(guān)閉該Socket對象
      singleSocket.close();
    }
    JOptionPane.showMessageDialog(null
      , "發(fā)送信息異常,請確認30001端口空閑,且網(wǎng)絡連接正常!"
      , "網(wǎng)絡異常", JOptionPane.ERROR_MESSAGE);
    System.exit(1);
   }
  }
  // 不斷從DatagramSocket中讀取數(shù)據(jù)的線程
  class ReadSingle extends Thread
  {
   // 定義接收網(wǎng)絡數(shù)據(jù)的字節(jié)數(shù)組
   byte[] singleBuff = new byte[DATA_LEN];
   private DatagramPacket singlePacket =
    new DatagramPacket(singleBuff , singleBuff.length);
   public void run()
   {
    while (true)
    {
      try
      {
       // 讀取Socket中的數(shù)據(jù)。
       singleSocket.receive(singlePacket);
       // 處理讀到的信息
       lanTalk.processMsg(singlePacket , true);
      }
      // 捕捉異常
      catch (IOException ex)
      {
       ex.printStackTrace();
       if (singleSocket != null)
       {
        // 關(guān)閉該Socket對象
        singleSocket.close();
       }
       JOptionPane.showMessageDialog(null
        , "接收信息異常,請確認30001端口空閑,且網(wǎng)絡連接正常!"
        , "網(wǎng)絡異常", JOptionPane.ERROR_MESSAGE);
       System.exit(1);
      }
    }
   }
  }
  // 持續(xù)讀取MulticastSocket的線程
  class ReadBroad extends Thread
  {
   public void run()
   {
    while (true)
    {
      try
      {
       // 讀取Socket中的數(shù)據(jù)。
       socket.receive(inPacket);
       // 打印輸出從socket中讀取的內(nèi)容
       String msg = new String(inBuff , 0
        , inPacket.getLength() , CHARSET);
       // 讀到的內(nèi)容是在線信息
       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 delList = new ArrayList<>();
        // 遍歷系統(tǒng)中已有的所有用戶,該循環(huán)必須循環(huán)完成
        for (int i = 1 ; i < lanTalk.getUserNum() ; i++ )
        {
          UserInfo current = lanTalk.getUser(i);
          // 將所有用戶失去聯(lián)系的次數(shù)加1
          current.setLost(current.getLost() + 1);
          // 如果該信息由指定用戶發(fā)送過來
          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);
        }
       }
       // 讀到的內(nèi)容是公聊信息
       else
       {
        // 處理讀到的信息
        lanTalk.processMsg(inPacket , false);
       }
      }
      // 捕捉異常
      catch (IOException ex)
      {
       ex.printStackTrace();
       if (socket != null)
       {
        // 關(guān)閉該Socket對象
        socket.close();
       }
       JOptionPane.showMessageDialog(null
        , "接收信息異常,請確認30000端口空閑,且網(wǎng)絡連接正常!"
        , "網(wǎng)絡異常", 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 listModel
   = new DefaultListModel<>();
  // 定義一個JList對象
  private JList friendsList = new JList<>(listModel);
  // 定義一個用于格式化日期的格式器
  private DateFormat formatter = DateFormat.getDateTimeInstance();
  public LanTalk()
  {
   super("局域網(wǎng)聊天");
   // 設置該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);
  }
  // 根據(jù)地址來查詢用戶
  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);
  }
  // 獲取該聊天窗口的用戶數(shù)量
  public int getUserNum()
  {
   return listModel.size();
  }
  // 獲取指定位置的用戶
  public UserInfo getUser(int pos)
  {
   return listModel.elementAt(pos);
  }
  // 實現(xiàn)JList上的鼠標雙擊事件的監(jiān)聽器
  class ChangeMusicListener extends MouseAdapter
  {
   public void mouseClicked(MouseEvent e)
   {
    // 如果鼠標的擊鍵次數(shù)大于2
    if (e.getClickCount() >= 2)
    {
      // 取出鼠標雙擊時選中的列表項
      UserInfo user = (UserInfo)friendsList.getSelectedValue();
      // 如果該列表項對應用戶的交談窗口為null
      if (user.getChatFrame() == null)
      {
       // 為該用戶創(chuàng)建一個交談窗口,并讓該用戶引用該窗口
       user.setChatFrame(new ChatFrame(null , user));
      }
      // 如果該用戶的窗口沒有顯示,則讓該用戶的窗口顯示出來
      if (!user.getChatFrame().isShowing())
      {
       user.getChatFrame().setVisible(true);
      }
    }
   }
  }
  /**
  * 處理網(wǎng)絡數(shù)據(jù)報,該方法將根據(jù)聊天信息得到聊天者,
  * 并將信息顯示在聊天對話框中。
  * @param packet 需要處理的數(shù)據(jù)報
  * @param single 該信息是否為私聊信息
  */
  public void processMsg(DatagramPacket packet , boolean single)
  {
   // 獲取該發(fā)送該數(shù)據(jù)報的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
{
  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 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;
  // 構(gòu)造器,用于初始化的登錄對話框
  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);
  }
  // 定義一個事件監(jiān)聽器
  class MyActionListener implements ActionListener
  {
   private LoginFrame loginFrame;
   public MyActionListener(LoginFrame loginFrame)
   {
    this.loginFrame = loginFrame;
   }
   // 當鼠標單擊事件發(fā)生時
   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端口空閑,且網(wǎng)絡正常!");
    }
   }
  }
}
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
{
  // 聊天信息區(qū)
  JTextArea msgArea = new JTextArea(12 , 45);
  // 聊天輸入?yún)^(qū)
  JTextField chatField = new JTextField(30);
  // 發(fā)送聊天信息的按鈕
  JButton sendBn = new JButton("發(fā)送");
  // 該交談窗口對應的用戶
  UserInfo user;
  // 構(gòu)造器,用于初始化交談對話框的界面
  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);
   // 發(fā)送消息的Action,Action是ActionListener的子接口
   Action sendAction = new AbstractAction()
   {
    @Override
    public void actionPerformed(ActionEvent evt)
    {
      InetSocketAddress dest = (InetSocketAddress)user.getAddress();
      // 在聊友列表中,所有人項的SocketAddress是null
      // 這表明是向所有人發(fā)送消息
      if (dest == null)
      {
       LoginFrame.comUtil.broadCast(chatField.getText());
       msgArea.setText("您對大家說:"
        + chatField.getText() + "\n" + msgArea.getText());
      }
      // 向私人發(fā)送信息
      else
      {
       // 獲取發(fā)送消息的目的
       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"關(guān)聯(lián)
   chatField.getInputMap().put(KeyStroke.getKeyStroke('\n'
    , java.awt.event.InputEvent.CTRL_MASK) , "send");
   // 將"send"與sendAction關(guān)聯(lián)
   chatField.getActionMap().put("send", sendAction);
   pack();
  }
  // 定義向聊天區(qū)域添加消息的方法
  public void addString(String msg)
  {
   msgArea.setText(msg + "\n" + msgArea.getText());
  }
}

上述內(nèi)容就是如何在java項目中使用MulticastSocket,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


分享題目:如何在java項目中使用MulticastSocket
URL分享:http://weahome.cn/article/ggodsp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部