我和另一个小组成员负责创建游戏的多人游戏方面。我们遵循服务器客户端样式以执行此操作。我们能够连接服务器和客户端,并从服务器向客户端发送4条消息。当使用2个客户端时,一个客户端将收到4个字符串,但第二个将接收一个字符串,该字符串是所有4个字符串之间的白色方块的组合,有时会删除部分消息。
两个客户有什么原因可以得到不同的结果,一个接收正确的4个消息,另一个接收一个是4个消息的组合?
MainServer充当游戏的主机,包含服务器套接字和客户端连接。 每个客户端都连接到Server类及其与MainServer对话的服务器
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 && 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 != null&&frmServ.length()>0){
if (frmServ.equals("BEGINGAME")){
//System.out.println("2");
while (!frmServ.equals("ENDLIST")){
frmServ = input.readUTF();
if (!frmServ.equals("BEGINGAME")&&!frmServ.equals("ENDLIST")&&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);
}
}
}
答案 0 :(得分:0)
TCP不维护邮件边界。有时,服务器发送的单个“消息”将由客户端一次一个地接收;有时不。如果多个消息快速连续发送到客户端,则发送系统(我的意思是操作系统而不是服务器程序)将它们捆绑到单个TCP段中,并将它们作为单个单元传送到另一个系统。即使没有发生这种情况,接收系统也可能最终聚合多个收到的消息并通过单个接收呼叫将其发送给客户端。
您必须始终在TCP提供的逻辑流上建立您自己的消息协议边界。这通常意味着(a)在记录之间放置“记录分隔符”(换行符,零字节,无论如何),或者(b)在每个记录的开头添加标题以指示其长度。