[英]Why is my in.ready() taking so long?
I'm creating a multiplayer game, which creates a new thread for each client, and then listens on a socket for strings via input and output streams.我正在创建一个多人游戏,它为每个客户端创建一个新线程,然后通过输入和输出流在套接字上侦听字符串。 On the client side I also have a thread separate from the main game thread, but this one will send the updates to the server 60 times per second with a two letter string as the key for what I want to happen.
在客户端,我也有一个与主游戏线程分开的线程,但是这个线程每秒将更新发送到服务器 60 次,并以两个字母的字符串作为我想要发生的事情的关键。 When I request my "general update" (code RP) on the client side, the server sends the size of the entity array OK, then there seems to be a very long delay for the stream to become ready again.
当我在客户端请求我的“一般更新”(代码 RP)时,服务器发送实体数组的大小 OK,然后流再次准备好似乎有很长的延迟。
I'm relatively sure this is the code of the problem area, after lots of testing to debug.我比较确定这是问题区域的代码,经过大量测试调试。
On the server side:在服务器端:
if(inputLine.equals("RP")){ //this is the main update
timetoupdate = System.currentTimeMillis(); //start timer
ArrayList<Player> currentplayers =world.getPlayers(); //get the list of players
out.println(currentplayers.size()); //send the size
for(int pl = 0; pl<currentplayers.size();pl++){ //loop through
Player player = currentplayers.get(pl); //get the player object
out.println(""+pl);
out.println(player.getUsername());
out.println(player.getType());
out.println(player.getXloc());
out.println(player.getYloc());
out.println(player.getXvel());
out.println(player.getYvel());
out.println(player.getPressing());
out.println(player.getLookingxloc());
out.println(player.getLookingyloc());
out.println(player.getTeam());
out.flush();
/*
id
username
class(type)
xloc
yloc
lxloc
lyloc
*/
// Just gaveout all info on player.getUsername()
}
System.out.println("Time this ("+inputLine+") part takes:"+(System.currentTimeMillis()-timetoupdate)); //stop timer
On the Client Side在客户端
out.println("RP"); //tell the server we are generally updating
String playercountstring = in.readLine(); //get the array size
int playercount = Integer.valueOf(playercountstring); //convert to int
for (int i = 0; i < playercount; i++) {//loop through all players
long timetoupdate = System.currentTimeMillis(); //start timer
while(!in.ready()){}//wait for input to become ready
System.out.println("time this (to ready) part takes:"+(System.currentTimeMillis()-timetoupdate));//stop timer
String toprocess = in.readLine(); //get id of player
... and continues to get all info on this player
As you'll notice I am timing how long the offending areas take to complete: the server takes less than 1 millisecond, yet just that one area of the client takes 200 millisecs, especially weird as the previous line collecting the size of the array takes less than 1 millisecond too.正如你会注意到的,我正在计时完成违规区域需要多长时间:服务器需要不到 1 毫秒,而客户端的一个区域需要 200 毫秒,特别奇怪,因为前一行收集数组的大小需要也小于 1 毫秒。 I'm really at a loss here as to what the issue is, I don't necessarily even need a solution just an explanation would be great.
我真的不知道问题是什么,我什至不需要一个解决方案,只是一个解释会很好。 Thanks!
谢谢!
There are 2 points in a TCP connection that often cause trouble: TCP连接有2点经常出问题:
BufferedOutputStream
BufferedOutputStream
flush()
flush()
TCP_NODELAY
option which disables Nagle's Algorithm that can otherwise delay sending of packets.TCP_NODELAY
选项,该选项禁用Nagle 算法,否则会延迟数据包的发送。 There are other ways as well. Those places exist on both sides of the connection and both sides.这些地方存在于连接的两侧和两侧。
A little example:一个小例子:
class Server {
public void serve(int port) throws IOException {
try (ServerSocket serverSocket = new ServerSocket(port)) {
for(;;) {
Socket clientSocket = serverSocket.accept();
clientSocket.setTcpNoDelay(true);
Thread clientThread = new Thread(() -> handleClient(clientSocket));
clientThread.start();
}
}
}
private void handleClient(Socket clientSocket) {
try (
Socket socket = clientSocket; // tricks try-with-resource into handling the socket
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
) {
while (true) {
String command = reader.readLine();
switch (command) {
case "quit":
Util.send(writer, "ok");
return; // ends this thread.
case "time":
Util.send(writer, String.valueOf(System.currentTimeMillis()));
break;
}
}
} catch (IOException e) {
System.out.println("Client connection closed due to " + e);
// maybe do something
}
}
}
And the client和客户
class Client {
public void connect(String host, int port) throws UnknownHostException, IOException {
try (
Socket socket = new Socket(host, port);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
) {
socket.setTcpNoDelay(true);
Util.send(writer, "time");
String time = reader.readLine();
System.out.println("Server time: " + time);
Util.send(writer, "quit");
System.out.println(reader.readLine());
return;
}
}
}
Note how both sides have called socket.setTcpNoDelay(true)
.请注意双方如何调用
socket.setTcpNoDelay(true)
。 And finally the code to write lines and calls flush()
to ensure data isn't stuck in an application level buffer.最后是编写行并调用
flush()
以确保数据不会卡在应用程序级缓冲区中的代码。
class Util {
public static void send(BufferedWriter writer, String command) throws IOException {
writer.write(command);
writer.newLine();
writer.flush();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.