Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关闭一个套接字将关闭所有套接字,Java_Java_Sockets - Fatal编程技术网

关闭一个套接字将关闭所有套接字,Java

关闭一个套接字将关闭所有套接字,Java,java,sockets,Java,Sockets,我有一个连接到一台服务器的多线程聊天室。它们彼此独立地连接、登录和发送消息都很好,但当我使用其中一个客户端注销时(服务器对该客户端实例执行socket.close()),所有客户端都将注销。在发布这篇文章之前,我看了一大堆关于stackoverflow的其他问题,但没有一个问题与我的(我发现的)问题相同。注意:所有的客户端都在我的计算机上本地运行,其中有2+个,这就是我遇到错误的原因。他们在同一个IP上(尽管一切都是在我的本地主机上完成的…)会导致这种情况发生吗?任何关于导致此问题的原因以及我如

我有一个连接到一台服务器的多线程聊天室。它们彼此独立地连接、登录和发送消息都很好,但当我使用其中一个客户端注销时(服务器对该客户端实例执行socket.close()),所有客户端都将注销。在发布这篇文章之前,我看了一大堆关于stackoverflow的其他问题,但没有一个问题与我的(我发现的)问题相同。注意:所有的客户端都在我的计算机上本地运行,其中有2+个,这就是我遇到错误的原因。他们在同一个IP上(尽管一切都是在我的本地主机上完成的…)会导致这种情况发生吗?任何关于导致此问题的原因以及我如何解决此问题的帮助或见解都将非常有用。当问题发生时,它还会将其输出到控制台:

Socket: Socket[addr=localhost/127.0.0.1,port=4000,localport=55650]
下面是代码(如何重新创建错误在底部):

服务器类:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;

public class ChatServer {

private static final int PORT = 4000;
private static HashSet<String> names = new HashSet<String>();
private static HashSet<ObjectOutputStream> outputs = 
                               new HashSet<ObjectOutputStream>();

public static void main(String[] args) throws IOException{
    System.out.println("The chat server is running...");
    ServerSocket listener = new ServerSocket(PORT);

    while(true){
        new Handler(listener.accept()).start();
    }
}

private static class Handler extends Thread{
    private String name;
    private Socket socket;
    private ObjectInputStream in;
    private ObjectOutputStream out;
    private boolean loggedOut;

    public Handler(Socket socket){
        this.socket = socket;

    }

    public void run(){
        try {
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputStream(socket.getInputStream());
            loggedOut = false;

            while(true){
                Message message = (Message) in.readObject();
                System.out.println("Server recieved login message!");
                if(message.getNumber() == 0){
                    name = message.getName();
                    synchronized(names){
                        if(!names.contains(name)){
                            names.add(name);
                            break;
                        }else{
                            Message nameTaken = new Message(null, 3);
                            sendMessage(out, nameTaken);
                        }
                    }
                }
            }

            synchronized(outputs){
                outputs.add(out);   
            }

            for(ObjectOutputStream output: outputs){
                Message response = new Message(name, name + " has logged on.", 0);
                sendMessage(output, response);
            }

            while(true){
                System.out.println("Waiting for message...");
                Message message = (Message) in.readObject();
                Message response = null;
                if(message.getNumber() == 1 && message.getMessage() != null){
                    response = new Message(message.getName(),
                                message.getMessage(), 1);
                }else if(message.getNumber() == 2){
                    response = new Message(message.getName(), message.getName() + 
                                         " has logged off.", 2);
                    loggedOut = true;
                }   
                for(ObjectOutputStream output: outputs){
                    sendMessage(output, response);
                }
                if(loggedOut) break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(name != null) names.remove(name);
            if(out != null) outputs.remove(out);
            try{
                socket.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

    private void sendMessage(ObjectOutputStream out, Message message){
        ObjectOutputStream outPutMessage = out;
        Message response = message;
        try {
            outPutMessage.writeObject(response);
            outPutMessage.flush();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}
}
import java.io.Serializable;

public class Message implements Serializable{

private int number;
private String message;
private String name;

public Message(String name, int number){
    this.name = name;
    this.number = number; 
}

public Message(String name, String message, int number){
    this.message = message;
    this.number = number;
    this.name = name;
}

public boolean isLogin(){
    if(number == 0) return true;
    return false;
}

public boolean isMessage(){
    if(number == 1) return true;
    return false;
}

public boolean isLogout(){
    if(number == 2) return true;
    return false;
}

public int getNumber() {
    return number;
}

public String getMessage() {
    return message;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}
我知道这是一个很大的代码块,没有那么整齐的文档/格式,所以我为此道歉。我只是发布了全部内容,这样您就可以通过完整地运行代码来复制问题。此外,请忽略JList,因为自从遇到此问题以来,我还没有找到它,并且无法解决注销/套接字问题。要重新创建错误,请执行以下步骤:

  • 运行服务器类
  • 运行客户机类,输入“localhost”作为服务器地址,然后输入名称并单击登录
  • 运行另一个客户端类并遵循步骤2
  • 单击其中一个客户端类上的注销,您将看到另一个客户端类也已注销

  • 提前谢谢你的帮助,我很感激

    在ChatClient类中,您需要更改行

    } else if (message.getNumber() == 2) {
    


    因为当前的方式,每个聊天客户端都会收到一条消息,表明某个客户端已注销,并且每个客户端都会通过注销来响应该消息。在该消息之后,您需要处理额外的情况。getNumber()==2,因为现在您将假定这意味着该名称已被取下。

    噢,哇,我完全没有想到这是原因!我真蠢,竟然用这个号码来识别是否有人已注销,同时显示出此人已登录到所有其他客户——完全是疏忽。我想我并没有像我想的那样彻底地看清楚><非常感谢你仔细地看了一遍并弄明白了这一点!非常感谢。是的,我添加了一个额外的case,因为它默认为if/else块的name take部分。谢谢
    } else if (message.getNumber() == 2) {
    
    } else if (message.getNumber() == 2 && message.getName().equals(name)) {