jnr / jnr-unixsocket

UNIX domain sockets (AF_UNIX) for Java
Apache License 2.0
278 stars 75 forks source link

Blocking reading from a UnixSocketChannel blocks writes #53

Open lihaoyi opened 6 years ago

lihaoyi commented 6 years ago

The following code sends hello from a client thread to a server thread over a UnixSocketChannel, and the server prints out the character codes (pardon my Scala)

package mill.clientserver

import java.nio.channels.Channels
import jnr.unixsocket.{UnixServerSocketChannel, UnixSocketAddress, UnixSocketChannel}

object Main {
  val tmp = java.nio.file.Files.createTempDirectory("") + "/sock"
  val addr = new UnixSocketAddress(tmp)
  def main(args: Array[String]): Unit = {
    new Thread(() => server()).start()
    new Thread(() => client()).start()
  }
  def server() = {
    val io = UnixServerSocketChannel.open()
    io.socket().bind(addr)

    val in = Channels.newInputStream(io.accept())

    while(true) println(in.read())
  }
  def client() = {
    Thread.sleep(1000)
    val ioSocket = UnixSocketChannel.open(addr)
    val in = Channels.newInputStream(ioSocket)
    val out = Channels.newOutputStream(ioSocket)

//    new Thread(() => println(in.read())).start()

    Thread.sleep(100)
    out.write("hello\n".getBytes)
  }
}

If you uncomment the new Thread(() => println(in.read())).start(), the out.write("hello\n".getBytes) appears to never make it to the server thread, and nothing is printed. It appears blocking on the UnixSocketChannel's in.read() also disables out.write. Not sure if this is expected or a bug, but another socket library I tried https://github.com/sbt/ipcsocket appears to allow writes while some other thread is read-blocked

CAFEBABE88 commented 6 years ago

You are using blocking I/O, that's how it works.

CAFEBABE88 commented 6 years ago

set the channel to nonblocking and use selector to get the read event and write when you have data to transfer. channel.configureBlocking(false);