Closed xueqiwang0v0 closed 8 months ago
Thanks for reporting, @xueqiwang0v0!
I think it's due to the fact that it's likely an AF_INET or AF_INET6 socket (you mention TCP), which junixsocket currently doesn't provide specific support for.
In that sense, junixsocket "works as expected", but obviously it's not working for you.
I see three possible solutions:
I can see the utility for ensuring compatibility with apps expecting a Socket instance, so option 3 may happen eventually.
A workaround that works right now would be to "cast" the FileDescriptor
to ByteChannel
or FileInputStream
/FileOutputStream
instead, so you can at least communicate bidirectionally.
Any other ideas?
Thanks for your reply, @kohlschuetter !
Sorry for my misusage about junixsocket library. It offers great help to my project! So many thanks again!
I'm currently working on option 1. I achieved rebuilding Socket using reflection, while ServerSocket rebuild is still unsolved. For option 3, will there be a rough plan?
There's no plan yet for option 3, but it may eventually arrive.
I will keep this ticket open for now to be reminded of it. Contributions are of course welcome!
@xueqiwang0v0
I've made some progress towards supporting your use case, but I haven't fully tested it yet.
Please try the latest 2.9.0-SNAPSHOT
.
Make sure the following section is in your POM:
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
Then run mvn clean compile --update-snapshots
(or similar) from your project.
If you use Gradle, please specify the following section in your build.gradle
file:
repositories {
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
mavenContent {
snapshotsOnly()
}
}
}
Then run gradle clean build --refresh-dependencies
(or similar) from your project.
@kohlschuetter Thanks for your help! I tested the new version 2.9.0-SNAPSHOT using 2 cases:
Case 1: transfer a tcp connection. I sent the tcp socket fd to another process and then rebuilt the connection using FileDescriptorCast. The new version works well. The rebuilt tcp connection received messages and replied as expected.
Case 2: transfer a listening tcp server. I sent the serverSocket fd to another process and then rebuilt it using FileDescriptorCast. Then I tried to establish a new tcp connection and communicate. There's something going wrong. The rebuilt server did not block waiting for the new connection. As a result, it throwed null pointer exception when I tried to get the inputStream and outputStream of the new connection. My Core Rebuild Steps:
// rebuild the server socket
ServerSocket serverSocket = FileDescriptorCast.using(serverFD).as(ServerSocket.Class);
// wait for client connection // The method should block until a connection is made. Socket connSocket = serverSocket.accept(); log.info("New client connected.");
// communicate BufferedReader input = new BuferredReader(new InputStreamReader(connSocket.getInputStream())); PrintWriter newClientOutput = new PrintWriter(connSocket.getOutputStream(), true);
@xueqiwang0v0 Cool, that's good news! (regarding case 1).
Regarding case 2, I think you found another bug that we should fix. Is there a chance that your socket was configured non-blocking in native code?
I think that calling configureBlocking(true) is currently not working as expected since there is some Java Socket code that ignores that call if the Java base class "thinks" it's blocking already.
Please try adding
serverSocket.getChannel().configureBlocking(false);
serverSocket.getChannel().configureBlocking(true);
right after casting the socket, and before calling accept
.
@kohlschuetter It works! Thanks a lot!
@xueqiwang0v0 That's great news!
Please re-test with the latest snapshot (20240129.162003-4
); I've made some adjustments.
Before testing, please make sure to remove the two configureBlocking
calls from your code.
@gamlerhart FYI, this could be relevant for you too, given your previous experiments. https://gamlor.info/posts-output/2019-10-15-java-file-descriptor-rant/en/
@kohlschuetter The new version works well. I removed configureBlocking
and the accept
method still block waiting for new connection.
@kohlschuetter Thanks for the notification. I've added a update note to the old blog post, for future visitor.
Fixed in 2.9.0, closing.
Describe the bug More tutorials on how to cast fd to socket. I got ClassCastException when casting. Are there any other restrictions?
To Reproduce Steps to reproduce the behavior: platform: Mac Arm MacOS 13.5.1 env: Java11 lib:
I‘m trying to transfer a tcp connection between two processes. To do this, I create a tcp socket in process1 and send the file descriptor of the tcp socket to process2. Then I try to rebuild the tcp socket in process2. I used
FileDescriptorCast.using(fd).as(Socket.class)
and it throws ClassCastException.I notice that there are only few global types are available for this fd, am I missing something? I follow the instruction here: https://kohlschutter.github.io/junixsocket/filedescriptors.html The available types I get: [class java.lang.Number, class java.io.OutputStream, interface java.lang.Comparable, class java.io.FileInputStream, interface java.nio.channels.Channel, interface java.nio.channels.InterruptibleChannel, interface java.io.Serializable, interface java.io.Closeable, interface java.io.Flushable, interface java.nio.channels.ScatteringByteChannel, class java.lang.Integer, class java.io.FileDescriptor, interface java.lang.AutoCloseable, class java.lang.ProcessBuilder$Redirect, interface java.nio.channels.GatheringByteChannel, interface java.nio.channels.ReadableByteChannel, class java.nio.channels.spi.AbstractInterruptibleChannel, class java.lang.Object, class java.nio.channels.FileChannel, interface java.nio.channels.ByteChannel, class java.io.InputStream, interface java.nio.channels.WritableByteChannel, class java.io.FileOutputStream, interface java.nio.channels.SeekableByteChannel]
Expected behavior FileDescriptorCast successfully cast the fd to socket.
Output/Screenshots When I called the
FileDescriptorCast.using(fd).as(Socket.class);
, I gotAny help would be appreciated!