意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

UDP实现群聊聊天室

来源:恒创科技 编辑:恒创科技编辑部
2024-01-29 08:36:59

  大家好,今天为大家带来了一个非常有意思的小程序——UDP实现的群聊聊天室。这个程序使用的UDP协议,并使用DatagramSocket的子类MulticastSocket实现组播,可以部署在一个局域网内的多台电脑上,并可以实现文字群聊。

   本文将会按照以下几个小节讲解:

   1). 组播的概念:**这个小节我们将讲解什么是:单播、广播、组播。


UDP实现群聊聊天室

   2). MulticastSocket类的使用:**这个小节我们将讲解MulticastSocket类的基本使用,并实现控制台的信息收发。

   3). 基于Swing和MulticastSocket实现的UDP群聊聊天室:**这个小节我们将制作一个界面,并结合MulticastSocket类实现一个完整的UDP群聊聊天室。

   4). 结束语:

  一、组播的概念

   网络数据传播按照接收者的数量,可分为以下3种方式:

  1.1 单播:

   单播是指实现“点对点”的通信,发送者发送数据要发送给网络上的唯一的一台电脑,指定一个接收者。像TCP协议和UDP协议都能实现点对点通信。

  1.2 广播:

   发送者发送的数据可以被某个接收范围内所有的接收者接收。它类似于广播电台,向某个范围内的所有用户发送广播信号,接收人打开广播就可以听到,关闭广播设备就停止收听。由于广播会大大增加网络数据流量,所以通常情况下一些网络路由器会禁止广播数据,尤其是一些占用网络资源比较大的视频数据等。

  1.3 组播:

   组播是指发送的数据可以被指定的一组用户接收。组播的范围没有广播那么广,任何的一台电脑都可以随时加入某一个组接收组播数据。若要使用组播,则需要让一个数据报标有一组目标主机地址,当数据报发出后,整个组的所有主机都能收到该数据报。IP协议为组播提供了这批特殊的IP地址,这些IP地址的范围是224.0.0.0至239.255.255.255。在Java类库中,DatagramSocket有一个子类:MulticastSocket,它具有组播的功能,它可以与DatagramPackage结合使用,用于发送和接收组播包。

  二. MulticastSocket类的使用

   Java类库中MulticastSocket类可以实现组播功能,它是DatagramSocket的子类:

  2.1 构造方法说明

   通过API文档我们可以看到它有三个构造方法:

1.MulticastSocket()创建一个多播套接字。(使用随机端口,如果只发送,可以使用这个构造方法)2.MulticastSocket(intport)创建一个多播套接字并将其绑定到一个特定的端口。(如果需要发送和接收,需要使用这个构造方法)3.MulticastSocket(SocketAddressbindaddr)创建一个多播套接字绑定到指定的套接字地址。

  2.2 成员方法说明

   以下是几个比较重要的成员方法:

