如何在java项目中使用MulticastSocket
本篇文章为大家展示了如何在java项目中使用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中读取数据。
packagecom.talk; importjava.io.IOException; importjava.net.DatagramPacket; importjava.net.InetAddress; importjava.net.MulticastSocket; importjava.util.Scanner; //让该类实现Runnable接口,该类的实例可以作为线程的target publicclassMulticastSocketTestimplementsRunnable{ //使用常量作为本程序多点广播的IP地址 privatestaticfinalStringBROADCAST_IP="230.0.0.1"; //使用常量作为本程序的多点广播的目的地端口 publicstaticfinalintBROADCAST_PORT=3000; //定义每个数据报大小最大为4kb privatestaticfinalintDATA_LEN=4096; //定义本程序的MulticastSocket实例 privateMulticastSocketsocket=null; privateInetAddressbroadcastAddress=null; privateScannerscan=null; //定义接收网络数据的字节数组 byte[]inBuff=newbyte[DATA_LEN]; //以指定字节数组创建准备接收数据的MulticastSocket对象 privateDatagramPacketinPacket=newDatagramPacket(inBuff,inBuff.length); //定义一个用于发送的DatagramPacket对象 privateDatagramPacketoutPacket=null; publicvoidinit()throwsIOException{ //创建键盘输入流 Scannerscan=newScanner(System.in); //创建用于发送、接收数据的MulticastSocket对象,由于该MulticastSocket需要接收数据,所以有指定端口 socket=newMulticastSocket(BROADCAST_PORT); broadcastAddress=InetAddress.getByName(BROADCAST_IP); //将该socket加入到指定的多点广播地址 socket.joinGroup(broadcastAddress); //设置本MulticastSocket发送的数据报会被回送到自身 socket.setLoopbackMode(false); //初始化发送用的DatagramSocket,它包含一个长度为0的字节数组 outPacket=newDatagramPacket(newbyte[0],0,broadcastAddress,BROADCAST_PORT); //启动本实例的run()方法作为线程执行体的线程 newThread(this).start(); //不断的读取键盘输入 while(scan.hasNextLine()){ //将键盘输入的一行字符转换成字节数组 byte[]buff=scan.nextLine().getBytes(); //设置发送用的DatagramPacket里的字节数据 outPacket.setData(buff); //发送数据报 socket.send(outPacket); } socket.close(); } publicvoidrun(){ //TODOAuto-generatedmethodstub while(true){ //读取Socket中的数据,读到的数据放入inPacket所封装的字节组里 try{ socket.receive(inPacket); //打印从socket读取到的内容 System.out.println("聊天信息:"+newString(inBuff,0,inPacket.getLength())); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } if(socket!=null){ //让该socket离开多点IP广播地址 try{ socket.leaveGroup(broadcastAddress); //关闭socket对象 socket.close(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } System.exit(1); } } publicstaticvoidmain(String[]args){ try{ newMulticastSocketTest().init(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock 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以及该用户对应的交谈窗口,失去联系的次数等信息:
packagecom.talk; importjava.net.SocketAddress; importcom.bank.ChatFrame; publicclassUserInfo { //该用户的图标 privateStringicon; //该用户的名字 privateStringname; //该用户的MulitcastSocket所在的IP和端口 privateSocketAddressaddress; //该用户失去联系的次数 privateintlost; //该用户对应的交谈窗口 privateChatFramechatFrame; publicUserInfo(){} //有参数的构造器 publicUserInfo(Stringicon,Stringname ,SocketAddressaddress,intlost) { this.icon=icon; this.name=name; this.address=address; this.lost=lost; } //省略所有成员变量的setter和getter方法 //icon的setter和getter方法 publicvoidsetIcon(Stringicon) { this.icon=icon; } publicStringgetIcon() { returnthis.icon; } //name的setter和getter方法 publicvoidsetName(Stringname) { this.name=name; } publicStringgetName() { returnthis.name; } //address的setter和getter方法 publicvoidsetAddress(SocketAddressaddress) { this.address=address; } publicSocketAddressgetAddress() { returnthis.address; } //lost的setter和getter方法 publicvoidsetLost(intlost) { this.lost=lost; } publicintgetLost() { returnthis.lost; } //chatFrame的setter和getter方法 publicvoidsetChatFrame(ChatFramechatFrame) { this.chatFrame=chatFrame; } publicChatFramegetChatFrame() { returnthis.chatFrame; } //使用address作为该用户的标识,所以根据address作为 //重写hashCode()和equals方法的标准 publicinthashCode() { returnaddress.hashCode(); } publicbooleanequals(Objectobj) { if(obj!=null&&obj.getClass()==UserInfo.class) { UserInfotarget=(UserInfo)obj; if(address!=null) { returnaddress.equals(target.getAddress()); } } returnfalse; } }
通过UserInfo的封装,所有客户端只需要维护该UserInfo类的列表,程序就可以实现广播、发送私聊信息等功能。本程序的底层通信类则需要一个MulticastSocket和一个DatagramSocket,该工具类的代码如下:
packagecom.talk; importjava.io.IOException; importjava.net.DatagramPacket; importjava.net.DatagramSocket; importjava.net.InetAddress; importjava.net.MulticastSocket; importjava.net.SocketAddress; importjava.util.ArrayList; importjavax.swing.JOptionPane; publicclassComUtil { //定义本程序通信所使用的字符集 publicstaticfinalStringCHARSET="utf-8"; //使用常量作为本程序的多点广播IP地址 privatestaticfinalStringBROADCAST_IP ="230.0.0.1"; //使用常量作为本程序的多点广播目的的端口 //DatagramSocket所用的的端口为该端口+1。 publicstaticfinalintBROADCAST_PORT=30000; //定义每个数据报的最大大小为4K privatestaticfinalintDATA_LEN=4096; //定义本程序的MulticastSocket实例 privateMulticastSocketsocket=null; //定义本程序私聊的Socket实例 privateDatagramSocketsingleSocket=null; //定义广播的IP地址 privateInetAddressbroadcastAddress=null; //定义接收网络数据的字节数组 byte[]inBuff=newbyte[DATA_LEN]; //以指定字节数组创建准备接受数据的DatagramPacket对象 privateDatagramPacketinPacket= newDatagramPacket(inBuff,inBuff.length); //定义一个用于发送的DatagramPacket对象 privateDatagramPacketoutPacket=null; //聊天的主界面程序 privateLanTalklanTalk; //构造器,初始化资源 publicComUtil(LanTalklanTalk)throwsException { this.lanTalk=lanTalk; //创建用于发送、接收数据的MulticastSocket对象 //因为该MulticastSocket对象需要接收,所以有指定端口 socket=newMulticastSocket(BROADCAST_PORT); //创建私聊用的DatagramSocket对象 singleSocket=newDatagramSocket(BROADCAST_PORT+1); broadcastAddress=InetAddress.getByName(BROADCAST_IP); //将该socket加入指定的多点广播地址 socket.joinGroup(broadcastAddress); //设置本MulticastSocket发送的数据报被回送到自身 socket.setLoopbackMode(false); //初始化发送用的DatagramSocket,它包含一个长度为0的字节数组 outPacket=newDatagramPacket(newbyte[0] ,0,broadcastAddress,BROADCAST_PORT); //启动两个读取网络数据的线程 newReadBroad().start(); Thread.sleep(1); newReadSingle().start(); } //广播消息的工具方法 publicvoidbroadCast(Stringmsg) { try { //将msg字符串转换字节数组 byte[]buff=msg.getBytes(CHARSET); //设置发送用的DatagramPacket里的字节数据 outPacket.setData(buff); //发送数据报 socket.send(outPacket); } //捕捉异常 catch(IOExceptionex) { ex.printStackTrace(); if(socket!=null) { //关闭该Socket对象 socket.close(); } JOptionPane.showMessageDialog(null ,"发送信息异常,请确认30000端口空闲,且网络连接正常!" ,"网络异常",JOptionPane.ERROR_MESSAGE); System.exit(1); } } //定义向单独用户发送消息的方法 publicvoidsendSingle(Stringmsg,SocketAddressdest) { try { //将msg字符串转换字节数组 byte[]buff=msg.getBytes(CHARSET); DatagramPacketpacket=newDatagramPacket(buff ,buff.length,dest); singleSocket.send(packet); } //捕捉异常 catch(IOExceptionex) { ex.printStackTrace(); if(singleSocket!=null) { //关闭该Socket对象 singleSocket.close(); } JOptionPane.showMessageDialog(null ,"发送信息异常,请确认30001端口空闲,且网络连接正常!" ,"网络异常",JOptionPane.ERROR_MESSAGE); System.exit(1); } } //不断从DatagramSocket中读取数据的线程 classReadSingleextendsThread { //定义接收网络数据的字节数组 byte[]singleBuff=newbyte[DATA_LEN]; privateDatagramPacketsinglePacket= newDatagramPacket(singleBuff,singleBuff.length); publicvoidrun() { while(true) { try { //读取Socket中的数据。 singleSocket.receive(singlePacket); //处理读到的信息 lanTalk.processMsg(singlePacket,true); } //捕捉异常 catch(IOExceptionex) { ex.printStackTrace(); if(singleSocket!=null) { //关闭该Socket对象 singleSocket.close(); } JOptionPane.showMessageDialog(null ,"接收信息异常,请确认30001端口空闲,且网络连接正常!" ,"网络异常",JOptionPane.ERROR_MESSAGE); System.exit(1); } } } } //持续读取MulticastSocket的线程 classReadBroadextendsThread { publicvoidrun() { while(true) { try { //读取Socket中的数据。 socket.receive(inPacket); //打印输出从socket中读取的内容 Stringmsg=newString(inBuff,0 ,inPacket.getLength(),CHARSET); //读到的内容是在线信息 if(msg.startsWith(YeekuProtocol.PRESENCE) &&msg.endsWith(YeekuProtocol.PRESENCE)) { StringuserMsg=msg.substring(2 ,msg.length()-2); String[]userInfo=userMsg.split(YeekuProtocol .SPLITTER); UserInfouser=newUserInfo(userInfo[1] ,userInfo[0],inPacket.getSocketAddress(),0); //控制是否需要添加该用户的旗标 booleanaddFlag=true; ArrayList<Integer>delList=newArrayList<>(); //遍历系统中已有的所有用户,该循环必须循环完成 for(inti=1;i<lanTalk.getUserNum();i++) { UserInfocurrent=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(inti=0;i<delList.size();i++) { lanTalk.removeUser(delList.get(i)); } if(addFlag) { //添加新用户 lanTalk.addUser(user); } } //读到的内容是公聊信息 else { //处理读到的信息 lanTalk.processMsg(inPacket,false); } } //捕捉异常 catch(IOExceptionex) { ex.printStackTrace(); if(socket!=null) { //关闭该Socket对象 socket.close(); } JOptionPane.showMessageDialog(null ,"接收信息异常,请确认30000端口空闲,且网络连接正常!" ,"网络异常",JOptionPane.ERROR_MESSAGE); System.exit(1); } } } } }
本程序的一个主类,LanTalk ,该类使用DefaultListModel来维护用户列表,该类里的每个列表项就是一个UserInfo。该类还提供了一个ImageCellRenderer,该类用于将列表项绘制出用户图标和用户名字。
packagecom.talk; importjava.awt.Color; importjava.awt.Component; importjava.awt.Dimension; importjava.awt.Font; importjava.awt.Graphics; importjava.awt.event.MouseAdapter; importjava.awt.event.MouseEvent; importjava.net.DatagramPacket; importjava.net.InetSocketAddress; importjava.net.SocketAddress; importjava.text.DateFormat; importjava.util.Date; importjavax.swing.DefaultListModel; importjavax.swing.ImageIcon; importjavax.swing.JFrame; importjavax.swing.JList; importjavax.swing.JPanel; importjavax.swing.JScrollPane; importjavax.swing.ListCellRenderer; importcom.bank.ChatFrame; importcom.bank.LoginFrame; publicclassLanTalkextendsJFrame { privateDefaultListModel<UserInfo>listModel =newDefaultListModel<>(); //定义一个JList对象 privateJList<UserInfo>friendsList=newJList<>(listModel); //定义一个用于格式化日期的格式器 privateDateFormatformatter=DateFormat.getDateTimeInstance(); publicLanTalk() { super("局域网聊天"); //设置该JList使用ImageCellRenderer作为单元格绘制器 friendsList.setCellRenderer(newImageCellRenderer()); listModel.addElement(newUserInfo("all","所有人" ,null,-2000)); friendsList.addMouseListener(newChangeMusicListener()); add(newJScrollPane(friendsList)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(2,2,160,600); } //根据地址来查询用户 publicUserInfogetUserBySocketAddress(SocketAddressaddress) { for(inti=1;i<getUserNum();i++) { UserInfouser=getUser(i); if(user.getAddress()!=null &&user.getAddress().equals(address)) { returnuser; } } returnnull; } //------下面四个方法是对ListModel的包装------ //向用户列表中添加用户 publicvoidaddUser(UserInfouser) { listModel.addElement(user); } //从用户列表中删除用户 publicvoidremoveUser(intpos) { listModel.removeElementAt(pos); } //获取该聊天窗口的用户数量 publicintgetUserNum() { returnlistModel.size(); } //获取指定位置的用户 publicUserInfogetUser(intpos) { returnlistModel.elementAt(pos); } //实现JList上的鼠标双击事件的监听器 classChangeMusicListenerextendsMouseAdapter { publicvoidmouseClicked(MouseEvente) { //如果鼠标的击键次数大于2 if(e.getClickCount()>=2) { //取出鼠标双击时选中的列表项 UserInfouser=(UserInfo)friendsList.getSelectedValue(); //如果该列表项对应用户的交谈窗口为null if(user.getChatFrame()==null) { //为该用户创建一个交谈窗口,并让该用户引用该窗口 user.setChatFrame(newChatFrame(null,user)); } //如果该用户的窗口没有显示,则让该用户的窗口显示出来 if(!user.getChatFrame().isShowing()) { user.getChatFrame().setVisible(true); } } } } /** *处理网络数据报,该方法将根据聊天信息得到聊天者, *并将信息显示在聊天对话框中。 *@parampacket需要处理的数据报 *@paramsingle该信息是否为私聊信息 */ publicvoidprocessMsg(DatagramPacketpacket,booleansingle) { //获取该发送该数据报的SocketAddress InetSocketAddresssrcAddress=(InetSocketAddress) packet.getSocketAddress(); //如果是私聊信息,则该Packet获取的是DatagramSocket的地址, //将端口减1才是对应的MulticastSocket的地址 if(single) { srcAddress=newInetSocketAddress(srcAddress.getHostName() ,srcAddress.getPort()-1); } UserInfosrcUser=getUserBySocketAddress(srcAddress); if(srcUser!=null) { //确定消息将要显示到哪个用户对应窗口上。 UserInfoalertUser=single?srcUser:getUser(0); //如果该用户对应的窗口为空,显示该窗口 if(alertUser.getChatFrame()==null) { alertUser.setChatFrame(newChatFrame(null,alertUser)); } //定义添加的提示信息 StringtipMsg=single?"对您说:":"对大家说:"; try{ //显示提示信息 alertUser.getChatFrame().addString(srcUser.getName() +tipMsg+"......................(" +formatter.format(newDate())+")\n" +newString(packet.getData(),0,packet.getLength() ,ComUtil.CHARSET)+"\n"); }catch(Exceptionex){ex.printStackTrace();} if(!alertUser.getChatFrame().isShowing()) { alertUser.getChatFrame().setVisible(true); } } } //主方法,程序的入口 publicstaticvoidmain(String[]args) { LanTalklanTalk=newLanTalk(); newLoginFrame(lanTalk,"请输入用户名、头像后登录"); } } //定义用于改变JList列表项外观的类 classImageCellRendererextendsJPanel implementsListCellRenderer<UserInfo> { privateImageIconicon; privateStringname; //定义绘制单元格时的背景色 privateColorbackground; //定义绘制单元格时的前景色 privateColorforeground; @Override publicComponentgetListCellRendererComponent(JListlist ,UserInfouserInfo,intindex ,booleanisSelected,booleancellHasFocus) { //设置图标 icon=newImageIcon("ico/"+userInfo.getIcon()+".gif"); name=userInfo.getName(); //设置背景色、前景色 background=isSelected?list.getSelectionBackground() :list.getBackground(); foreground=isSelected?list.getSelectionForeground() :list.getForeground(); //返回该JPanel对象作为单元格绘制器 returnthis; } //重写paintComponent方法,改变JPanel的外观 publicvoidpaintComponent(Graphicsg) { intimageWidth=icon.getImage().getWidth(null); intimageHeight=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(newFont("SansSerif",Font.BOLD,18)); //绘制好友用户名 g.drawString(name,getWidth()/2-name.length()*10 ,imageHeight+30); } //通过该方法来设置该ImageCellRenderer的最佳大小 publicDimensiongetPreferredSize() { returnnewDimension(60,80); } }
除了以上主要的代码,还有YeekuProtocol ChatFrame LoginFrame等类:
packagecom.talk; publicinterfaceYeekuProtocol { StringPRESENCE="⊿⊿"; StringSPLITTER="▓"; }
packagecom.bank; importjava.awt.Dimension; importjava.awt.Font; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JComboBox; importjavax.swing.JComponent; importjavax.swing.JDialog; importjavax.swing.JLabel; importjavax.swing.JPanel; importjavax.swing.JTextField; importcom.talk.ComUtil; importcom.talk.LanTalk; importcom.talk.YeekuProtocol; //登录用的对话框 publicclassLoginFrameextendsJDialog { publicJLabeltip; publicJTextFielduserField=newJTextField("钱钟书",20); publicJComboBox<Integer>iconList=newJComboBox<>( newInteger[]{1,2,3,4,5,6,7,8,9,10}); privateJButtonloginBn=newJButton("登录"); //聊天的主界面 privateLanTalkchatFrame; //聊天通信的工具实例 publicstaticComUtilcomUtil; //构造器,用于初始化的登录对话框 publicLoginFrame(LanTalkparent,Stringmsg) { super(parent,"输入名字后登录",true); this.chatFrame=parent; setLayout(newGridLayout(5,1)); JPaneljp=newJPanel(); tip=newJLabel(msg); tip.setFont(newFont("Serif",Font.BOLD,16)); jp.add(tip); add(jp); add(getPanel("用户名",userField)); iconList.setPreferredSize(newDimension(224,20)); add(getPanel("图标",iconList)); JPanelbp=newJPanel(); loginBn.addActionListener(newMyActionListener(this)); bp.add(loginBn); add(bp); pack(); setVisible(true); } //工具方法,该方法将一个字符串和组件组合成JPanel对象 privateJPanelgetPanel(Stringname,JComponentjf) { JPaneljp=newJPanel(); jp.add(newJLabel(name+":")); jp.add(jf); returnjp; } //该方法用于改变登录窗口最上面的提示信息 publicvoidsetTipMsg(Stringtip) { this.tip.setText(tip); } //定义一个事件监听器 classMyActionListenerimplementsActionListener { privateLoginFrameloginFrame; publicMyActionListener(LoginFrameloginFrame) { this.loginFrame=loginFrame; } //当鼠标单击事件发生时 publicvoidactionPerformed(ActionEventevt) { try { //初始化聊天通信类 comUtil=newComUtil(chatFrame); finalStringloginMsg=YeekuProtocol.PRESENCE+userField.getText() +YeekuProtocol.SPLITTER+iconList.getSelectedObjects()[0] +YeekuProtocol.PRESENCE; comUtil.broadCast(loginMsg); //启动定时器每20秒广播一次在线信息 javax.swing.Timertimer=newjavax.swing.Timer(1000*10 ,event->comUtil.broadCast(loginMsg)); timer.start(); loginFrame.setVisible(false); chatFrame.setVisible(true); } catch(Exceptionex) { loginFrame.setTipMsg("确认30001端口空闲,且网络正常!"); } } } }
packagecom.bank; importjava.awt.BorderLayout; importjava.awt.event.ActionEvent; importjava.net.InetSocketAddress; importjavax.swing.AbstractAction; importjavax.swing.Action; importjavax.swing.JButton; importjavax.swing.JDialog; importjavax.swing.JLabel; importjavax.swing.JPanel; importjavax.swing.JScrollPane; importjavax.swing.JTextArea; importjavax.swing.JTextField; importjavax.swing.KeyStroke; importcom.talk.LanTalk; importcom.talk.UserInfo; //定义交谈的对话框 publicclassChatFrameextendsJDialog { //聊天信息区 JTextAreamsgArea=newJTextArea(12,45); //聊天输入区 JTextFieldchatField=newJTextField(30); //发送聊天信息的按钮 JButtonsendBn=newJButton("发送"); //该交谈窗口对应的用户 UserInfouser; //构造器,用于初始化交谈对话框的界面 publicChatFrame(LanTalkparent,finalUserInfouser) { super(parent,"和"+user.getName()+"聊天中",false); this.user=user; msgArea.setEditable(false); add(newJScrollPane(msgArea)); JPanelbuttom=newJPanel(); buttom.add(newJLabel("输入信息:")); buttom.add(chatField); buttom.add(sendBn); add(buttom,BorderLayout.SOUTH); //发送消息的Action,Action是ActionListener的子接口 ActionsendAction=newAbstractAction() { @Override publicvoidactionPerformed(ActionEventevt) { InetSocketAddressdest=(InetSocketAddress)user.getAddress(); //在聊友列表中,所有人项的SocketAddress是null //这表明是向所有人发送消息 if(dest==null) { LoginFrame.comUtil.broadCast(chatField.getText()); msgArea.setText("您对大家说:" +chatField.getText()+"\n"+msgArea.getText()); } //向私人发送信息 else { //获取发送消息的目的 dest=newInetSocketAddress(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(); } //定义向聊天区域添加消息的方法 publicvoidaddString(Stringmsg) { msgArea.setText(msg+"\n"+msgArea.getText()); } }
上述内容就是如何在java项目中使用MulticastSocket,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注恰卡编程网行业资讯频道。