代码之家  ›  专栏  ›  技术社区  ›  Joseph Hwang

java套接字聊天代码抛出java.net.SocketException:socket closed

  •  0
  • Joseph Hwang  · 技术社区  · 7 年前

    我尝试用javasocketapi制作基本的Java聊天应用程序。但当客户端被终止时,它抛出以下异常:,

    java.net.SocketException:套接字已关闭

    我的代码

    服务器

    package com.aaa.server;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    public class JavaChatServer {
    
        final static int Port = 10001; 
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ServerSocket serverSocket = null;
            Map<String, PrintWriter> clientMap = null;
    
            try {
                serverSocket = new ServerSocket(Port);
                clientMap = new HashMap<String, PrintWriter>();
                Collections.synchronizedMap(clientMap);
    
                while(true) {
                    System.out.println("Waiting Connection ....");
                    Socket socket = serverSocket.accept();
    
                    ServerThread thread = new ServerThread(socket, clientMap);
                    thread.start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if(!serverSocket.isClosed()) {
                        serverSocket.close();
                    }
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    
    }
    
    class ServerThread extends Thread {
        private Socket socket = null;
        private BufferedReader br = null;
    
        private Map<String, PrintWriter> clientMap;
        private String id;
    
        public ServerThread(Socket socket, Map<String, PrintWriter> clientMap) {
            this.socket = socket;
            this.clientMap = clientMap;
        }
    
        @Override
        public void run() {
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
    
                id = br.readLine();
                broadcast(id + " is connected");
                System.out.println("Connected User Id : " + id);
                clientMap.put(id, pw);
    
                String msg = "";
    
                while(true) {
                    msg = br.readLine();
    
                    if(msg.equals("/exit")) {
                        break;
                    }
    
                    broadcast(id + " : " + msg);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    clientMap.remove(id);
                    broadcast(id + " is disconnected!!");
    
                    if (br != null)
                        br.close();
                    if(socket != null)
                        socket.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    
        private void broadcast(String msg) throws Exception{
            Collection<PrintWriter> collection = clientMap.values();
            Iterator<PrintWriter> iterator = collection.iterator();
    
            while(iterator.hasNext()) {
                PrintWriter pw = iterator.next();
                pw.println(msg);
                pw.flush();
            }
        }
    }
    

    顾客

    package com.aaa.client;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.Scanner;
    
    public class JavaChatClient {
    
        final static int Port = 10001;
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Socket socket = null;
            PrintWriter pw = null;
    
            Scanner keyboard = new Scanner(System.in);
            String id = "";
    
            try {
                socket = new Socket("localhost", Port);
    
                pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                System.out.print("Welcome to Chat Room. Pls, type your ID : ");
                id = keyboard.nextLine();
                pw.println(id);
                pw.flush();
    
                ClientInputThread inputThread = new ClientInputThread(socket);
                inputThread.start();
    
                String msg = "";
                while (!msg.toLowerCase().equals("/exit")) {
                    msg = keyboard.nextLine();
    
                    if(!msg.trim().equals("")) {
                        pw.println(msg);
                        pw.flush();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (keyboard != null)
                        keyboard.close();
                    if (pw != null)
                        pw.close();
                    if(socket != null)
                        socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    
    class ClientInputThread extends Thread {
        private Socket socket = null;
    
        public ClientInputThread (Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            BufferedReader br = null;
    
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String msg = "";
    
                while(true) {
                    if(socket.isClosed())
                        break;
    
                    msg = br.readLine(); // This line throws SocketException
                    System.out.println(msg);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    当生成的客户端以“/Exchange”消息终止时, BufferedReader.readLine() 行引发如下异常

    java.net.SocketException: Socket closed
            at java.net.SocketInputStream.read(Unknown Source)
            at java.net.SocketInputStream.read(Unknown Source)
            at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
            at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
            at sun.nio.cs.StreamDecoder.read(Unknown Source)
            at java.io.InputStreamReader.read(Unknown Source)
            at java.io.BufferedReader.fill(Unknown Source)
            at java.io.BufferedReader.readLine(Unknown Source)
            at java.io.BufferedReader.readLine(Unknown Source)
            at com.aaa.client.ClientInputThread.run(JavaChatClient.java:80)
    

    我认为BufferedReader流仍然试图读取行消息,即使套接字已经关闭。

    但我不知道何时以及如何在客户端终止时关闭BufferedReader流和Socket连接。

    我完全被困在这部分。有什么想法吗?

    1 回复  |  直到 7 年前
        1
  •  0
  •   zhh    7 年前

    这是因为当你打电话 readLine() ,套接字已关闭。如果消息是 \exit ,然后第一站 inputThread (使用旗帜或其他东西),然后发送 退出 到服务器。总之,检查一下 /exit ->停止 输入线程 ->发送 退出 到服务器。

    String msg = "";
    while (!msg.toLowerCase().equals("/exit")) {
        msg = keyboard.nextLine();
    
        if (msg.toLowerCase().equals("/exit")) {
            // stop inputThread.
            // make sure inputThread is stopped.
        }
    
        if (!msg.trim().equals("")) {
            pw.println(msg);
            pw.flush();
        }
    }