gpt4 book ai didi

java - 创建一个对象,将该对象传递给另一个对象的构造函数,在该对象上调用 wait(),然后在 Java 中调用 notification()

转载 作者:行者123 更新时间:2023-11-30 04:58:20 24 4
gpt4 key购买 nike

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

服务器类别:

   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(可运行)类:

   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()方面做错了什么吗?

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

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;还没有完全弄清楚它应该如何工作),只是之后无法执行任何操作。例如,我可以注册(登录),但之后就什么都没有了。我可以进入客户端的另一个实例并列出所有当前用户(有效),但同样,此后我无法输入其他命令。知道可能发生什么原因导致这种情况吗?

最佳答案

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

将其放入主线程中:

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

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

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

关于java - 创建一个对象,将该对象传递给另一个对象的构造函数,在该对象上调用 wait(),然后在 Java 中调用 notification(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7775790/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com