zoukankan      html  css  js  c++  java
  • java 网络编程基础 UDP协议DatagramSocket,MulticastSocket 实现局域网聊天软件(Server + Client模式)

     
    开发思路:
    服务端两个Socket:
    1. UDP的DatagramSocket接收客户端消息。
    2. 广播multicastSocket 发送广播消息

    客户端一个Socket:

    1. multicastSocket 接收服务端发来的广播 (不允许客户端直接发广播),同时发送点对点数据到UDP服务端DatagramSocket 。
    2. javax.swing.* 提供客户端图形化界面

    生疏知识点:

    图形化界面按钮监控键盘

    addActionListener(AbstractAction接口实现类);监听器。
    topTextField.getInputMap().put(KeyStroke.getKeyStroke('
    '),"confirm_username"); 键盘事件和名字关联;
    topTextField.getActionMap().put("confirm_username",confirmListener); 事件别名和监听器关联
    服务器端程序:
    package tcpandudp.udpexample;
    
    import java.io.IOException;
    import java.net.*;
    
    /**
     * @ClassName MulticastServerScoket
     * @projectName: object1
     * @author: Zhangmingda
     * @description: 设计思想:为避免所有人直接发广播,导致消息内容无环节把控,消息发送的时候,发送到非广播端口(作为一个服务端)再由此服务端向广播地址发送消息,
     * date: 2021/5/13.
     */
    public class MulticastServerScoket {
        /**
         * 广播Socket端口
         */
        private static final int BROAD_PORT = 30000;
        /**
         * 广播IP地址 :224.0.0.0 到 239.255.255.255
         */
        private static final String BROAD_IP = "230.3.3.3";
        /**
         * 服务端口
         */
        private static final int SERVER_PORT = 8888;
        private void start(){
            try (
                    /**
                     * 广播用套接字
                     */
                    MulticastSocket multicastSocket = new MulticastSocket(BROAD_PORT);
                     /**
                      * 服务端套接字
                      */
                     DatagramSocket datagramSocket = new DatagramSocket(SERVER_PORT)
            ){
                /**
                 * 广播IP地址
                 */
                InetAddress multi_addr = InetAddress.getByName(BROAD_IP);
                /**
                 * 广播套接字配置接收广播的IP地址
                 */
                multicastSocket.joinGroup(multi_addr);
                /**
                 * 构建接收UDP数据的包
                 */
                byte[] inBuff = new byte[4096];
                DatagramPacket inPacket = new DatagramPacket(inBuff,inBuff.length);
                /**
                 * 接收广播,并广播出去
                 */
                while (true){
                    //普通套接字收广播
                    datagramSocket.receive(inPacket);
    
                    String content = new String(inPacket.getData(),0,inPacket.getLength());
                    System.out.println(content);
                    //广播套接字发广播
                    DatagramPacket outPacket = new DatagramPacket(inPacket.getData(),inPacket.getLength(),multi_addr,BROAD_PORT);
                    multicastSocket.send(outPacket);
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         * 程序入口
         */
        public static void main(String[] args) {
            new MulticastServerScoket().start();
        }
    }

    客户端

    package tcpandudp.udpexample;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    import java.net.*;
    import java.util.Scanner;
    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * @ClassName MulticastClientSocket
     * @projectName: object1
     * @author: Zhangmingda
     * @description: XXX
     * date: 2021/5/13.
     */
    public class MulticastClientSocket {
        /**
         * 广播Socket端口
         */
        private static final int BROAD_PORT = 30000;
        /**
         * 广播IP地址 :224.0.0.0 到 239.255.255.255
         */
        private static final String BROAD_IP = "230.3.3.3";
    
        /**
         * 要发送数据包的服务端IP地址和 端口
         */
        private static final String SERVER_IP = "127.0.0.1";
        private static final int    SERVER_PORT = 8888;
    
        private void go() {
            JFrame jFrame = new JFrame("广播聊天客户端");
            //上部
            JPanel topPanel = new JPanel();
            JTextField topTextField = new JTextField(30);
            JButton topButton = new JButton("确认用户名");
            topPanel.add(topTextField);
            topPanel.add(topButton);
            jFrame.add(topPanel, BorderLayout.NORTH);
            //中部
            JTextArea centerArea = new JTextArea(10,40);
            JScrollPane centerPane = new JScrollPane(centerArea);
            jFrame.add(centerPane);
            //
            JPanel bottomPanel = new JPanel();
            JTextField bottomTextField = new JTextField(35);
            JButton sendButton = new JButton("发送");
            bottomPanel.add(bottomTextField);
            bottomPanel.add(sendButton);
            jFrame.add(bottomPanel, BorderLayout.SOUTH);
    
            jFrame.setLocation(400,300);
            jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            jFrame.pack();
            jFrame.setVisible(true);
            AtomicReference<String> username = new AtomicReference<>("");
            //确认用户名事件监听器
            Action confirmListener = new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent actionEvent) {
                    String topTextContent = topTextField.getText();
                    if (topTextContent != null && ! "".equals(topTextContent)){
                        username.set(topTextContent);
                        System.out.println("用户名设置成功");
                    }
                }
            };
            //绑定事件监听器
            topButton.addActionListener(confirmListener);
            topTextField.getInputMap().put(KeyStroke.getKeyStroke('
    '),"confirm_username");
            topTextField.getActionMap().put("confirm_username",confirmListener);
            /**
             * 发送&接收用socket
             */
            try{
                MulticastSocket mClinetSocket = new MulticastSocket(BROAD_PORT);
                InetAddress multi_addr = InetAddress.getByName(BROAD_IP);
                /**
                 * 接收端
                 */
                new Thread(){
                    @Override
                    public void run() {
                        byte[] inBuff = new byte[4096];
                        /**
                         * 构建接收包
                         */
                        DatagramPacket inPacket = new DatagramPacket(inBuff,0,inBuff.length);
                        while (true){
                            /**
                             * 接收数据放包里,转为字符串打印出来
                             */
                            try {
                                mClinetSocket.receive(inPacket);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            String content = new String(inPacket.getData(),0, inPacket.getLength());
                            System.out.println(content);
                            centerArea.append(content + "
    "); //向文本框加入文本
                        }
                    }
                }.start();
                /**
                 * 套接字加入广播地址
                 */
                mClinetSocket.joinGroup(multi_addr);
    
                /**
                 * 服务端地址构建
                 */
                InetAddress server_addr = InetAddress.getByName(SERVER_IP);
                /**
                 * 构建发出包
                 */
                DatagramPacket outPacket = new DatagramPacket(new byte[0],0,server_addr,SERVER_PORT);
                /**
                 * 发送按钮监听器
                 */
                Action sendListener = new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent actionEvent) {
                        if (username.get().equals("")){
                            System.err.println("请输入用户名");
                        }else {
                            String sendContent = bottomTextField.getText();
                            if (sendContent != null && ! "".equals(sendContent)){
                                sendContent = username + ":" + sendContent;
                                //输入字节存入包,
                                outPacket.setData(sendContent.getBytes());
                                try {
                                    mClinetSocket.send(outPacket);
                                    bottomTextField.setText(null);
                                } catch (IOException ex) {
                                    ex.printStackTrace();
                                }
                            }
                        }
                    }
                };
                /**
                 * 发送按钮绑定监听器
                 */
                sendButton.addActionListener(sendListener);
                //内容框监听键盘
                bottomTextField.getInputMap().put(KeyStroke.getKeyStroke('
    '),"send");
                bottomTextField.getActionMap().put("send",sendListener);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        public static void main(String[] args) {
            new MulticastClientSocket().go();
        }
    }
  • 相关阅读:
    EventDemo——演示事件流
    数组的深复制和浅复制
    Loader类和LoaderInfo类
    几个不同颜色方框——事件流
    自定义事件类的方法——实现接口
    [转帖]ModelSim+Synplify+Quartus的Altera FPGA的仿真与验证
    [转帖]2011年最新企业offer(待遇)比较
    [转帖]引用 利用ModelSim进行的功能仿真,综合后仿真,时序仿真
    [转帖]VHDL中Configuration
    [转帖]ModelSim+Debussy仿真(Verilog)
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/14770483.html
Copyright © 2011-2022 走看看