套接字 - 软件导致连接中止:接收失败

Socket - Software caused connection abort: recv failed

我正在尝试构建一个简单的 TCP 多线程 client/server 应用程序。 每当客户端 (Socket) 连接到 ServerSocket 并发送对应于下面所示的简单可序列化 class 的 Object (Message) 时,服务器就会崩溃当他的 ObjectInputStream 尝试从客户端 Socket 读取时得到 SocketExpection.

Message.java

package storageserver;

import java.io.Serializable;

public class Message implements Serializable {

    private static final long serialVersionUID = 27015L;

    public int ClientStatus; // 0 - NotLogged :::  1 - Logged
    public String Command;
    public String[] Commands;  

    public Message()
    {
        this.ClientStatus = 0;
        this.Command = null;
        this.Commands = null;
    }   

    public void createMessage(String msg)
    {
        this.Command = msg;
        this.Commands = msg.split("\s+");
    }
}

StorageServer.java

package storageserver;
 // imports..


public class StorageServer {

    public static final int MAX_USERS = 250;

    ServerSocket myServerSocket;
    boolean serverOn = true;
    File workingDir;

    public StorageServer(int port, File dir) {

        try {
            InetAddress addr = InetAddress.getByName("192.168.1.73");

            myServerSocket = new ServerSocket(port, MAX_USERS, addr);
            workingDir = dir;
            if(!workingDir.exists())
                workingDir.mkdir();

            System.out.println("StorageServer created successfully.");

        } catch (IOException ex) {
            Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Could not create storage server on port 7000. Exiting."); 
            System.exit(-1); 
        }
    }

    public void listen()
    {
        System.out.println("Listening for connections...");
        while(serverOn)
        {
            try {
                //accepts incoming TCP connection
                Socket clientSocket = myServerSocket.accept();

                //starts new service thread to handle client requests in background
                new ClientHandleThread(clientSocket).start();
            }
            catch (IOException e)
            {
                System.out.println("Exception encountered on accept. Ignoring. Stack Trace :"); 
                e.printStackTrace();
            }
        }

        try {
            myServerSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class ClientHandleThread extends Thread {

        private Socket myClientSocket;
        private HashMap<String, Runnable> commandsMap;
        private Message messageToSend, messageToReceive;

        public ClientHandleThread() {
            super();
        }

        public ClientHandleThread(Socket myClientSocket) {
            this.myClientSocket = myClientSocket;
            this.messageToSend = new Message();
            this.messageToReceive = new Message();
        }

        private void help()
        {
            messageToSend.createMessage("Avaible commands:\n\n"
                + "exit                       -> Exits the App\n"
                + "stop                       -> Stops the server\n"
                + "dir                        -> Gets personal file's info in current server\n");
            messageToSend.ClientStatus = 0;
        }

        @Override
        public void run()
        {
            ObjectInputStream in = null; 
            ObjectOutputStream out = null;

            System.out.println("Accepted connection from "
                        +  myClientSocket.getInetAddress().getHostAddress()+ ":" + myClientSocket.getPort());

            try
            {        
                System.out.println("IN..");
                in = new ObjectInputStream(myClientSocket.getInputStream()); 
                out = new ObjectOutputStream(myClientSocket.getOutputStream()); 
                System.out.println("IN!");

                messageToReceive = (Message) in.readObject(); //exception here - Software caused connection abort: recv failed
                System.out.println("Client Says :" + messageToReceive.Command);

                out.writeObject(messageToSend);
                out.flush(); 

            } catch (IOException | ClassNotFoundException ex) {
                ex.printStackTrace();
                Logger.getLogger(StorageServer.class.getName()).log(Level.SEVERE, null, ex);
            }
            finally
            {
                try
                {                    
                    in.close(); 
                    out.close(); 
                    myClientSocket.close(); 
                    System.out.println("...Stopped"); 
                } 
                catch(IOException e) 
                { 
                    e.printStackTrace(); 
                }
            }
        }

    }

}

调试输出

java.net.SocketException: Software caused connection abort: recv failed
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at java.net.SocketInputStream.read(SocketInputStream.java:223)
    at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2303)
    at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2596)
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2606)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1319)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at storageserver.StorageServer$ClientHandleThread.run(StorageServer.java:145)
nov 11, 2015 2:53:36 AM storageserver.StorageServer$ClientHandleThread run

可能导致此异常的原因是什么?我确定我不会在任何地方(client/server 端)关闭或重置套接字连接。

编辑:

在下面添加了客户端代码。 客户端在尝试 receive() 来自服务器的响应时出现异常。

TCPService.java(客户端)

package client;

//imports..

public class TCPService {

    private Socket clientSocket;


    public TCPService(String host, int port)
    {
        try {
            clientSocket = new Socket(InetAddress.getByName(host), port);
            clientSocket.setSoTimeout(5000);
        } catch (IOException ex) {
            System.err.println("Cant connect to Storage Server.\n" + ex);
            System.exit(-1);
        }

    }

    public Message receive()
    {
        try { 
            ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
            try {
                Message msg = (Message) in.readObject();

                if(msg instanceof Message)
                    return msg;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }      

        }   catch (IOException ex) {
            Logger.getLogger(TCPService.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void send(Message msg)
    {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
            oos.writeObject(msg);
            oos.flush();
            oos.close();
        } catch (IOException ex) {
            Logger.getLogger(TCPService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    //Main
     public static void main(String[] args) throws IOException
    {        
        /* Service Variable Declaration */
        TCPService tcpService = new TCPService(args[0], args[1]);

        /* Other Variables */
        String buf = "";
        Scanner scanIn = new Scanner(System.in);
        Message msg = new Message();
        isTCPRunning = true;

        /* While-Loop for TCP Service */
        while (isTCPRunning)
        {
            System.out.print("[User@StorageServer] Insert command: ");
            buf = scanIn.nextLine();

            msg.createMessage(buf);

            scanIn.reset();

            tcpService.send(msg);

            msg = tcpService.receive(); //SocketException -> Socket Closed

            System.out.println("[StorageServer] " + msg.Command);

            tcpService.handleMessage(msg);
        }
}

发送消息后,客户端立即关闭 ObjectOutputStream。这将关闭套接字的输出流,从而关闭套接字。当客户端尝试从输入流中读取时,套接字已经关闭,因此客户端出现异常。这也可能导致服务器端出现问题,因为在服务器读取数据时,TCP 连接可能已经关闭。