1.publicvoidjoinGroup(InetAddressmcastaddr):将该MulticastSocket加入指定的多点广播地址。2.publicvoidleaveGroup(InetAddressmcastaddr让该MulticastSocket离开指定的多点广播地址。3.publicvoidsetInterface(InetAddressinf):如果当前系统有多个网络接口,可以使用次方法指定一个网络接口。4.publicInetAddressgetInterface():获取当前的网络接口。5.publicvoidsetTimeToLive(intttl):该参数设置数据报最多可以跨过多少个网络,当ttl为0时,指定数据报应停留在本地主机;当ttl的值为1时,指定数据报发送到本地局域网;当ttl的值为32时,意味着只能发送到本站点的网络上;当ttl为64时,意味着数据报应保留在本地区;当ttl的值为128时,意味着数据报应保留在本大洲;当ttl为255时,意味着数据报可发送到所有地方;默认情况下,该ttl的值为1。

  2.3 一个简单的示例

   接下来我们写一个小例子来看一下MulticastSocket的使用方式。这个程序将包含两个线程:1. 接收线程,主要用于接收信息;2. 主线程,主要用于发送信息。将这个程序部署到局域网上的几台电脑上,全部启动,就可以实现多台电脑的组播了,而且每台主机都可以发出信息,其它主机则会收到这条信息。

packagecom.heima.se.chat;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.InetAddress;importjava.net.MulticastSocket;importjava.util.Date;importjava.util.Scanner;publicclassMulticastSocketDemo{publicstaticvoidmain(String[]args)throwsIOException{//创建MuticastSocket对象,并监听端口55555MulticastSocketsocket=newMulticastSocket(55555);//加入组:235.235.235.235socket.joinGroup(InetAddress.getByName("235.235.235.235"));//启动线程-此线程用于接收数据报newThread(()->{byte[]bytes=newbyte[1024];DatagramPacketpacket=newDatagramPacket(bytes,bytes.length);while(true){try{socket.receive(packet);System.out.println(newString(packet.getData(),0,packet.getLength()));}catch(IOExceptione){e.printStackTrace();}}}).start();//获取本机IPStringlocalIp=InetAddress.getLocalHost().getHostAddress();//创建一个Scanner对象,用于接收控制台数据Scannersc=newScanner(System.in);while(true){System.out.println("【请输入信息】");Stringmsg=sc.next();//获取当前时间格式化字符串,把IP、时间,以及要发送的文本连接在一起Stringtime=String.format("<====>%tF%<tT",newDate());msg=localIp+time+"\n"+msg+"\n\n";//发送数据报socket.send(newDatagramPacket(msg.getBytes(),msg.getBytes().length,InetAddress.getByName("235.235.235.235"),55555));}}}

  通过上面的程序,我们发现,MulticastSocket类的使用和DatagramSocket类基本相同,只是多了一步加入组:joinGroup(),所有加入这个组的主机都将会收到信息。

  三. 基于Swing和MulticastSocket实现的UDP群聊聊天室

   接下来我们使用Swing为这个程序制作一个界面,让用户操作起来更加方便。

   这个程序我们制作了两个类:

   1). ChatFrame:这个类继承自JFrame,实现了界面的显示、布局等相关功能。

   2). SocketChat:这个类继承自ChatFrame,加入了MulticastSocket的连接、信息发送和接收。

  3.1 界面ChatFrame类

packagecom.heima.se.chat;importjavax.swing.*;importjava.awt.*;importjava.awt.event.*;importjava.net.InetAddress;publicabstractclassChatFrameextendsJFrame{privateJTextAreareceiveArea=newJTextArea();//接收文本框,用来显示服务器发送过来的文本privateJTextAreasendArea=newJTextArea();//发送文本框,用来显示当前用户要发送的文本privateJButtonsendBtn=newJButton("SEND");//发送按键publicChatFrame(){this.initFrame();//初始化窗口this.initComponent();//初始化组件this.initListener();//初始化监听器this.receive();//开启监听服务器线程,把接收到的文本显示在receiveArea中}//初始化监听器privatevoidinitListener(){//给发送按键添加监听器,当被点击时调用send()方法sendBtn.addActionListener(newActionListener(){publicvoidactionPerformed(ActionEventevt){send();}});//给发送文本框添加键盘监听器,当按下Ctrl+ENTER时调用send()方法sendArea.addKeyListener(newKeyAdapter(){publicvoidkeyPressed(KeyEvente){if(e.isControlDown()){if(e.getKeyCode()==KeyEvent.VK_ENTER){send();}}}});}//子类需要重写本方法//在本方法中使用socket实现消息发送publicabstractvoidsendText(Stringtext);//子类需要重写本方法//在本方法中启动监听服务器线程,调用本类receiveText(String)把接收到的文本显示出来publicabstractvoidreceive();//本方法用来发送文本publicvoidsend(){//如果发送文本框中没有文本,弹出警告对话框if(sendArea.getText().equals("")){javax.swing.JOptionPane.showMessageDialog(this,"空文本不能发送!");sendArea.requestFocus();//把光标归还给发送文本框return;}//调用子类的方法完成文本发送sendText(sendArea.getText());//把发送文本框内容清空sendArea.setText(null);}//本方法完成接收服务器消息的后续工作-在文本框中显示服务器消息,子类的receive()方法在接收服务器消息后可以调用本方法publicvoidreceiveText(Stringtext){receiveArea.append(text);//把接收到的消息添加到文本框中//设置光标位置到最后,如果不设置滚动条不动receiveArea.setCaretPosition(receiveArea.getText().length());}//初始化组件privatevoidinitComponent(){//使用接收文本框创建滚动窗口(把文本框添加到了滚动窗口中),总是显示纵向滚动条,永不显示横向滚动条JScrollPanesp1=newJScrollPane(receiveArea,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);//设置滚动窗口大小、位置、无边框;并把滚动窗口添加到主窗口中sp1.setSize(606,350);sp1.setLocation(14,20);sp1.setBorder(null);this.add(sp1);//设置接收文本框背景色、不可编辑、自动换行receiveArea.setBackground(newColor(238,238,238));receiveArea.setEditable(false);receiveArea.setLineWrap(true);//创建发送文本框的滚动窗口,设置自动换行、大小、位置,然后添加到主窗口中JScrollPanesp2=newJScrollPane(sendArea,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);sendArea.setLineWrap(true);sp2.setSize(606,145);sp2.setLocation(14,400);this.add(sp2);//设置发送按键的大小、位置,并添加到主窗口中sendBtn.setSize(68,21);sendBtn.setLocation(553,560);this.add(sendBtn);//设置主窗口的标题为当前IP地址try{this.setTitle(InetAddress.getLocalHost().getHostAddress());}catch(Exceptione){thrownewRuntimeException(e);}}//初始化主窗口privatevoidinitFrame(){//设置主窗口的大小、布局管理器为空、背景色、位置、大小不可改变this.setSize(640,620);this.setLayout(null);this.setBackground(newColor(246,246,247));this.setLocation(350,50);this.setResizable(false);//设置主窗口的“X”按钮点击后结束程序this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}//显示主窗口方法publicvoidsetVisible(booleanb){super.setVisible(b);//调用父类的显示方法sendArea.requestFocus();//让发送文本框得到焦点}}

  这个类中定义了很多抽象方法,这些抽象方法由子类实现。

  3.2 组播聊天SocketChat类

packagecom.heima.se.chat;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.InetAddress;importjava.net.MulticastSocket;importjava.util.Date;/***本类继承了ChatFrame,ChatFrame实现了GUI显示*本类负责使用MulticastSocket完成群聊的发送消息与接收消息*/publicclassSocketChatextendsChatFrame{privateMulticastSocketsocket;//群组SocketpublicSocketChat()throwsIOException{socket=newMulticastSocket(54321);//创建群组Socket,绑定54321端口//加入虚拟IP:235.235.235.235指定的群组中。虚拟IP范围是:224.0.0.1和239.255.255.255//加入群组后,就可以接收群组的消息,也可以向群组发送消息了socket.joinGroup(InetAddress.getByName("235.235.235.235"));}//发送消息方法publicvoidsendText(Stringtext){try{//获取IP地址Stringip=InetAddress.getLocalHost().getHostAddress();//获取当前时间格式化字符串Stringtime=String.format("<====>%tF%<tT",newDate());//把IP、时间,以及要发送的文本连接在一起text=ip+time+"\n"+text+"\n\n";//把文本转换成字节数组byte[]buff=text.getBytes();//使用socket向群组发送,socket的send()方法需要两个参数:DatagramPacket、端口号//DatagramPacket表示数据包,创建它需要三个参数:数据包的内容、数据包的字节数、要发送的IP地址socket.send(newDatagramPacket(buff,buff.length,InetAddress.getByName("235.235.235.235"),54321));}catch(Exceptione){e.printStackTrace();}}//本方法用来接收群组发送过来的消息publicvoidreceive(){//创建监听群组消息的线程,并启动它newThread(){publicvoidrun(){//循环监听while(true){try{//创建数据包的字节数组,大小为1KBbyte[]buff=newbyte[1024];//创建数据包DatagramPacketdp=newDatagramPacket(buff,buff.length);//接收群组发送过来的消息到数据包中//本方法会阻塞当前线程,直到接收到消息为止socket.receive(dp);//把接收到的消息转换成字符串Stringtext=newString(dp.getData(),0,dp.getLength());//调用父类的方法完成显示receiveText(text);}catch(Exceptione){}}}}.start();}publicstaticvoidmain(String[]args)throwsIOException{SocketChatsc=newSocketChat();sc.setVisible(true);}}

  这个类使用MulticastSocket,使用端口:54321,组播地址:235.235.235.235。当用户在界面按下send按钮时,会触发sendText()方法发送数据;receive()方法用于使用线程接收数据,它是在父类的构造方法中被触发启动,启动后,使用无限循环进行信息的接收。

  四.结束语

   这篇文章我们使用MulticastSocket类实现了组播功能,并使用Swing和MulticastSocket制作了一个基于UDP的群聊聊天室,希望大家能够通过本篇文章了解MulticastSocket类的使用,有兴趣的朋友可以基于这个程序,为它添加更多的功能,例如:文件的发送、接收;表情图片的发送、接收等等。后面我还会为大家带来更多更实用的程序,期待大家来围观哦!谢谢大家!!

上一篇: k8s快速入门 下一篇: 手机怎么远程登录云服务器?