创建一个Object,将Object传递给另一个Object的构造函数,在Object上调用wait(),然后在Java中notify() [英] Create an Object, pass the Object to another Object's constructor, call wait() on Object, then notify() in Java

查看:42
本文介绍了创建一个Object,将Object传递给另一个Object的构造函数,在Object上调用wait(),然后在Java中notify()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的服务器的同一端口上处理多个连接.我是通过实例化一个对象并将其传递给另一个实现 Runnable 的类的构造函数来实现的.然后我在 Runnable 类中设置一个套接字,并在客户端连接到端口后对传递的对象调用 notify() .这应该允许服务器重新启动它的循环,在收到通知后创建 Runnable 类的另一个实例.但是,目前直到客户端关闭后才会到达 wait() .以下是我拥有的 3 个相关课程:

I'm trying to handle multiple connections on the same port of my server. I'm doing this by instantiating an Object and passing it into the constructor for another class, which implements Runnable. Then I set up a socket in the Runnable class and call notify() on the passed Object after a Client connects on the port. This should then allow the server to restart its loop, creating another instance of the Runnable class after being notified. However, currently the wait() isnt being reached until after the client is closed. Here are the 3 relevant classes I have:

服务器类:

   package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.HashMap;

public class Server {

    public static void main(String[] args){
        HashMap<String, PortDummy> portDummies = new HashMap<String, PortDummy>();
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8000);
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        for(;;){
            Object block = new Object();
            PortDummy dummy = new PortDummy(serverSocket, block, portDummies);
            System.out.println("Running dummy port...");
            dummy.start();
            try {
                synchronized(block){
                    System.out.println("Waiting...");
                    block.wait();
                    System.out.println("Block notified.");
                }
            } catch (InterruptedException e) {
                System.out.println("Can't be interrupted!");
                e.printStackTrace();
            }
        }
    }
}

PortDummy(可运行)类:

PortDummy (Runnable) class:

   package server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class PortDummy extends Thread {

    private Object block;
    private HashMap<String, PortDummy> portDummies;
    private String clientName = null;
    ServerSocket serverSocket;
    BufferedReader socketIn;
    PrintWriter socketOut;

    public PortDummy(ServerSocket serverSocket, Object block, HashMap<String, PortDummy> portDummies){
        this.block = block;
        this.portDummies = portDummies;
        this.serverSocket = serverSocket;
    }

    @Override
    public void run() {
        try {
            System.out.println("Starting dummy port...");
            Socket clientSocket = serverSocket.accept();
            System.out.println("Connection made.");
            synchronized(block){
                System.out.print("Notifying...");
                block.notify();
                System.out.println("...done.");
            }

            socketIn = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            socketOut = new PrintWriter(clientSocket.getOutputStream(), true);

            String inContent;

            boolean loggedIn = false;
            while((inContent = socketIn.readLine()) != null){   
                socketOut.println("Server Echo: " + inContent);
                if(inContent.startsWith("/exit")){
                    if(loggedIn){
                        portDummies.remove(clientName);
                        System.out.println(clientName + " signed out. Removed from portDummies.");
                    }
                    else{
                        System.out.println("Closing...");
                    }
                }
                else if(inContent.startsWith("/register")){
                    System.out.println("/register accepted");
                    if(!loggedIn){
                        if(registerUser(inContent)){
                            System.out.println("Successfully registered.");
                            socketOut.println(clientName + " successfully registered.");
                            loggedIn = true;
                        }else{
                            socketOut.print("That user already exists.");
                        }
                    }
                    else{
                        socketOut.print("Already logged in.");
                    }
                }
                else if(inContent.startsWith("/tell")){
                    if(!loggedIn){
                        socketOut.println("You need to log in.");
                    }
                    else{
                        String[] parts = inContent.split("\\w");
                        String[] withoutCommand = new String[parts.length-1];
                        for(int i = 1; i<parts.length-1; i++){
                            withoutCommand[i] = parts[i];
                        }
                        String[] messageParts = new String[withoutCommand.length-1];
                        String message = "";
                        for(int j = 1; j<withoutCommand.length-1; j++){
                            message += withoutCommand[j] + " ";
                        }

                        String recipient = withoutCommand[0];
                        sendMessage(recipient, message);
                    }
                }
                else if(inContent.startsWith("/help")){
                    socketOut.print("/help ~~~~~~~ List all commands. \n " +
                            "/register <username> ~~~~~~~ Register a new user with 'username'. \n " +
                            "/tell <username> <message> ~~~~~~~ Send 'username' text 'message'. \n " +
                            "/exit ~~~~~~~ Log out.");
                }
            }

            System.out.println("Shutting down client connections...");
            socketOut.close();
            socketIn.close();
            clientSocket.close();
            serverSocket.close();

        } catch (IOException e) {
            System.out.println("IOException!");
            e.printStackTrace();
        }       
    }

    private boolean registerUser(String text){
        System.out.println("Registering user...");
        String user = text.substring(10);
        if((user != null) && !(portDummies.containsKey(user))){
            portDummies.put(user, this);
            clientName = user;
            System.out.println(user + " registered.");
            return true;
        }
            return false;
    }

    private void sendMessage(String username, String message){
        if(portDummies.containsKey(username)){
            PortDummy recip = portDummies.get(username);
            recip.getSocketOutput().println(clientName + ": " + message);
        }
        else{
            socketOut.write("User " + username + " doesn't exist.");
        }
    }

    public PrintWriter getSocketOutput(){
        return socketOut;
    }
}

