Java套接字聊天代码抛出java.net.SocketException:套接字已关闭

时间:2018-08-04 06:06:32

标签: java sockets

我尝试使用Java套接字API创建基本的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();
        }
    }
}

当生成的客户端以“ / exit”消息终止时,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流和套接字连接。

我完全陷入了这一部分。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

这是因为在调用readLine()时,套接字已关闭。您可以先检查味精,如果味精是\exit,然后首先停止inputThread(使用标志或其他方式),然后将\exit发送到服务器。简短地说,请检查/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();
    }
}