我有一个问题,我无法自己解决。我认为我的方法是拆分并添加到数组列表并最终重新组装消息片,如果(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());
}
}
}
答案 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
(确保速率不为零!)。计时器应弹出列表中的下一个数据报并发送它。如果列表中没有剩余数据报,则应自行取消。
1000L / rate
计划时间运行它。注意两个独立的循环!
关于重新组装数据报
首先,请注意,您从服务器收到的DatagramPacket
与您发送给它的的DatagramPacket
不同,即使内容相同!它们是两个不同的对象,equals()
中的Object
方法未被覆盖,这意味着对于a
类型的任何两个对象b
和DatagramPacket
,{ {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;混合到你重新组装的有效载荷中。