UDP发送多个拆分字符串

时间:2015-02-13 11:19:41

标签: java udp stringbuilder datagram

我有一个问题,我无法自己解决。我认为我的方法是拆分并添加到数组列表并最终重新组装消息片,如果(1)MSG> BUFFER&消息速率为1msg /秒。但是当我发送超过1条消息/秒并且我必须分割大/小消息时出现问题。是的,从长远来看,这种方法可能效率低下,但这是一项任务,所以我只想让它按照我想要的方式运作,并且我很好。

我很确定问题是它当然会发送每个消息的速率。输出在我的控制台中是这样的:

--------------------------------
| UDP Echo Client
| Configuration: 
| server name: localhost
| port: 4950
| buffer: 8
| rate: 5
| message size: 15
--------------------------------
Original: [HelloHe, lloHell, o]
Received: [HelloHe]
MESSAGE IS NOT EQUAL!
Received: [HelloHe, HelloHe]
MESSAGE IS NOT EQUAL!
Received: [HelloHe, HelloHe, HelloHe]
MESSAGE IS NOT EQUAL!

有人可以试着帮助我吗?解决这个问题的最佳方法是什么?

UDP客户端:

import java.io.IOException;
import java.net.*;
import java.util.*;

/*
UDP Echo client. Sends a echo message of a size to the server and gets it back.
It checks so that the message wasn't lost or anything has happened to it.
by jv222dp

Rate works perfectly when MSG.length <= MY_BUFFER.
When the BUFFER is smaller then the MSG it works great if rate is 1
 */
public class UDPEchoClient {

    private static final String MSG = "HelloHelloHello";

    private static int MY_PORT;
    private static int RATE;
    private static int MY_BUFFER;
    private static String HOST_NAME;
    private static byte[] buf;
    private static int packages;
    private static int chars;
    private static List<String> originalMsg;
    private static List<String> receivedString = new ArrayList<>(packages);
    private static DatagramPacket sendPacket;

    public static void main(String[] args) {

        if (!isCorrect(args)) {
            System.exit(1);
        } else {

            try {

            /* Configuration printout */
                System.out.println("--------------------------------" +
                        "\n| UDP Echo Client" +
                        "\n| Configuration: " +
                        "\n| server name: " + HOST_NAME +
                        "\n| port: " + MY_PORT +
                        "\n| buffer: " + MY_BUFFER +
                        "\n| rate: " + RATE +
                        "\n| message size: "+MSG.length()+
                        "\n--------------------------------");
                /* Sets the buffer */
                buf = new byte[MY_BUFFER];

                /* Create socket */
                DatagramSocket socket = new DatagramSocket(null);

                /* Create local endpoint using bind() */
                SocketAddress localBindPoint = new InetSocketAddress(0);
                socket.bind(localBindPoint);

                socket.setSoTimeout(2000);

                /* Create remote endpoint */
                SocketAddress remoteBindPoint = new InetSocketAddress(HOST_NAME,
                        (MY_PORT));



                /* Sends and reads the echo message */
                sendEchoPackets(socket, remoteBindPoint);


            } catch (SocketException se) {
                System.err.println("Host unreachable!" +
                        "Wrong port or host offline");
            }
        }
    }

    public static void sendEchoPackets(DatagramSocket socket, SocketAddress remoteBindPoint) {

        System.out.println("Original: "+originalMsg.toString());

        /* For each string in the List of message parts */
        for (String message : originalMsg) {

        /* Create datagram packet for sending message */
            sendPacket = new DatagramPacket(
                    message.getBytes(),
                    message.length(),
                    remoteBindPoint);

            Timer timer = new Timer();
            TimerTask rate = new TimerTask() {

                @Override
                public void run() {
                    try {

                        if (RATE == 0 || RATE == 1) {
                            for (int i = 0; i < RATE; i++) {
                                socket.send(sendPacket);
                                timer.cancel();
                            }
                        } else {
                            for (int i = 0; i < RATE; i++) {
                                socket.send(sendPacket);
                                timer.cancel();
                            }

                        }
                    } catch (IOException e) {
                        System.out.println(e.getMessage());
                    }
                }
            };

            timer.scheduleAtFixedRate(rate, 0, 1000);
            readEchoPacket(socket);
        }

    }

