[java]基于UDP的Socket通信Demo

  java课编程作业:在老师给的demo的基础上实现客户端发送数据到服务器端,服务器端接受客户端后进行数据广播。

  整体功能类似于聊天室,代码部分不是太难,但是在本机测试的时候出现这样的问题:

    服务端通过将每一个Socket客户端的IP存入Set集合,每次接受到数据后都向当前所有的IP转发。但是本机演示的时候所有开的ChatClient客户端都是同一IP,怎么测试呢?

  解决办法就是本机测试时候服务端向多个不同的端口转发就好了,这样跑起来的客户端是在不同端口上进行监听的(只是为了实现广播,实际应用下还是通过IP来转发)。

 

  客户端代码:

  

import javax.print.attribute.HashPrintServiceAttributeSet;

import javax.swing.*;



import java.awt.BorderLayout;

import java.awt.Dimension;

import java.awt.FlowLayout;

import java.awt.Toolkit;

import java.awt.event.*;

import java.io.*;

import java.net.*;

import java.util.*;



public class ChatClient extends JFrame {



    JTextArea contents = new JTextArea();

    JLabel label1 = new JLabel("服务器地址");

    JTextField address = new JTextField();

    JLabel label2 = new JLabel("用户名");

    JTextField username = new JTextField();

    JButton online = new JButton("上线");

    JButton offline = new JButton("下线");

    JTextField input = new JTextField();

    JButton send = new JButton("发送");



    boolean onlineFlag = false;