客户端类:

package client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.io.IOException;

public class Client {

    protected String username;

    public static void main(String[] args){
        try{
            Socket serverSocket = new Socket("localhost", 8000);
            BufferedReader socketIn = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
            PrintWriter socketOut = new PrintWriter(serverSocket.getOutputStream(), true);

            Scanner keyboardInputScanner = new Scanner(System.in);
            String keyboardInput, serverInput;
            System.out.println("Welcome to Chris Volkernick's Server IM Client! \n" +
                    "Type '/register <username>' to register, '/list' to list connected users," +
                    "\n or '/tell <username> <message>' to send a user a message. '/help' lists these commands. (Type '/exit' to sign out.)");
            while((keyboardInput = keyboardInputScanner.nextLine()) != null){
                System.out.println("Input '" + keyboardInput + "' read on client side.");
                if(keyboardInput.equals("/exit")){
                    socketOut.println("/exit");
                    socketOut.close();
                    socketIn.close();
                    serverSocket.close();
                }else{
                    socketOut.println(keyboardInput);

                    while((serverInput = socketIn.readLine()) != null){
                        System.out.println(serverInput);
                    }
                }           
            }       
            keyboardInputScanner.close();

        }catch(IOException e){
            System.out.println("IOException!");
            e.printStackTrace();
        }       
    }
}

我在使用 wait() 和/或 notify() 时做错了吗?

Am I doing something wrong with the wait() and/or notify()?

我还尝试将实现 Runnable 更改为扩展线程,然后将服务器中的 .run() 更改为 .start(),但这给了我这个错误:

I also tried changing the implements Runnable to extends Thread then changing the .run() in the server to .start(), but that gives me this error:

java.net.BindException: Address already in use: JVM_Bind
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:365)
    at java.net.ServerSocket.bind(ServerSocket.java:319)
    at java.net.ServerSocket.<init>(ServerSocket.java:185)
    at java.net.ServerSocket.<init>(ServerSocket.java:97)
    at server.PortDummy.run(PortDummy.java:28)

编辑 2:就启动新线程而言,它似乎按照现在的方式工作.但是,我现在遇到了另一个问题:在任何给定客户端的客户端输入命令后,我无法输入其他命令.第一个命令可以正常工作(减去/exit;还没有完全弄清楚它应该如何工作),之后就不能做任何事情了.例如,我可以注册(登录),但之后就没有别的了.我可以进入 Client 的另一个实例并列出所有当前用户(工作),但同样,之后我无法输入其他命令.知道是什么原因导致了这种情况吗?

推荐答案

问题是您的子线程正在尝试侦听端口 8000,但父线程已经这样做了.您需要做的是通过接受来自原始套接字的连接,然后将其提供给子线程.我不确定如何在 Java 中执行此操作,但我怀疑它只是..

The problem is that your child threads are trying to listen on port 8000, but the parent thread is already doing that. What you need to do is pass accept a connection from the original socket and then give it to the child thread. I'm not exactly sure how to do this in Java, but I suspect it's just..

把它放在你的主线程中:

Put this in your main thread:

ServerSocket serverSocket = new ServerSocket(8000);
Socket clientSocket = serverSocket.accept();

然后一旦你得到它,将 clientSocket 传递给你的 Thread.

And then once you get that, pass clientSocket to your Thread.

这样只有一个套接字监听端口 8000,但您可以让子线程处理每个连接.

That way there's only one socket listening on port 8000, but you can make child threads handle each connection.

这篇关于创建一个Object,将Object传递给另一个Object的构造函数,在Object上调用wait(),然后在Java中notify()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