    public static void readEchoPacket(DatagramSocket socket){

        try {

            /* Create datagram packet for receiving echoed message */
            DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);

            socket.receive(receivePacket);

            String receivedEcho = new String(
                    receivePacket.getData(),
                    receivePacket.getOffset(),
                    receivePacket.getLength());

            receivedString.add(receivedEcho);

            /* Compares if the message is the same as the one that was sent */
            compareEchoMessage(receivedString);
        }
        catch (IOException e) {
            System.out.println(e.getMessage());
        }


    }

    public static void compareEchoMessage(List<String> receivedMsg){
        StringBuilder sb = new StringBuilder();

        for (String str : receivedMsg) {
            sb.append(str);
        }
        System.out.println("Received: "+receivedMsg.toString());
        if (sb.toString().compareTo(MSG) == 0){
            System.out.printf("%s bytes sent and received!",sb.length());
        }
        else{
            System.out.println("MESSAGE IS NOT EQUAL!");
        }
    }

    /* Splits the message equally */
    private static ArrayList<String> splitMessage(String message, int chunks)    {
        /* */
        ArrayList<String> packages = new ArrayList<>(
                (message.length() + chunks) - 1 / chunks);

        for (int i = 0; i < message.length(); i += chunks){
            packages.add(message.substring(i, Math.min(message.length(),
                    i + chunks)));
        }
        return packages;
    }

    public static boolean isCorrect(String[] args) {

        /* Make sure all arguments are present */
        if (args.length != 4 && args.length == 0) {
            printUsage();
            return false;
        }
        else
            try {

                HOST_NAME = args[0];
                MY_PORT = Integer.parseInt(args[1]);
                MY_BUFFER = Integer.parseInt(args[2]);
                RATE = Integer.parseInt(args[3]);

            /* Ensures RATE is not too high with a tested limit of 3000 */
                if (RATE > 3000) {
                    System.err.println("Rate value is too large!");
                    return false;
                }

            /* Make sure the host is valid */
                if (!isValidHost(HOST_NAME)) {
                    System.err.println("Host address is not valid!" +
                            "\nRequires a valid IP address or just localhost");
                    return false;
                }

             /* Make sure the port number is in the valid range */
                if (MY_PORT <= 0 || MY_PORT >= 65536) {
                    System.err.println("Port value must be in (0 -> 65535)!");
                    return false;
                }

            /* Make sure the buffer is at least 2, not lower */
                if (MY_BUFFER < 2){
                    System.err.println("Buffer must be higher or equal to 2!");
                    return false;
                }

            /* Split the message if bigger than buffer to appropriate packages */
                if (MSG.length() > MY_BUFFER) {
                    packages = (int) Math.ceil((double) MSG.length() / MY_BUFFER);
                    chars = (MSG.length() / packages);
                    originalMsg = splitMessage(MSG, chars);
                }

            /* Else adds whole message to array list */
                else {

                    packages = (int) Math.ceil( (double)MSG.length() / MY_BUFFER);
                    chars = (MSG.length() / packages);
                    originalMsg = splitMessage(MSG, chars);
                }
            }
            catch (IndexOutOfBoundsException e) {
                printUsage();
                System.exit(1);
            }
            catch (NumberFormatException n) {
                System.err.println("Invalid arguments!");
                printUsage();
                System.exit(1);
            }

        /* Everything is valid */
        return true;
    }

    private static boolean isValidHost(String host) {

        /* Check if the string is valid */
        if (host == null || host.length() < 7 || host.length() > 15){
            return false;
        }
        else

        /* Host is valid "localhost" */
            if (host.equals("localhost")){
                return true;
            }

        /* Check the host string, should be in x.x.x.x format */
        StringTokenizer token = new StringTokenizer(host,".");
        if (token.countTokens() != 4)
            return false;

        while (token.hasMoreTokens()) {

            /* Get current token and convert to an integer value */
            String ip = token.nextToken();
            try {

                int ipVal = Integer.valueOf(ip).intValue();
                if ( ipVal < 0 || ipVal > 255)
                    return false;
            }
            catch (NumberFormatException ex) {
                return false;
            }
        }

        /* IP Address looks valid */
        return true;
    }

    private static void printUsage() {
        System.err.println("Input arguments did not match expected arguments!" +
                "\nUsage: \"<host_name> <port> <message_buffer> <message_rate>\"");
    }
}

UDP服务器:

/*
  UDPEchoServer.java
  A simple echo server with no error handling
*/
import java.io.IOException;
import java.net.*;

public class UDPEchoServer {
    public static final int BUFSIZE = 1024;
    public static final int MYPORT = 4950;
    public static boolean running = true;

