【问题标题】:(Small) Java server side application fails to receive DatagramPackets(小)Java服务器端应用接收DatagramPackets失败
【发布时间】:2015-01-13 00:07:03
【问题描述】:

我有一个运行 Java JDK 7“服务器”的 Linux Microsoft Azure VM(使用 SSH 连接)

我的电脑 (Mac OSX) 正在运行 Java JDK 8“服务器”

消息客户端在我的电脑上编译运行,服务器在我的vm上运行编译。我已将端口 xxx2 和 xxx3 配置为 UDP。

服务器代码:

public class server {
    public static void main(String args[]) throws Exception {
        int OutPort = xxx2;
        int InPort = xxx3;
        byte data[] = new byte[2048];
        System.out.println("LOCALHOST:" + InetAddress.getLocalHost());
        InetAddress users[] = new InetAddress[1000];
        DatagramSocket dataIn = new DatagramSocket(OutPort);
        DatagramSocket dataOut = new DatagramSocket(InPort);
        DatagramPacket dataIncoming = new DatagramPacket(data, 2048);
        int userNum = 0;
        while (true) {
            try {
                dataIn.receive(dataIncoming);
            } catch (IOException e) {
                System.out.println(e);
            }
            String message = dataIncoming.getData().toString();
            if (message.startsWith("login")) {
                users[userNum] = dataIncoming.getAddress();
                System.out.println("NEW USER:" + dataIncoming.getAddress().toString() + ", ADDED AS:" + users[userNum]);
                userNum++;
            }
            for (int i = 0; i <= userNum; i++) {
                dataOut.send(new DatagramPacket(message.getBytes(), 2048, users[i], InPort));
            }
        }
    }
}

客户端代码:

public class message {
    public String username;
    public int OutPort = xxx2;
    public int InPort = xxx3;
//    xxx2 out, xxx3 in (default for testing the opposite).
    final InetAddress address;
    message() throws UnknownHostException {
//        Create the variables.
        InetAddress addresses[] = null;
        address = InetAddress.getByName("xxxxx.cloudapp.net");
        addresses = InetAddress.getAllByName("xxxxx.cloudapp.net");
//        Create the colors.
        Color background = new Color(141,234,184);
//        Create the window.
        JFrame window = new JFrame("Java Message");
        window.setSize(600,400);
        window.setLayout(new BorderLayout());
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
//        Create the title.
        JLabel title = new JLabel("Xxxxx's Java Messaging System");
        title.setFont(new Font("Arial", Font.PLAIN, 24));
        title.setOpaque(true);
        title.setBackground(background);
        title.setHorizontalAlignment(SwingConstants.CENTER);
        window.add(title, BorderLayout.NORTH);
//        Create the text output.
        JTextArea content = new JTextArea();
        content.setFont(new Font("Arial", Font.PLAIN, 14));
        content.setEditable(false);
        window.add(content, BorderLayout.CENTER);
        JScrollPane scroll = new JScrollPane(content);
        window.add(scroll, BorderLayout.CENTER);
//        Create the info panel.
        JTextArea info = new JTextArea();
        info.setFont(new Font("Menlo", Font.PLAIN, 14));
        startup(info, address, addresses);
        window.add(info, BorderLayout.EAST);
//        Create username dialog.
        JDialog usernameWindow = new JDialog();
        usernameWindow.setTitle("Username setup");
        usernameWindow.setSize(300,200);
        usernameWindow.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        usernameWindow.setVisible(true);
//        Create username title.
        JLabel loginTitle = new JLabel("Enter a username:");
        loginTitle.setFont(new Font("Arial", Font.PLAIN, 16));
        usernameWindow.add(loginTitle, BorderLayout.CENTER);
//        Create username input.
        JTextField usernameInput = new JTextField();
        usernameInput.setFont(new Font("Arial", Font.PLAIN, 16));
        usernameWindow.add(usernameInput, BorderLayout.SOUTH);
        usernameInput.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (usernameInput.getText().length() >= 8) {
                    errorDialog("Username too long, must be 8 characters or less!");
                } else {
                    username = usernameInput.getText().toString().toUpperCase();
                    content.append(":Logged in as:" + username + "\n");
                    sendMessage("login", username, address);
                    usernameWindow.dispose();
                }
            }
        });
