播放器无法连接到 Java 中的服务器



我目前正在编程一款在线国际象棋游戏,希望在一台电脑上托管多台服务器。当我与两名玩家一起玩时,它也可以工作,但如果我启动第三名玩家,它就无法连接到服务器。

玩家的代码:

public Socket socket;
public int PlayerID;
public ReadFromServer rfs;
public WriteToServer wts;

public void connectToServer(){
for (int i = 1;i <=3 ;i++ ) {
try {              
socket = new Socket("localhost",(1000+i));
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
PlayerID = in.readInt();
System.out.println("You are Player Number:"+PlayerID);
if(PlayerID == 1){
System.out.println("Waiting for Oponent...");
}  
rfs = new ReadFromServer(in);
wts = new WriteToServer(out);
Thread rT = new Thread(rfs);
Thread wT = new Thread(wts);
rT.start();
wT.start();    
i = 4;   
} catch(IOException e) {
System.out.println("ERROR at: connect to Server");
}
}
}

public static void main(String[] args) {
PlayerFrame pf = new PlayerFrame();
pf.connectToServer();
pf.GUI();
}

服务器代码:

import java.io.*;
import java.net.*;
import java.net.InetAddress;
public class GameServer {
public int GameNumber = 3;
public ServerSocket ss;
public int numPlayers;
public int maxPlayers;

public Socket socket1;
public Socket socket2;
public ReadFromClient p1read;
public ReadFromClient p2read;
public WriteToClient p1write;
public WriteToClient p2write; 

public GameServer[] gs;

public int p1x1,p1x2,p1y1,p1y2,p2x1,p2x2,p2y1,p2y2;
public GameServer(){
gs = new GameServer[GameNumber];
Thread[] server = new Thread[GameNumber];
ServerThread[] thread = new ServerThread[GameNumber];
for (int i = 0;i < gs.length ;i++ ) {
gs[i] = new GameServer((1000+i+1));
thread[i] = new ServerThread(i);   
server[i] = new Thread(thread[i]);
server[i].start();
} // end of for 
}

public GameServer(int i){
System.out.println("=====Game Server=====");
numPlayers = 0;
maxPlayers = 2;

try {
ss = new ServerSocket(i);  

} catch(IOException e) {
System.out.println("ERROR at: Server Construction");
}  
}
public void acceptConnections(){
try {
System.out.println("Waiting for connections...");
while (numPlayers < maxPlayers) { 
Socket s = ss.accept();
DataInputStream in = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());

numPlayers++;
out.writeInt(numPlayers);
System.out.println("Player Number "+numPlayers+" has connected");

ReadFromClient rfc = new ReadFromClient(numPlayers,in);
WriteToClient wtc = new WriteToClient(numPlayers,out);

if(numPlayers == 1){
socket1 = s;
p1read = rfc;
p1write = wtc;
Thread read1 = new Thread(p1read);
Thread write1 = new Thread(p1write);
read1.start();
write1.start();
}
else{
socket2 = s;
p2read = rfc;
p2write = wtc;
Thread read2 = new Thread(p2read);
Thread write2 = new Thread(p2write);
read2.start();
write2.start();
}
} // end of while
System.out.println("No longer accepting connections");
} catch(IOException e) {
System.out.println("ERROR at: acceptConnections");
}
}

public static void main(String[] args) {
new GameServer();
}

public class ReadFromClient implements Runnable{
public int playerID;
public DataInputStream dataIn;
public ReadFromClient(int pid, DataInputStream in){
playerID = pid;
dataIn = in;
System.out.println("RFC "+playerID+" Runnable created");
}
@Override
public void run(){
try {
while (true) { 
if(playerID == 1){
p1x1 = dataIn.readInt();
p1y1 = dataIn.readInt();
p1x2 = dataIn.readInt();
p1y2 = dataIn.readInt();
}
else{
p2x1 = dataIn.readInt();
p2y1 = dataIn.readInt();
p2x2 = dataIn.readInt();
p2y2 = dataIn.readInt();
}
try {
Thread.sleep(25); 
} catch(InterruptedException ex) {
System.out.println("ERROR at RFS Run"); 
}
} // end of while
} catch(IOException e) {
System.out.println("ERROR at: RFS");
}
}
}
public class WriteToClient implements Runnable{
public int playerID;
public DataOutputStream dataout;
public WriteToClient(int pid, DataOutputStream out){
playerID = pid;
dataout = out;
System.out.println("WTC "+playerID+" Runnable created");
}
@Override
public void run(){
try {
while (true) { 
if(playerID == 1){
dataout.writeInt(p2x1);
dataout.writeInt(p2y1);
dataout.writeInt(p2x2);
dataout.writeInt(p2y2);

dataout.flush();
}
else{
dataout.writeInt(p1x1);
dataout.writeInt(p1y1);
dataout.writeInt(p1x2);
dataout.writeInt(p1y2);
dataout.flush();
}
try {
Thread.sleep(25); 
} catch(InterruptedException ex) {
System.out.println("ERROR at WTC Run"); 
} 
} // end of while
} catch(IOException e) {
System.out.println("ERROR at: WTC run");  
}
}
}
public class ServerThread implements Runnable{
public int num;
public ServerThread(int i){
num = i;
}
@Override
public void run(){
gs[num].acceptConnections();
}

}
} // end of class GameServer

我没有任何错误,即使当我运行第三个玩家时,窗口不会弹出。

只有一个ServerSocket和一个循环,在接受客户端套接字时,使用该套接字启动一个运行游戏的线程。

ServerSocket serverSocket = ...
ExecutorService executorService = Executors.newFixedThreadPool(4);
while (!executorService .isTerminated()) {
Socket socket = serverSocket.accept();
Runnable gameRun = () -> { ... socket ... };
// like new WorkerThread("...");
executorService .execute(gameRun);
}
executorService .shutdown();

你可以做得比这里更整洁,线程和传递套接字等等。

以上内容在其各自的线程中运行每个游戏对话。它在服务器套接字上有一个主循环,这是至关重要的;不应在两个线程中使用相同的ServerSocket。

您很容易被DoS攻击(拒绝服务,数百个请求(淹没。只需留意线程数即可。


根据请求

我无法在这里对整个客户端-服务器对话框进行编码。为此你应该看看例子,这些例子可能比什么要好得多我可以在这里写作。我的代码也没有编译。

一些代码片段。首先,我不会交换二进制数据,而是文本。这使得开发,尤其是调试更加容易。还有国际象棋符号,一切都快完成了。

Runnable gameRun = new GameRun(socket);
executorService .execute(gameRun);
class GameRun implements Runnable, Autoclosable {
final BufferedReader in;
final PrintWriter out
GameRun(Socket socket) {
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream(),
StandardCharsets.UTF_8));
out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream(),
StandardCharsets.UTF_8)));
}
@Override
public void close() {
in.close();
out.close();
}
@Override
public void run() {
for (;;) {
out.println("Your move/action:");
if (!in.ready()) {
out.println("I am awaiting...");
//continue;
}
String line = in.readLine();
out.println("echo " + line);
if (line == null) {
break;
}
}
}
}

客户应该做类似的事情。

最新更新