我制作了一个使用UDP协议的客户端和服务器。我知道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 - 发送地图长度(块数量) 4 - 发送地图名称给我 但是服务器必须响应:4_mapname和1个字节是不够的
答案 0 :(得分:2)
您需要在接收之前重置DatagramPacket的长度。
我并不为此疯狂:
confirmation = new DatagramPacket(buf, buf.length, adress, port);
packet = new DatagramPacket(buf, buf.length, adress, port);
两个DatagramPackets
共享相同的数据缓冲区。您使用它们时需要非常小心。最好只有一个,然后你知道你必须要小心。实际上,在发送任何类型的确认或回复时,最好重新使用包含您回复的请求的数据包。这样,目标地址和端口已经设置好了,您所要做的就是设置数据,偏移量和长度。