我做了一个使用UDP协议(protocol)的客户端和服务器。我知道 UDP 不是很可靠,数据可能会丢失,但我在本地主机上运行所有内容,并且我发送的数据大小只有大约 10 个字节。 问题是,当服务器发送 4 个字节时,客户端仅收到第一个字节,但是当服务器发送 50 或 1000 字节客户端接收...只有第一个字节的数据?!是的,正好 1 个字节(有时 2 或 3 个字节,但不多)!我不知道发生了什么事。我的代码是否有错误或者这是 UDP 的错误?
这是客户端代码
public void connect(String ip, int port) {
try {
adress = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
error("UnknownHostException");
e.printStackTrace();
}
try {
noErrors = true;
socket = new DatagramSocket();
socket.setSoTimeout(5000);
socket.connect(adress, port);
confirmation = new DatagramPacket(buf, buf.length, adress, port);
packet = new DatagramPacket(buf, buf.length, adress, port);
preapreConfirmation();
logIn();
} catch (SocketException e) {
error("Cannot connect");
e.printStackTrace();
}
}
private void logIn(){
String s;
while (noErrors) {// Sending request for connecting
sendRequest("2");
s = new String(packet.getData());
if (s.contains("2")) { // Connection was accepted
break;
} else if (s.contains("1")) {// Connection was refused
disconnect();
error("Connection refused");
break;
}
}
while(noErrors){ //loding map data: name
sendRequest("4"); // ask about world name
s = new String(packet.getData());
try {
System.out.println(s+" BYTES:"+s.getBytes().length+" "+socket.getReceiveBufferSize());
} catch (SocketException e) {
e.printStackTrace();
}
if(s.startsWith("4")){//world name was given
if( s.split("_").length>1){
mapname = s.split("_")[1];
break;
}
}
}
while (noErrors) { // loding map data: hash
sendRequest("6"); // ask about world hash
s = new String(packet.getData());
if (s.startsWith("6")) {
if (s.contains("h")) { // world hash was given
maphash = parse(s, 1);
break;
}
}
}
if(!noErrors)return;
System.out.println(maphash+" ==> "+ Screen.game.getHash(mapname)+" ("+mapname+")");
if (Screen.game.checkIfWorldExists(maphash, mapname)) { //validating world
Screen.game.loadMap(mapname);
Screen.setState(GameStates.GAME);
} else {
sendCommand("0");
}
isLogged = true;
}
public void sendRequest(){
try {
socket.send(packet);//Sending data
try{
socket.receive(packet);//receiving answer
} catch(PortUnreachableException ee){
error("Cannot connect");
} catch(SocketTimeoutException e){
error("End of stream");
}
socket.send(confirmation);//Sending confirmation of receiving answer
} catch (IOException e) {
error("IOException");
e.printStackTrace();
}
}
private void error(String message){
noErrors = false;
Screen.setErrorState(message);
}
public void sendCommand(){
try {
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
这是服务器的代码:
public void run() {
System.out.println("Server is waiting for data from socket");
while (isRunning) {
try {
buf = new byte[256];
// receives request
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
System.out.println("packet received");
// creating response
setCommand(new String(packet.getData(), "UTF-8"));
String d = getNextQuote(getCommand());
// sends the response to the client. "address" and "port" are
// already saved in last received packet
InetAddress address = packet.getAddress();
int port = packet.getPort();
System.out.println(">"+getCommand()+"\n<"+d);
if(d.equals("7")){
for(String g:packages){
buf = g.getBytes();
packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
}
} else {
buf = d.getBytes();
packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
}
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
}
}
System.err.println("Server stopped");
socket.close();
}
在我的代码中,我使用命令来缩小发送数据的大小,以便客户端和服务器可以仅使用一个字节进行通信,例如客户端发送: 1 - 断开我的连接 2 - 连接我 3 - 发送 map 长度( block 数量) 4 - 将 map 名称发送给我 但服务器必须响应:4_mapname 和 1 个字节不够
最佳答案
接收前需要重置DatagramPacket的长度。
我对此并不疯狂:
confirmation = new DatagramPacket(buf, buf.length, adress, port);
packet = new DatagramPacket(buf, buf.length, adress, port);
两个DatagramPackets
共享相同的数据缓冲区。您需要非常小心地使用它们。最好只有一个,然后您知道必须小心。事实上,在发送任何类型的确认或回复时,最好重复使用包含您要回复的请求的数据包。这样目标地址和端口就已经设置好了,你所要做的就是设置数据、偏移量和长度。
关于java - UDP 客户端仅获取数据的开头 (Java),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25086222/