java - 我基于套接字的 EchoServer 和 EchoClient 有什么问题?

标签 java sockets scala

我写了一个基于Socket的EchoServer和EchoClient:

package socket.echo

import actors.Actor
import java.net.{InetSocketAddress, Socket, ServerSocket}
import java.io.{ByteArrayOutputStream, InputStream, OutputStream}

object EchoServer {
  def main(args: Array[String]): Unit = {
    val port = if (args.length > 1 && args(0) != null) args(0).toInt else 8080;
    val backlog = if (args.length > 2 && args(1) != null) args(1).toInt else 50;
    new EchoServer(port, backlog).start()
  }
}

class EchoServer(val port: Int, val backlog: Int) extends Actor {
  def act() {
    val serverSocket = new ServerSocket(port, backlog)
    println("Create a serverSocket: " + serverSocket)
    var isStop = false
    while (!isStop) {
      val socket = serverSocket.accept();
      println("Create a socket " + socket)
      Actor.actor {
        val is = socket.getInputStream
        val os = socket.getOutputStream
        val buf = IO.read(is)
        os.write(buf)
        os.flush()
        is.close()
        os.close()
        val msg = new String(buf, "UTF-8")
        println("Receive " + msg + " from " + socket)
        if ("quit".equalsIgnoreCase(msg)) isStop = true
        socket.close()
      }
    }
    println("Server stop! ")
  }
}

object IO {
  val BYTE_BLOCK_LENGTH = 1024
  /**
   * The input and output stream won't be closed after the method invocation
   *
   * @param is
   * @param os
   */
  def copy(is: InputStream, os: OutputStream): Unit = {
    var buf = new Array[Byte](BYTE_BLOCK_LENGTH)
    var isStop = false
    while (!isStop) {
      val len = is.read(buf, 0, buf.length);
      if (len == -1) isStop = true
      else os.write(buf, 0, len)
    }
  }

  def read(is: InputStream, encoding: String): String = {
    var resBytes: Array[Byte] = read(is)
    return new String(resBytes, encoding)
  }

  def read(is: InputStream): Array[Byte] = {
    var baos: ByteArrayOutputStream = new ByteArrayOutputStream(BYTE_BLOCK_LENGTH)
    copy(is, baos)
    baos.flush
    var resBytes: Array[Byte] = baos.toByteArray
    is.close
    baos.close
    return resBytes
  }
}

object EchoClient {
  def main(args: Array[String]): Unit = {
    val ip = if (args.length > 1 && args(0) != null) args(0) else "127.0.0.1";
    val port = if (args.length > 2 && args(1) != null) args(1).toInt else 8080
    val n = if (args.length > 3 && args(2) != null) args(2).toInt else 100
    val isReuseAddr = if (args.length > 4 && args(3) != null) args(3).toBoolean else false

    for (i <- 0 until n) {
      val socket = createSocket(ip, port, isReuseAddr)
      val msg = "hello"
      println("send " + msg + " to " + socket.getRemoteSocketAddress)
      val is = socket.getInputStream()
      val os = socket.getOutputStream()
      os.write(msg.getBytes("UTF-8"))
      os.flush()
      IO.read(is)
      is.close
      os.close
      socket.close
    }


  }

  private def createSocket(ip: String, port: Int, isReuseAddr: Boolean): Socket = {
    val socket = new Socket()
    socket.setReuseAddress(isReuseAddr)
    socket.connect(new InetSocketAddress(ip, port))
    return socket;
  }
}

当 EchoServer 启动后启动 EchoClient 时,EchoServer 在 IO.read(is) 上被阻塞,因为如果我关闭 EchoClient,EchoServer 会报错:

scala.actors.Actor$$anon$1@1dd46f7: caught java.net.SocketException: Connection reset
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:168)
    at socket.echo.IO$.copy(Echo.scala:61)
    at socket.echo.IO$.read(Echo.scala:74)
    at socket.echo.EchoServer$$anonfun$act$1.apply$mcV$sp(Echo.scala:34)
    at scala.actors.Actor$$anon$1.act(Actor.scala:133)
    at scala.actors.Reactor$$anonfun$dostart$1.apply(Reactor.scala:222)
    at scala.actors.Reactor$$anonfun$dostart$1.apply(Reactor.scala:222)
    at scala.actors.ReactorTask.run(ReactorTask.scala:33)
    at scala.concurrent.forkjoin.ForkJoinPool$AdaptedRunnable.exec(ForkJoinPool.java:611)
    at scala.concurrent.forkjoin.ForkJoinTask.quietlyExec(ForkJoinTask.java:422)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.mainLoop(ForkJoinWorkerThread.java:340)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:325)

我的代码有什么问题吗?

PS:示例代码是用Scala写的,但是我觉得Java程序员比较容易理解

最佳答案

由于您的客户端正在阻止阅读回显的回复,主要问题是您的服务器是否真的在回显您正在阅读的所有内容。对于这个简单的任务,您的 I/O 代码过于复杂。不需要 ByteArrayOutputStreams,也不需要转换为字符串等。只需读写字节,确保只写入您读取的字节数。 “连接重置”通常意味着您已写入已被另一端关闭的连接。

关于java - 我基于套接字的 EchoServer 和 EchoClient 有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8003882/

相关文章:

java - gradle windows java.io.IOException : CreateProcess error=206, 文件名太长

java - 如何使用 JPA 中的规范连接多个列?

html - 使用fmt.Fprintf()发送文本/纯文本

c++ - 从 TArray<uint8> 中提取 float32

java - 使用java修改wave文件

java - 动态更改 JTree 的节点图像

java - 适用于 S3 的 AWS Java 开发工具包中的 SignatureDoesNotMatch

scala - 在 yarn 簇上使用带有管道的 addFile

通过套接字的 iOS 连接不起作用

generics - Scala list 有哪些限制?