如何处理从大厅服务器到客户端的多个流

时间:2018-10-23 17:13:04

标签: java networking input stream connection

所以,我的一个项目遇到了问题。我正在编写一个多人游戏大厅系统,该系统将允许多个用户加入一个大厅,并通过按下一个键进行准备。我面临的问题是,当两个玩家准备就绪时,大厅仅向最后准备就绪的玩家打印一条消息。该系统以以下方式构建。

主服务器

package master;

import java.net.*;
import java.io.*;
import java.util.*;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import main.Lobby;

public class MainServer {

public static final int PORT = 4444;
public static final String HOST = "localhost";
public ArrayList<Lobby> serverList = new ArrayList<>();

public static void main(String[] args) throws IOException, ClassNotFoundException {

    new MainServer().runServer();
}

public void runServer() throws IOException, ClassNotFoundException {

    // Creating the server

    ServerSocket serverSocket = new ServerSocket(PORT);
    System.out.println("Main Server initiated.");

    while (true) {

        Socket socket = serverSocket.accept();

        try {

            // Establishing the connection to the Lobby server and then adding it to its list
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject("Server created successfully.");
            Lobby s = (Lobby) objectInputStream.readObject();
            this.serverList.add(s);
            System.out.println("Server \"" + s.name + "\" added to game list.");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

}

大厅

package main;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.Semaphore;

import master.MainServer;

/**
 * The Class Server.
 */
public class Lobby implements Serializable {
    private static final long serialVersionUID = -21654L;
    public static final int PORT = 4445;
    public static final int MAX_USERS = 5000;
    public static final String HOST = "localhost";
    public String name = "Lobby Server";
    public int clientNumber;
    public int playerNumberReady = 0;
    public boolean allPlayersReady = false;
    public boolean OddurIsNice = false;

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Lobby s = new Lobby();
        s.runServer();
    }
    public void runServer() throws IOException, ClassNotFoundException {
        registerServer();
        new Thread( () -> {
            try {
                ServerSocket serverSocket = new ServerSocket(PORT);
                System.out.println("Server waiting for connections...");
                while (true) {
                    Socket socket = serverSocket.accept();
                    System.out.println("User 1 is now connected");
                    clientNumber++;             
 new ObjectOutputStream(socket.getOutputStream()).writeObject("You are connected man");
                        Socket socket2 = serverSocket.accept();
                        System.out.println("User 2 is now connected");
                        clientNumber++;
//                      ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket2.getOutputStream());
//                      objectOutputStream2.writeObject("You are player number " + clientNumber + ". Waiting for other players to join");
                        new ServerThread(socket, socket2).start();

                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }).start();
    }
    private void registerServer() throws UnknownHostException, IOException, ClassNotFoundException {
        // Method for establishing a connection to the MainServer 
        Socket socket = new Socket(MainServer.HOST, MainServer.PORT);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
        objectOutputStream.writeObject(this);

        System.out.println((String) objectInputStream.readObject());
    }
    public class ServerThread extends Thread {
        public Socket socket = null;
        public Socket socket2 = null;
        ServerThread(Socket socket, Socket socket2) {
            this.socket = socket;
            this.socket2 = socket2;
        }
        public void run() {
            try {       



// This method is for when the client want's to connect to the lobby
                    ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                    ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                    System.out.println("User 1 is now connected");

                    ObjectInputStream objectInputStream2 = new ObjectInputStream(socket2.getInputStream());
                    ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket2.getOutputStream());
                    System.out.println("User 2 is now connected");
                    BoardGameClient joined = (BoardGameClient) objectInputStream.readObject();
                    System.out.println(joined.name + " is now connected.");
                    while(true) {
                    objectOutputStream.writeObject("You joined the server.");
                    objectOutputStream.writeObject("You are player Number " + 1);

                    objectOutputStream.writeObject("Press '1' if you are ready");

                    objectOutputStream2.writeObject("You joined the server.");
                    objectOutputStream2.writeObject("You are player Number " + 2);

                    objectOutputStream2.writeObject("Press '1' if you are ready");

                if(objectInputStream.readObject().equals(1)) {
                    playerNumberReady++;
                }

                if(objectInputStream2.readObject().equals(1)) {
                    playerNumberReady++;
                }

                    if(playerNumberReady != 2) {
                        allPlayersReady = false;
                    } else {
                        allPlayersReady = true;
                    }



                    if (allPlayersReady == false) {
                        objectOutputStream.writeObject("Waiting...");
                        objectOutputStream2.writeObject("Waiting...");
                } 

                    if (allPlayersReady == true) {
                    objectOutputStream.writeObject("Lets GO");
                    objectOutputStream2.writeObject("Lets GO");
                }                           


                    while (true) {
                    System.out.println(objectInputStream.readObject());
                    }
                    }
                    } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

还有客户

    package main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.concurrent.Semaphore;

import master.MainServer;

public class BoardGameClient implements Serializable {

    private int playerName;
    private static final long serialVersionUID = -6224L;
    public String name = "User";
    private transient Socket socket;
    public transient Scanner input = new Scanner(System.in);    

    public static void main(String[] args) {

        BoardGameClient c = new BoardGameClient();

        if (args.length > 0) {

            c.name = args[0];
        }

        try {

            c.joinServer();

        } catch (ClassNotFoundException | IOException e) {

            System.out.println("Failed to join server.");
            e.printStackTrace();
        }
    }

    public void joinServer() throws UnknownHostException, IOException, ClassNotFoundException {

        socket = new Socket(Lobby.HOST, Lobby.PORT);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

        while(true) {
        objectOutputStream.writeObject(this);

        BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in));

        System.out.println(objectInputStream.readObject());
        System.out.println(objectInputStream.readObject());
        System.out.println(objectInputStream.readObject());

        int ready = input.nextInt();
        objectOutputStream.writeObject(ready);

        System.out.println(objectInputStream.readObject());



            objectOutputStream.writeObject(name + ": " + inputReader.readLine());
        }
    }
}

我衷心希望,有人能够帮助我<3

1 个答案:

答案 0 :(得分:0)

首先,关于此代码,有些事情令我感到困惑。听起来并不屈尊,但是您需要尽可能避免重写代码。如果您将来需要3个或更多玩家,会发生什么?当前,您必须手动创建一个完整的套接字,例如socket3,然后重写所有已经编写的代码。这是不好的。您手动花费了时间创建2个套接字,然后为这两个套接字等创建了2个流。

这可以自动化吗?

第二,您有很多公共变量。除非它们是静态的和最终的,否则在大多数情况下,应将变量保留为私有。

我已经修改了您的大厅课程,如下所示,它更具扩展性。无论如何,它都不是完美的,但我认为这说明了您应该追求的改进方向。查找SOLID OOP原则,它们可以帮助您保证。

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * The Class Server.
 */
public class Lobby implements Serializable {
    private static final long serialVersionUID = -21654L;
    public static final int PORT = 4445;
    public static final int MAX_USERS = 5000;
    public static final String HOST = "localhost";
    private static final int MIN_USERS = 2;

    private String name = "Lobby Server";
    private int clientNumber;
    private boolean gameRunning = false;

    // set of client connections
    private final Set<ServerThread> clientConnectionThreads = new LinkedHashSet<>();

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Lobby s = new Lobby();
        s.createLobby();
    }

    public void createLobby() throws IOException, ClassNotFoundException {
        // waits for all players to ready up in a different thread
        new Thread(this::waitReady).start();

        registerServer();

        // Listens for clients
        runServer();
    }

    public void runServer() {
        // closes serverSocket automatically in this way
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("Server waiting for connections...");
            long ids = 0;
            while (!gameRunning) {
                // accepts a new client connection
                Socket socket = serverSocket.accept();

                if (clientConnectionThreads.size() >= MAX_USERS) {
                    // tell user server is full and dont add the connection
                } else {
                    // calculates the new id of the incoming player and adds them to the lobby
                    ids++;
                    this.clientConnectionThreads.add(new ServerThread(ids, socket));
                    System.out.println("User " + ids + " is now connected");
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /*
     * loops until every player is ready and there is enough players and then starts
     * the game.
     */
    public void waitReady() {
        while (true) {
            try {
                if (areAllReady() && this.clientConnectionThreads.size() >= MIN_USERS) {
                    startGame();
                    return;
                }
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // returns true if all users are ready
    public boolean areAllReady() {
        return clientConnectionThreads.stream().allMatch(ServerThread::isReady);
    }

    public void startGame() {
        System.out.println("Starting game...");
        this.gameRunning = true;
        clientConnectionThreads.forEach(ServerThread::startGame);

        // do game stuff
    }

    // i havent touched this function
    private void registerServer() throws UnknownHostException, IOException, ClassNotFoundException {
        // Method for establishing a connection to the MainServer
        Socket socket = new Socket(MainServer.HOST, MainServer.PORT);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
        objectOutputStream.writeObject(this);

        System.out.println((String) objectInputStream.readObject());
    }

    public class ServerThread extends Thread {
        private final Socket socket;
        private final ObjectInputStream in;
        private final ObjectOutputStream out;
        private final long id;
        boolean ready = false;

        private ServerThread(long id, Socket socket) throws IOException {
            // does some basic initialization
            this.socket = socket;
            this.id = id;
            in = new ObjectInputStream(socket.getInputStream());
            out = new ObjectOutputStream(socket.getOutputStream());

            // starts this connection thread
            this.start();
        }

        public boolean isReady() {
            return ready;
        }

        public void run() {
            try {
                // sets up the client and waits for their input
                BoardGameClient joined = (BoardGameClient) in.readObject();
                System.out.println(joined.name + " is now connected.");
                out.writeObject("You joined the server.");
                out.writeObject("You are player Number " + id);
                out.writeObject("Press '1' if you are ready");
                out.flush();

                // waits for user to return ready
                while (!ready) {
                    try {
                        int input = in.readInt();
                        System.out.println("input: " + input);
                        ready = input == 1;
                    } catch (ClassCastException e) {
                        e.printStackTrace();
                    }
                }

                out.writeObject("Waiting for players...");

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void startGame() {
            // send client message etc etc
        }
    }

    public String getName() {
        return name;
    }
}

除了客户端类中的几行内容,我基本上没有更改其他任何类。 (我将就绪输入类型从writeObject()更改为writeInt()) 我还没有测试过这个问题,但是我知道它至少可以在基本水平上起作用。

我还建议使用writeUTS()/ readUTS()而不是writeObject()/ readObject()跨流发送和接收字符串,因为这会增加代码的复杂性。