    public static void main(String[] args) {
        byte[] buf = new byte[BUFSIZE];

        try{

            /* Create socket */
            DatagramSocket socket = new DatagramSocket(null);

            /* Create local bind point */
            SocketAddress localBindPoint = new InetSocketAddress(MYPORT);
            socket.bind(localBindPoint);

            System.out.println("---------------------------------"+
                    "\n| UDP Echo Server"+
                    "\n| Configuration: "+
                    "\n| port: "+MYPORT+
                    "\n---------------------------------");

            while (running) {

                /* Create datagram packet for receiving message */
                DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);

                /* Receiving message */
                socket.receive(receivePacket);

                /* Create datagram packet for sending message */
                DatagramPacket sendPacket =
                        new DatagramPacket(receivePacket.getData(),
                                receivePacket.getLength(),
                                receivePacket.getAddress(),
                                receivePacket.getPort());

                String echo = new String(receivePacket.getData(),
                        receivePacket.getOffset(), receivePacket.getLength());

                System.out.printf("UDP echo request from %s", receivePacket.getAddress().getHostAddress());
                System.out.printf(" using port %d\n", receivePacket.getPort());
                System.out.println("Received: "+echo);

                 /* Send message*/
                socket.send(sendPacket);
            }
        }
        catch (SocketException s){
            System.err.println(s.getMessage());
        }
        catch (IOException e){
            System.err.println(e.getMessage());
        }
    }
}

1 个答案:

答案 0 :(得分:1)

让我们看看当你的费率为5时会发生什么:

这是计时器正文:

                    if (RATE == 0 || RATE == 1) {
                        for (int i = 0; i < RATE; i++) {
                            socket.send(sendPacket);
                            timer.cancel();
                        }
                    } else {
                        for (int i = 0; i < RATE; i++) {
                            socket.send(sendPacket);
                            timer.cancel();
                        }

                    }

因此,if条件为false,因为费率既不是0也不是1.我们转到else

                        for (int i = 0; i < RATE; i++) {
                            socket.send(sendPacket);
                            timer.cancel();
                        }

对于RATE = 5,这就像写作:

                            socket.send(sendPacket);
                            timer.cancel();
                            socket.send(sendPacket);
                            timer.cancel();
                            socket.send(sendPacket);
                            timer.cancel();
                            socket.send(sendPacket);
                            timer.cancel();
                            socket.send(sendPacket);
                            timer.cancel();

当然,取消计时器五次并没有任何效果,但它 一个接一个地发送相同的数据包5次。然后它会发送下一个部分5次,第三部分发送5次,因为你要为部件创​​建三个独立的计时器。

我认为如果你想以每秒5个数据报的速率发送(这是rate的意思吗?),你不应该创建与部分一样多的计时器。您应该创建一个计时器,为其提供要发送的数据报列表,并将其计划周期设置为1000L / rate(确保速率不为零!)。计时器应弹出列表中的下一个数据报并发送它。如果列表中没有剩余数据报,则应自行取消。

  • 使用datagrams填充列表的一个循环
  • 将列表分配给最终变量,该变量可以从匿名类或字段中使用。
  • 创建计时器并使用1000L / rate计划时间运行它。
  • 运行第二个循环以读取和比较收到的回波数据报。

注意两个独立的循环!

关于重新组装数据报

首先,请注意,您从服务器收到的DatagramPacket与您发送给它的DatagramPacket不同,即使内容相同!它们是两个不同的对象,equals()中的Object方法未被覆盖,这意味着对于a类型的任何两个对象bDatagramPacket,{ {1}}相当于a.equals(b)

这意味着您唯一可以比较的是数据报内容,而不是数据报对象

由于UDP不保证数据包将以任何特定顺序发送,因此您必须自己处理。这通常意味着您必须在数据报有效负载中包含更多信息,而不仅仅是字符串内容。一个好的起点是添加一个代表零件编号的字节。

例如,假设您要发送消息&#34; ABCDEF&#34;两个包含&#34; ABC&#34;和&#34; DEF&#34;。你现在正在做的是发送类似的东西:

┌──┬──┬──┐
│65│66│67│
└──┴──┴──┘
┌──┬──┬──┐
│68│69│70│
└──┴──┴──┘

现在你可以回复

┌──┬──┬──┐
│68│69│70│
└──┴──┴──┘
┌──┬──┬──┐
│65│66│67│
└──┴──┴──┘

你无法知道这一点,并且你将重新组装它,它将是a == b

但是如果您发送了另一个给出订单的字节:

┌─┬──┬──┬──┐
│0│65│66│67│
└─┴──┴──┴──┘
┌─┬──┬──┬──┐
│1│68│69│70│
└─┴──┴──┴──┘

您获取第一个字节,将其转换为整数,并将其余字节转换为字符串。然后你可以使用索引将它放在列表中,无论你是第一个还是第二个DEFABC数据包,它们都会以正确的顺序出现。

在现实世界中,您还会发送大小(数据包数量)和一个识别号码(这样,如果您获得一些属于刚刚到达的旧通信的流氓数据报,他们就会赢得&# 39;混合到你重新组装的有效载荷中。