我如何测试有人连接到我的服务器?

时间:2014-05-10 16:34:57

标签: java android

我正在创建一个Android客户端,我想确保它可以连接到Java服务器。

我的服务器就是这个

public static void main(String[] args){

    int portNumber = 5885;
    System.out.println("Starting..");

    // We use a try-with-resources statement to ensure that all sockets and 
    // readers/writers are closed when the program terminates
    try (
            // Set up the server socket on a specified port number
            ServerSocket serverSocket = new ServerSocket(portNumber);

            // Wait until a connection is made by a client and accept its socket
            Socket clientSocket = serverSocket.accept();

            // Set up a writer to the client socket
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

            // Set up a reader from the client socket
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        ) {

            // Missing Part

        } catch (IOException e) {
            System.out.println("Exception caught when trying to listen on port " + portNumber + " or listening for a connection");
            System.out.println(e.getMessage());
        }
    }
}

并且客户端正在尝试连接此代码

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.board_layout);

    new Thread(new ClientThread()).start();

 }

class ClientThread implements Runnable {

    @Override
    public void run() {

        try {
            InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

            socket = new Socket(serverAddr, SERVERPORT);

        } catch (UnknownHostException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

    }

}

如何检查是否有人连接到服务器?用

if (clientSocket != null)
     System.out.println("Someone is in");

还是什么?

2 个答案:

答案 0 :(得分:1)

如果您希望在客户端连接时收到通知..

Socket clientSocket = serverSocket.accept();之后放一个打印声明。方法ServerSocket#accept将阻止执行,直到客户端被接受为止,这意味着accept之后的打印语句只会在客户端被接受时触发。

try(ServerSocket server = new ServerSocket(5885)) {
    while(true) {
        try {
            Socket socket = server.accept();
            System.out.println("Client accepted!");
        } catch(IOException e) {
            e.printStackTrace(); // error accepting client
        }
    }
} catch(IOException e) {
    e.printStackTrace(); // error starting server
}

如果您想检查用户是否在线..

您需要为每个用户分配唯一的ID。然后,您需要一个数据结构来存储每个用户 - 一个允许您根据ID获取用户的用户可能是首选(Map可行)。

当您接受连接时..

生成UUID,然后将Socket存储在允许您使用密钥访问值的数据结构中(在本例中为UUID

class Server {
    private static final Map<UUID, Socket> CONNECTIONS = new HashMap<>();

    public static void main(String[] args) {
        try(ServerSocket server = new ServerSocket(5885)) {
            while(true) {
                try {
                    Socket socket = server.accept();
                    UUID uniqueId = UUID.randomUUID();

                    CONNECTIONS.put(uniqueId, Socket);
                } catch(IOException e) {
                    e.printStackTrace(); // error accepting client
                }
            }
        } catch(IOException e) {
            e.printStackTrace(); // error starting server
        }
    }

    public static boolean userExists(UUID uniqueId) {
        return CONNECTIONS.containsKey(uniqueId);
    }
}

您也可以使用用户名执行此操作。或者更好的是,创建一个由SocketUUIDString username;组成的自己的类型:

class User {
    private Socket socket;
    private UUID uniqueId;
    private String username;

    // constructor, getters, behaviors
}

维持List User而不是Map<UUID, Socket>

List<User> users = new ArrayList<>();

当您需要检查列表时,请将其转换为您要检查的属性的List

String nameOfUser = ...;

boolean containsUser= users.stream().map(User::getUsername).anyMatch(name -> name.equals(nameOfUser));

这假定UsergetUsername()方法。 UUID也可以这样做。

答案 1 :(得分:1)

如果您想知道客户端是否已连接,serverSocket.accept()将阻止,直到有人连接。这也应该在为每个客户端生成专用线程的循环中。

如果您想要可靠地确认客户端已连接,我会使用心跳(来自客户端的消息,其目的是确认连接的状态):

让每个客户端向服务器发送心跳。例如,在客户端有一个线程,它会休眠一段时间(10秒),然后唤醒以发送心跳。这样,如果您在一段时间内没有收到心跳,则表示存在连接问题。

只是为了说明这个概念:

服务器:

public void startServer() throws IOException{
        ServerSocket serverSocket = new ServerSocket(9209);
        List<ClientThread> clientThreads = new ArrayList<ClientThread>();
        boolean running = true;
        while(running){
            try {
                Socket clientSocket = serverSocket.accept();
                ClientThread clientThread = new ClientThread(clientSocket);
                clientThread.run();
                clientThreads.add(clientThread);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        for(ClientThread thread : clientThreads){
            thread.shutdown();
        }
}





 public class ClientThread extends Thread{
        private BufferedReader in;
        private volatile boolean running = true;
        private long lastHeartBeat;

        public ClientThread(Socket socket) throws IOException{
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        }

        public void shutdown(){
            running = false;
        }

        @Override
        public void run() {
            while(running){
                try {
                    if(in.readLine().equalsIgnoreCase("HeartBeat")){
                        lastHeartBeat = System.currentTimeMillis();
                    }else{
                        //do something else 
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

每个客户端都会创建以下内容之一:

public class HeartBeatThread extends Thread{

    PrintWriter out;
    volatile boolean running = true;

    public HeartBeatThread(Socket socket) throws IOException{
        this.out = new PrintWriter(socket.getOutputStream(), true);
    }

    public void shutdown(){
        running = false;
    }

    @Override
    public void run() {
        while(running){
            try {
                sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            out.println("HeartBeat");
        }
    }
}