#java #sockets #jakarta-ee #networking
#java #сокеты #джакарта-ee #сеть
Вопрос:
Я и еще один член группы отвечаем за создание многопользовательского аспекта игры. Для этого мы следуем стилю клиента сервера. Мы можем подключить сервер и клиентов, и мы отправляем клиенту 4 сообщения с сервера. При использовании 2 клиентов один клиент получит 4 строки, а второй получит одну строку, представляющую собой комбинацию всех 4 с белыми квадратами между ними, иногда с отрезанными частями сообщения.
В чем может быть причина того, что два клиента имеют разные результаты: один получает правильное сообщение 4, а другой получает сообщение, представляющее собой комбинацию всех 4?
Главный сервер действует как хост игры, содержит серверный сокет и клиентские соединения. Каждый клиент подключен к классу сервера, и это сервер, который взаимодействует с основным сервером
public class MainServer {
public GameManager game;
public Server[] connections; //Array of connected players if server is running.
public int playerID = 1001;
public ArrayList<Integer> idList = new ArrayList<Integer>();
int maxPlayers;
public MainServer(GameManager game, int maxPlayers){
this.game = game;
this.maxPlayers = maxPlayers;
}
public synchronized void runServer(int port){ //As it stands, having the game in server mode will dedicate it to server mode totally.
try {
int nclients = 0;
connections = new Server[maxPlayers];
//Await connections.
ServerSocket ss = new ServerSocket(port);
System.out.println("GAME NOW IN SERVER MODE" " Port: " port " URL: " ss.getInetAddress());
while (idList.size() != maxPlayers) { //WHile there are still open players slots
//Wait for a socket
//System.out.println("MainServer, before ss.accept()");
Socket s = ss.accept();
System.out.println("ACCEPTED CONNECTION FROM: " s.getInetAddress());
connections[nclients] = new Server(s, playerID);
idList.add(playerID);
playerID ;
connections[nclients].start();
nclients ;
}
for (Server s : connections){
System.out.println(s.playerID);
if(s.dout==null){System.out.println("dout is null for server " s.playerID);}
s.dout.writeUTF("BEGINGAME");
for (int i : idList){
s.dout.writeUTF(Integer.toString(i));
}
s.dout.writeUTF("ENDLIST");
}
} catch(IOException e) {
System.err.println("I/O error: " e.getMessage());
}
}
public class Server extends Thread {
public final Socket socket;
public DataInputStream din;
public DataOutputStream dout;
public int playerID;
public Server(Socket sock, int ID) {
this.socket = sock;
playerID = ID;
}
public void run() {
try {
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
dout.writeInt(playerID);
dout.flush();
String frmClient = "", toClient = "";
while (!frmClient.equals("stop")) {
frmClient = din.readUTF();
//System.out.println("client says: " frmClient);
//toClient = frmClient " :Reply From Server";
toClient = frmClient;
sendToAll(toClient);
dout.flush();
}
din.close();
socket.close();
} catch (IOException e) {
System.err.println("Server I/O Error: " e.getMessage());
e.printStackTrace(System.err);
}
}
public void sendToAll(String msg) throws IOException {
for (Server s : GameManager.server.connections) {
if (s != null amp;amp; s.dout != null) {
s.dout.writeUTF(msg);
}
}
}
}
public class Client extends Thread {
public DataOutputStream output;
public DataInputStream input;
private GameManager game;
private String address;
private int port;
public int playerID;
public ArrayList<String> allIds = new ArrayList<String>();
private Socket s;
//
String l="";
//
public ArrayList<String> outBuff = new ArrayList<String>();
public ArrayList<String> inBuff = new ArrayList<String>();
public Client(String add, int por, GameManager game) {
address = add;
port = por;
this.game = game;
}
public void run() {
System.out.println("CLIENT");
try {
s = new Socket(address,port);
DataInputStream input = new DataInputStream(s.getInputStream());
DataOutputStream output = new DataOutputStream(s.getOutputStream());
String toServ = "";
String frmServ = "";
playerID = input.readInt();
while (!toServ.equals("stop")) {
toServ = "";
if(outBuff.size()>0){
toServ = outBuff.remove(0);}
if (toServ != null){
output.writeUTF(toServ);
output.flush();
}
frmServ = input.readUTF();
if(frmServ.length()>0){
System.out.println(frmServ " :test");}
if (frmServ != nullamp;amp;frmServ.length()>0){
if (frmServ.equals("BEGINGAME")){
//System.out.println("2");
while (!frmServ.equals("ENDLIST")){
frmServ = input.readUTF();
if (!frmServ.equals("BEGINGAME")amp;amp;!frmServ.equals("ENDLIST")amp;amp;frmServ.length()>0){
System.out.println(frmServ " :Adding to allIds");
allIds.add(frmServ);
}
}
game.beginGame(allIds);
}
if(!frmServ.equals("BEGINGAME")||!frmServ.equals("ENDLIST")){
inBuff.add(frmServ);
}
}
for (int i = 0; i < inBuff.size() - 1; i ){
game.applyUpdateFromServer(inBuff.remove(i)); //Possible temporary solution, may cause lag because this thread is going into main game and performing tasks
}
}
output.close();
s.close();
} catch (IOException e) {
System.err.println("Client I/O Error: " e.getMessage());
e.printStackTrace(System.err);
}
}
}
Комментарии:
1. Не могли бы вы правильно отформатировать этот беспорядок.
2. И задайте актуальный вопрос. Вы не задали вопрос и не указали, что не работает.
Ответ №1:
TCP не поддерживает границы сообщений. Иногда отдельные «сообщения», отправленные вашим сервером, будут приниматься клиентом по одному; иногда нет. Если несколько сообщений отправляются клиенту в быстрой последовательности, система отправки (я имею в виду здесь операционную систему, а не вашу серверную программу) объединит их в один TCP-сегмент и доставит их в другую систему как единое целое. Даже если этого не произойдет, принимающая система может в конечном итоге объединить несколько полученных сообщений и доставить их клиенту с помощью одного вызова receive.
Вы всегда должны накладывать свои собственные границы протокола сообщений поверх логического потока, предоставляемого TCP. Обычно это означает либо (а) установку «разделителя записей» (новая строка, нулевой байт, что угодно) между записями, либо (б) размещение заголовка в начале каждой записи с указанием ее длины.