ObjectInputStream readObject意外关闭套接字

时间:2019-09-28 19:09:55

标签: sockets kotlin network-programming serversocket

我想设置一个服务器/客户端,其中客户端通过套接字向服务器发送可序列化的对象。由于某种原因,当我尝试读取发送到服务器的对象时,我会不断得到java.net.SocketException: SocketClosed

这是我给客户的代码:

class Client(address: String, port: Int) {
    private val connection: Socket = Socket(address, port)
    private var connected: Boolean = true
    private val writer = ObjectOutputStream(connection.getOutputStream())
    private val reader = ObjectInputStream(connection.getInputStream())

    init {
        println("Connected to server at $address on port $port")
    }

    fun run() {
        var sent = false
        while (connected) {
            try {
                if (!sent) {
                    sent = true
                    writer.use {
                        it.writeObject("Hello")
                        it.flush()
                    }
                    println("Sent")
                } else {
                    println("Didn't send")
                }
                Thread.sleep(1000)
            } catch (ex: Exception) {
                ex.printStackTrace()
                shutdown()
            }
        }
    }

    ...
}

这是服务器的代码:

class ClientHandler(private val client: Socket) {
    private val reader = ObjectInputStream(client.getInputStream())
    private val writer = ObjectOutputStream(client.getOutputStream())
    private var running: Boolean = false

    fun run() {
        running = true

        while (running) {
            try {
                reader.use {
                    val packet = it.readObject()

                    when (packet) {
                        is String -> {
                            println("Received packet with data: ${packet}")
                        }
                    }
                }
            } catch (ex: Exception) {
                ex.printStackTrace()
                shutdown()
            }
        }
    }

    ...
}

我的服务器上的输出是

Server is running on port 9999
Client connected: 127.0.0.1
Received packet with data: Hello
java.net.SocketException: Socket closed
    at java.base/java.net.SocketInputStream.socketRead0(Native Method)
    at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
...

因此,好像我的String的一个实例正在使用它,但是后来的调用声称该套接字已关闭。

我见过的与此问题相关的其他每篇文章都声称发件人(客户端)正在尽早关闭套接字。但是,我知道客户端不是通过自己的方式关闭套接字。如果我将客户代码更改为:

class Client(address: String, port: Int) {
    ...
    private val writer = connection.getOutputStream()          // Regular streams
    private val reader = Scanner(connection.getInputStream())

    ...


    fun run() {
        var sent = false
        while (connected) {
            try {
                if (!sent) {
                    sent = true
                    writer.write("Hello\n".toByteArray())    // Send regular byte array
                    println("Sent")
                } else {
                    println("Didn't send")
                }

    ...
}

和我的服务器代码:

class ClientHandler(private val client: Socket) {
    private val reader = Scanner(client.getInputStream())    // Regular streams
    private val writer = client.getOutputStream()
    private var running: Boolean = false

    fun run() {
        running = true

        while (running) {
            try {
                // Just read lines from stream
                println(reader.nextLine())
            }

    ...
}

然后我的输出就是我所期望的:

Server is running on port 9999
Client connected: 127.0.0.1
Hello

我唯一的假设是.readObject()正在某种程度上关闭套接字连接,从而迫使下一个readObject()抛出异常。不过,这对我来说没有太大意义。为什么会这样?

1 个答案:

答案 0 :(得分:1)

深入研究代码可以给我所需的答案。 .use似乎在完成后关闭了套接字。删除use { }块使此工作按预期进行。