    public ChatClient() {

        super("Chat Client");



        contents.setEditable(false);

        getContentPane().add(contents);



        JPanel p1 = new JPanel();

        p1.setLayout(new FlowLayout(FlowLayout.LEADING));



        address.setPreferredSize(new Dimension(100, 28));

        username.setPreferredSize(new Dimension(80, 28));

        input.setPreferredSize(new Dimension(180, 28));



        p1.add(label1);

        p1.add(address);

        p1.add(label2);

        p1.add(username);

        p1.add(online);

        p1.add(offline);

        p1.add(input);

        p1.add(send);



        offline.setEnabled(false);

        send.setEnabled(false);



        getContentPane().add(p1, BorderLayout.SOUTH);



        addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent we) {

                onlineFlag = false;

                Map<String, Object> m1 = new HashMap<String, Object>();

                m1.put("time", new Date()); // 上线时间

                m1.put("username", getUsername());

                m1.put("onlineFlag", onlineFlag);



                send(getServerAddress(), 2222, m1);



                System.exit(0);

            }

        });



        ActionListener al = new ActionListener() {

            public void actionPerformed(ActionEvent ae) {

                String server = getServerAddress();

                if (server == null || server.length() == 0) {

                    JOptionPane.showMessageDialog(ChatClient.this, "请输入服务器地址!");

                    return;

                }



                if (ae.getSource() == online) {

                    // 用户点击了上线按钮

                    if (!onlineFlag) {

                        onlineFlag = true;

                        Map<String, Object> m1 = new HashMap<String, Object>();

                        m1.put("time", new Date()); // 上线时间

                        m1.put("username", getUsername());

                        m1.put("onlineFlag", onlineFlag);

                        online.setEnabled(false);

                        offline.setEnabled(true);

                        send.setEnabled(true);

                        address.setEnabled(false);

                        username.setEnabled(false);

                        send(getServerAddress(), 2222, m1);



                    }

                } else {

                    // 用户点击了下线按钮

                    if (onlineFlag) {

                        onlineFlag = false;

                        Map<String, Object> m1 = new HashMap<String, Object>();

                        m1.put("time", new Date()); // 上线时间

                        m1.put("username", getUsername());

                        m1.put("onlineFlag", onlineFlag);

                        online.setEnabled(true);

                        offline.setEnabled(false);

                        send.setEnabled(false);

                        address.setEnabled(true);

                        username.setEnabled(true);

                        send(getServerAddress(), 2222, m1);

                    }

                }

            }

        };



        ActionListener al2 = new ActionListener() {

            public void actionPerformed(ActionEvent ae) {

                Map<String, Object> m1 = new HashMap<String, Object>();

                m1.put("time", new Date());

                m1.put("username", getUsername());

                m1.put("input", getInput());

                send(getServerAddress(), 2222, m1);

            }

        };



        send.addActionListener(al2);



        online.addActionListener(al);

        offline.addActionListener(al);



        // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setSize(720, 400);

        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();



        setLocation((d.width - 720) / 2, (d.height - 400) / 2);

        setVisible(true);



        new Thread() {

            public void run() {

                try {

                    // 在2221端口接收服务器发送过来的聊天内容,包括上线,下线消息。

                    DatagramSocket rSocket = new DatagramSocket(2220);

                    while (true) {

                        byte[] buffer = new byte[1024 * 16];

                        DatagramPacket recvPacket = new DatagramPacket(buffer, buffer.length);

                        rSocket.receive(recvPacket);

                        byte[] data = recvPacket.getData();

                        byte[] recvData = new byte[recvPacket.getLength()];

                        System.arraycopy(buffer, 0, recvData, 0, recvData.length);

                        //将从服务器接收的数据存入Map并显示

                        Map<String, Object> map = convertByteArrayToMap(recvData);

                        if (map.containsKey("onlineFlag")) { // 上线或者下线

                            boolean b = (boolean) map.get("onlineFlag");

                            if (b) { // 上线

                                map.put("input", "上线");

                            } else { // 下线

                                map.put("input", "下线");

                            }

                        }

                        Date time = (Date) map.get("time");

                        String s = convertDateToFormatString(time);

                        String user = (String) map.get("username");

                        user = "[" + user + "]";

                        contents.append(s + user + ": " + (String) map.get("input") + "\r\n");

                    }

                } catch (Exception e) {

                    e.printStackTrace();

                }



            }

        }.start();



    }



    public String getServerAddress() {

        String s = address.getText();

        //trim删除多余空格

        s = s.trim();

        return s;

    }



    public String getUsername() {

        String s = username.getText();

        s = s.trim();

        if (s == null || s.length() == 0) {

            s = "匿名";

        }

        return s;

    }



    public String getInput() {

        String s = input.getText();

        s = s.trim();

        if (s == null || s.length() == 0) {

            s = "不想说什么";

        }

        return s;

    }



    public static String convertDateToFormatString(Date d) {

        return new java.text.SimpleDateFormat("(yyyy-MM-dd HH:mm:ss)").format(d);

    }



    public static void send(String ip, int port, Map<String, Object> map) {

        try {

            byte[] data = convertMapToByteArray(map);

            DatagramSocket socket = new DatagramSocket();

            DatagramPacket packet = new DatagramPacket(data, data.length);



            packet.setSocketAddress(new InetSocketAddress(ip, port));

            socket.send(packet);



        } catch (Exception e) {

            e.printStackTrace();

        }



    }



    public static byte[] convertMapToByteArray(Map<String, Object> map) {

        try {

            //完成此代码块,要求将map集合中的数据转换成字节数组

            

            ByteArrayOutputStream b = new ByteArrayOutputStream();

            ObjectOutputStream ois = new ObjectOutputStream(b);

            ois.writeObject(map);

            byte[] temp = b.toByteArray();

            return temp;

            

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }



    public static Map<String, Object> convertByteArrayToMap(byte[] data) {

        try {

            ByteArrayInputStream bais = new ByteArrayInputStream(data);

            ObjectInputStream ois = new ObjectInputStream(bais);

            Map<String, Object> result = (Map<String, Object>) ois.readObject();

            return result;

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }



    public static void main(String[] args) {

        new ChatClient();

    }



}

 

    服务端代码:

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetSocketAddress;



import java.util.*;

import java.util.concurrent.LinkedBlockingQueue;



public class ChatServer {



    LinkedBlockingQueue<Map<String, Object>> queue = new LinkedBlockingQueue<Map<String, Object>>();

    Set<String> onlineIPs = new HashSet<String>(); // 当前在线IP。



    public ChatServer() {

        try {



            new Thread() {

                public void run() {

                    while (true) {

                        try {

                            //补齐程序,要求从接收队列中取出数据,遍历在线IP集合,向所有在线IP发送数据



                            if( !queue.isEmpty() ){

                                if( !onlineIPs.isEmpty() ){

                                    for(String ip : onlineIPs){

                                        //下面的端口号可以自定义增加,初始转发至2220端口   多增加的端口可以实现本机内的广播

                                        ChatClient.send(ip, 2221, queue.peek() );

                                        ChatClient.send(ip, 2220, queue.remove() );

                                    }    

                                }

                            }

                            

                            //end

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                    }

                }

            }.start();

            //接受端口2222

            DatagramSocket serverSocket = new DatagramSocket(2222);

            System.out.println("Chat Server started.");

            while (true) {

                byte[] buffer = new byte[1024 * 16];

                DatagramPacket recvPacket = new DatagramPacket(buffer, buffer.length);



                serverSocket.receive(recvPacket);



                InetSocketAddress remoteAddress = new InetSocketAddress(recvPacket.getAddress(),

                        recvPacket.getPort());

                System.out.println("接收到 " + remoteAddress.getHostString() + " 发送过来的数据包");



                byte[] data = recvPacket.getData();

                byte[] recvData = new byte[recvPacket.getLength()];

                System.arraycopy(buffer, 0, recvData, 0, recvData.length);

                System.out.println(recvData.length);

                Map<String, Object> map = ChatClient.convertByteArrayToMap(recvData);

                System.out.print("map长度"+map.size());

                if (map.containsKey("onlineFlag")) { // 上线或者下线

                    boolean b = (boolean) map.get("onlineFlag");

                    if (b) { // 上线

                        onlineIPs.add(remoteAddress.getHostString());

                    } else { // 下线

                        onlineIPs.remove(remoteAddress.getHostString());

                    }

                }



                queue.add(map);



            }



        } catch (Exception e) {

            e.printStackTrace();

        }

    }



    public static void main(String[] args) {

        new ChatServer();



    }



}

 

你可能感兴趣的:(socket通信)