我目前正在攻读编程考试,在早期的考试集中,一个问题有以下代码。
public class Question18 {
public static class Question18Server implements Runnable {
DatagramSocket serverSocket;
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
public Question18Server(int port) throws SocketException{
serverSocket = new DatagramSocket(port);
}
public void run() {
while (true) {
DatagramPacket receivePacket = new
DatagramPacket(receiveData,
receiveData.length);
try {
serverSocket.receive(receivePacket);
String sentence = new String(receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
} catch (IOException e) {
}
}
}
}
public static class Question18Client implements Runnable {
int port;
DatagramSocket clientSocket;
InetAddress IPAddress;
public Question18Client(int port) throws SocketException,
UnknownHostException {
this.port = port;
clientSocket = new DatagramSocket();
IPAddress = InetAddress.getByName("localhost");
}
public void run() {
for (int i = 0; i < 4; i++) {
byte[] sendData = new byte[1024];
String sentence = "Hello " + i * 2;
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, IPAddress, port);
try {
clientSocket.send(sendPacket);
} catch (IOException e) {
}
}
}
}
public static void main(String[] args) {
try {
Thread server = new Thread(new Question18Server(9000));
Thread client = new Thread(new Question18Client(9000));
server.start();
client.start();
} catch (Exception e) {
}
}
}
我遇到麻烦的问题是:
如果server.start()和client.start()被反转,输出会是什么?
我对UDP没有太多经验,我可能误解了一些东西,但我最初的想法是服务器可能会收到客户端发送的一些datagramPackets。
但令我惊讶的是它收到了所有数据发送。
我尝试将代码更改为以下内容,以便在两个线程的开头之间创建一个小暂停,但它仍在工作。
client.start();
long waittime = System.currentTimeMillis() + 5000;
while(System.currentTimeMillis() < waittime)
{}
server.start();
我真的希望有人可以解释为什么这有效,我目前的理论是
a)由于我使用“localhost”
,因此数据存储在我的计算机上b)DatagramPackets在一段时间内搜索正确的IP和端口。
答案 0 :(得分:1)
由于UDP中不需要连接设置,因此发布者和订户的启动顺序不如TCP中那么重要。在UDP中,后期用户不一定会看到所有数据包,即使用户没有迟到也无法保证。
在您的代码中,Question18Client
是发布商,Question18Server
是订阅者。尝试以下实验:
例如:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public class SoQuestion {
private static class Publisher {
private DatagramSocket socket;
private InetAddress address;
private int port;
private int count = 1;
public Publisher(int port, String host)
throws SocketException, UnknownHostException {
this.port = port;
address = InetAddress.getByName(host);
socket = new DatagramSocket();
}
public void publish(int packets) {
System.out.println(
"Publishing " + packets +
" packets via UDP to port " + this.port
);
for (int i = 1; i <= packets; i++,count++) {
String data = "" + count;
byte[] dataBytes = data.getBytes();
DatagramPacket packet = new DatagramPacket(
dataBytes,
dataBytes.length,
address,
port
);
try {
socket.send(packet);
System.out.println(data + " sent");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static class Subscriber extends Thread {
private int port;
private String host;
private InetAddress address;
private DatagramSocket socket;
private byte[] buffer = new byte[1024*1024];
private volatile boolean finished;
public Subscriber(int port, String host) throws SocketException{
this.port = port;
this.host = host;
}
@Override
public void run() {
try {
address = InetAddress.getByName(host);
socket = new DatagramSocket(port, address);
socket.setSoTimeout(5000);
System.out.println("Subscribed via UDP to port " + port);
while (!finished) {
DatagramPacket packet = new DatagramPacket(
buffer,
buffer.length
);
socket.receive(packet);
System.out.println(
new String(
packet.getData(),
0,
packet.getLength()
) + " received"
);
}
System.out.println("Subscription finished");
} catch (SocketTimeoutException x ) {
System.out.println("Subscription timed-out.");
} catch (Exception e) {
e.printStackTrace();
}
}
public void finish() {
this.finished = true;
}
}
public static void main(String[] args) {
try {
int packets = 1024;
Publisher publisher = new Publisher(9000, "localhost");
publisher.publish(packets);
Subscriber subscriber = new Subscriber(9000, "localhost");
subscriber.start();
Thread.sleep(2000);
publisher.publish(packets);
//subscriber.finish();
} catch (Exception e) {
e.printStackTrace();
}
}
}
当我运行时:
javac SoQuestion.java
java SoQuestion|sort -k 1,1n -k 2,2r
我看到前1024个数据包没有收到,并且x64 Linux 3.16.7-29
上的下一个1024匹配接收:
1 sent
...
1024 sent
1025 sent
1025 received
...
2048 sent
2048 received
答案 1 :(得分:0)
使用DatagramSocket发送数据不需要另一侧的监听器。数据不会随处可见。它也不存储在等待侦听器套接字打开的任何地方。您看到的行为很可能是由您的代码引起的。
你应该对你正在捕捉的异常做一些事情而不是忽略它们。
您还应该确保停止Question18Server。 ServerSocket位于receive()中而未关闭。
您真的需要为客户端使用线程吗?你不能在没有启动线程的情况下将它作为主类的一部分运行。
我认为如果你解决这些问题,你就会开始看到真正发生的事情。