//        Create the text input.
        JTextField messageInput = new JTextField();
        window.add(messageInput, BorderLayout.SOUTH);
        reciveMessages(content);
        messageInput.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                sendMessage(username, messageInput.getText(), address);
                messageInput.setText("");
            }
        });
    }
    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    new message();
                } catch (Exception e) {
                    System.out.println("ERROR:" + e);
                }
            }
        });
    }
    public void startup(JTextArea content, InetAddress ip, InetAddress ips[]) {
        InetAddress local = null;
        try {
            local = InetAddress.getLocalHost();
        } catch(Exception e) {
            System.out.println(e);
        }
        content.append("SERVER IP(s):\n");
        for (int i = 0; i < ips.length; i++) content.append(ips[i].getHostAddress() + "\n");
        content.append("USING:\n" + ip.getHostAddress() + "\n\n");
        content.append("LOCALHOST:\n" + local.getHostAddress() + "\n");
    }
    public void sendMessage(String username, String message, InetAddress address) {
        byte data[] = new byte[2048];
        char usernameChar[] = username.toCharArray();
        char messageChar[] = message.toCharArray();
        for (int i = 0; i < usernameChar.length; i++) data[i] = (byte)usernameChar[i];
        data[usernameChar.length + 1] = (byte)':';
        for (int c = 0; c < messageChar.length; c++) data[usernameChar.length + c + 2] = (byte)messageChar[c];
        try {
            DatagramSocket outSocket = new DatagramSocket(OutPort);
            DatagramPacket dataOut = new DatagramPacket(data, 2048, address, InPort);
            outSocket.send(dataOut);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    public void reciveMessages(JTextArea content) {
        new Thread("PortListener") {
            public void run() {
                try {
                    byte inData[] = new byte[2048];
                    DatagramSocket inSocket = new DatagramSocket(InPort);
                    DatagramPacket dataIn = new DatagramPacket(inData, 2048);
                    while (true) {
                        inSocket.receive(dataIn);
                        content.append(new String(dataIn.getData(), 0, dataIn.getLength()));
                    }
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }.start();
    }
    public void errorDialog(String cause) {

    }
}

问题:我在 VM 上运行服务器代码,控制台从不返回“新用户:”,并且没有任何消息通过。

我对 Java 网络完全陌生,是在完成 Java 指南章节(该书由 Oracle 出版)后完成的,我需要一些有关如何使其工作的指导。

我不知道这是一个简单的错误还是整个想法和理论都是错误的。

我的理论:

  1. 服务器错误地监听数据包。

  2. 客户端和服务器数据[]大小不同。

  3. 服务器的 IP 地址不正确(例如:缺少内部 IP),我需要使用 SocketAddress。

我知道的:

我已经制作了这个程序的一个版本,我在其中编译了它,然后在切换端口的情况下重新编译它(所以传出变成了传入数据)并在我的计算机上运行并且系统运行良好。

【问题讨论】:

  • 我一直在使用 java,因为我还在上高中,还没有在电脑前那么忙。所以请原谅我的愚蠢或简单的错误。
  • 您的服务器检查数据报是否以“登录”开头。你发送的数据报不是以“login”开头的。
  • @immibis 一旦用户创建了他们的用户名,系统就会发送一条以“login”开头的消息(参见 ln 83)

标签: java azure udp port datagram


【解决方案1】:

好的,所以在浏览了您的代码之后,我已经制作了一个工作版本。以下是您需要编辑的内容以及原因(其中一些可能是不必要的,但这就是它对我有用的原因):

当我添加了一些打印和 cmets 来帮助我理解代码时,我可能对行号有点不理解。如果我遗漏了修复/没有清楚地解释某些内容,请发表评论。

服务器客户端:

在第 9 行,您不需要像数据包中指定的那样为出站套接字指定端口。

DatagramSocket dataOut=new DatagramSocket();

在第 18 行,我不确定您希望通过调用数组的 toString() 方法来完成什么,但您应该将字节数组转换回字符串,如下所示:

String message = new String(dataIncoming.getData());

在第 24 行,您将上升到 userNum,但 userNum 是要填充的数组的下一个位置的索引,所以那里什么都没有。 改成小于

for(int i=0;i<userNum;i++)

消息客户端:

第 58 行:toString() 在字符串上是多余的

username=usernameInput.getText().toUpperCase();

第 107 行:就像服务器一样,您不需要声明端口,因为这是在数据包中完成的

DatagramSocket outSocket=new DatagramSocket();

第 108 行:由于您将数据发送到服务器正在侦听的端口(输出端口),因此您应该发送到输出端口,而不是输入端口

DatagramPacket dataOut=new DatagramPacket(data,2048,address,OutPort);

最后,第 123 行:我明白你在做什么,但这仍然会给你一个长度为 2048 的字符串和许多不可读的字符。此外,线路不会终止。使用 trim() 缩减为文本,使用 \n 终止行。

content.append(new String(dataIn.getData()).trim()+"\n");

【讨论】:

  • 谢谢!我现在正在编辑和编译。尽管我对第 24 行编辑感到困惑,因为您的陈述与您的编辑相矛盾。
  • 错字对不起我会改正的
  • 我已经尝试了所有的修复,服务器仍然没有收到数据
  • 我将服务器托管在一台计算机上,并在同一台计算机上运行聊天客户端,然后连接到我自己。你试过这样做吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-27
  • 2018-01-06
  • 2017-12-29
  • 2014-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多