- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我遇到了一个我自己无法解决的问题。我认为,如果 (1) MSG > BUFFER 和消息速率为 1 消息/秒,那么我的拆分和添加到数组列表并最终重新组装消息片段的方法效果很好。但是当我每秒发送超过 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());
}
}
}
最佳答案
让我们看看当您的费率为 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 个数据报的速率发送(这就是速率
的含义吗?),您不应该创建与部件一样多的计时器。您应该创建一个计时器,为其提供要发送的数据报列表,并将其计划周期设置为 1000L/速率(确保速率不为零!)。计时器应该从列表中弹出下一个数据报并发送它。如果列表中没有留下任何数据报,它应该自行取消。
1000L/rate
计划时间运行。注意两个独立的循环!
关于重新组装数据报
首先,请注意,您从服务器收到的 DatagramPacket
与您发送给服务器的 DatagramPacket
并不相同,即使内容相同!它们是两个不同的对象,并且 Object
中的 equals()
方法不会被重写,这意味着对于 DatagramPacket
类型的任意两个对象 a
和 b
,a.equals(b)
等价于 a == b
。
这意味着您唯一可以比较的是数据报内容,而不是数据报对象。
由于 UDP 不保证数据包将以任何特定顺序发送,因此您必须自己处理这一点。这通常意味着您必须在数据报有效负载中包含更多信息,而不仅仅是字符串内容。一个好的起点是添加一个表示零件编号的字节。
例如,假设您要在包含“ABC”和“DEF”的两个数据包中发送消息“ABCDEF”。您现在正在做的是发送如下内容:
┌──┬──┬──┐│65│66│67│└──┴──┴──┘┌──┬──┬──┐│68│69│70│└──┴──┴──┘
现在你可能会得到它作为
┌──┬──┬──┐│68│69│70│└──┴──┴──┘┌──┬──┬──┐│65│66│67│└──┴──┴──┘
你无法知道这一点,你将重新组装它,它将是 DEFABC
。
但是如果您发送了另一个给出命令的字节:
┌─┬──┬──┬──┐│0│65│66│67│└─┴──┴──┴──┘┌─┬──┬──┬──┐│1│68│69│70│└─┴──┴──┴──┘
您将获得第一个字节,将其转换为整数,并将其余字节转换为字符串。然后,您可以使用索引将其放入列表中,无论您是第一个还是第二个获得 1
数据包,它们都会按正确的顺序出现。
在现实世界中,您还将发送大小(数据包数量)和识别号(这样,如果您收到一些属于刚刚到达的旧通信的恶意数据报,它们就不会混合到您重新组装的有效负载中。
关于java - UDP 发送多个分割字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28498440/
我刚刚了解了 udp 校验和计算。 但我很困惑算法是否检测到所有错误。 最佳答案 当然不是。没有校验和可以检测到所有错误。 关于udp - UDP 校验和是否检测到所有错误?,我们在Stack Ove
下面这个函数有什么问题?? 它应该抛出错误,因为我没有在本地主机上运行 UDP 服务器。 int openUdpSocket(int port) { int sock,sin_size;
我正在尝试修改这两个程序。我想让 udpclient.c 能够接收消息并让 udpserver.c 将消息回显给客户端。我还想在 udpclient 发送消息之前先获取它们的时间标记消息。收到的消息应
我有相当简单的 UDP 服务器写在 c 上。 有时我需要知道在套接字中排队的所有 udp 数据包(字节)的当前长度。 据我了解,getsockopt 没有得到这样的信息。 欢迎使用 Linux 和 F
除了直播音乐/视频外,谁能告诉在哪里使用 UDP 协议(protocol)? UDP 的默认用例是什么? 最佳答案 其他任何您需要性能但如果数据包在途中丢失时可以生存的东西。例如,多人游戏浮现在脑海中
与 TCP 的监视方法相反,UDP 是否会在所有数据包可用时立即发送它们? 谢谢。 最佳答案 TCP 有拥塞控制,UDP 没有,因为它是无连接的。 但是您的问题涉及多个问题:发送消息是否会导致立即发送
我知道 UDP 本质上是不可靠的,但是当连接到 localhost 时,我希望内核以不同的方式处理连接,因为一切都可以在内部处理。那么在这种特殊情况下,UDP 是否被认为是一种可靠的协议(protoc
我正在尝试使用 flash 和 rtmfp 协议(protocol)开发一个实时视频聊天应用程序,但我有疑问rtmfp 如何保证连接对等点,尤其是当对等点位于不同网络时。 最佳答案 RTMFP 依靠中
我发现所有使用 Netty 4.0 的 TCP 服务器实现都使用了 ServerBootstrap 实例。 The biggest and only difference between a serv
对于个人 MMO 游戏项目,我正在 java 中实现一个自制的可靠的基于 UDP 的协议(protocol)。鉴于我当前的设置,我相信窥探者劫持 session 相对简单,因此为了防止这种情况,我借此
我正在尝试手动计算各种 UDP 数据包的校验和,但与 Wireshark 中显示的结果相比,我总是得到错误的结果。下面是我如何做到这一点的示例: Source Address: 192.168.0.1
我正在尝试手动计算各种 UDP 数据包的校验和,但与 Wireshark 中显示的结果相比,我总是得到错误的结果。下面是我如何做到这一点的示例: Source Address: 192.168.0.1
我有一个奇怪的问题。我有一个成功运行的 C++ (boost asio) P2P 应用程序,它可以在大多数 NAT 上运行。问题是,当我将初始启动端口号指定为 1000 时,它会检查 1000 是否空
带有数据源的短 radio 链路,需要通过 IPv6 的 1280 Kbps 吞吐量,使用 UDP 停止和等待协议(protocol),该区域内没有其他客户端或明显的噪声源。我到底如何才能计算出最佳数
似乎可以在没有有效负载的情况下发送 UDP 数据包。 我能想到的唯一不需要有效载荷的就是用于 NAT 打洞。 这还能用来做什么? 这与我之前的问题有关Under Linux, can recv eve
我有一个客户端,我无法更改其代码 - 但我想(重新)使用 编写代码ZeroMQ socket 。 客户端同时使用原始 TCP 和原始 UDP socket 。 我知道我可以使用 ZMQ_ROUTER_
网络 4.0.24 我通过 UDP 传递 XML。收到 UPD 数据包时,数据包的长度始终为 2048,截断消息。尽管如此,我尝试将接收缓冲区大小设置为更大的值(4096、8192、65536),但它
我正在尝试编写一个有关 UDP 连接的简单程序来了解它们。我已经实现了一些基本的事情,但是当我尝试发送并取回我发送的内容时,我遇到了一些问题,例如, 当我这样做时;发送一个字符串 “asd”到服务器我
当我检查时,我在 UDP 客户端每 100 毫秒从服务器发送 UDP 数据包 接收频率不等于 100 毫秒,有时它要少得多,例如 3 毫秒…10 毫秒。 我知道UDP client server是异步
海友我是一个学习winsock2的新手。以下是我的udp服务器和客户端程序。 我这个程序客户端不知道服务器的IP地址,只知道端口。但是服务器会在整个网络中广播一条消息。 当客户端收到消息时,它会回溯服
我是一名优秀的程序员,十分优秀!