How java.net.Socket threadsafe?

I have a Socket that I read and write using BufferedReaders and BufferedWriters. I am not sure what operations can be done from individual threads. I would suggest that writing to a socket from two different threads at the same time is a bad idea. Same thing while reading a socket from two different streams. How about reading in one thread while writing on another?

I ask because I want one thread to be blocked for a long time while reading, since it waits for more data, but during this wait I also have random data to send to the socket. I don't understand if this is thread safe, or if I have to cancel reading before I write (which will be annoying).

+7
source share
6 answers

You really read from InputStream and write to OutputStream. They are fairly independent, and as long as you serialize access to each of them, you're fine.

You must match, however, the data that you send with the data that you receive. This is different from thread safety.

+3
source

Sockets are unsafe threads at the thread level. You must provide synchronization. The only guarantee is that you will not receive copies of the same bytes in different read requests, regardless of concurrency.

But at the Reader level, and especially at Writer, you may have problems with.

In any case, you can handle read and write operations with Socket threads as if they were completely independent objects (they are the only ones they share with, their life cycle).

Once you have ensured the correct synchronization between the streams of readers, on the one hand, and the streams of letters, on the other hand, any number of readers and writers will be in order. This means that yes, you can read on one thread and write on another (actually very often), and you do not need to stop reading while writing.

One last tip: all thread operations are timeout related, make sure you handle timeouts correctly.

+5
source

Java java.net.Socket is actually not thread safe: open the Socket source and see the member field (let it be said) connected and how it is used. You will see that it is not volatile , reading and updating without syncing. This indicates that the Socket class is not intended to be used by multiple threads. Although, there are some locks and synchronization there, this is not consistent. `

I recommend not to do this. In the end, use buffers (nio) and make the socket read / write in a single thread

See v discussion for more details.

+1
source

You can have one stream reading a socket and another stream writing to it. You may want to write multiple streams to a socket, in which case you will have to serialize your access with synchronization, or you may have one stream of letters that receives data for writing from the queue. (I prefer the first)

You can use non-blocking IO and share the work of reading and writing in one thread. However, it is actually more complicated and difficult to do correctly. If you want to do this, I suggest you use a library that will help you, for example, Netty or Mina.

+1
source

Very interesting, the nio SocketChannel record is syncing

http://www.docjar.com/html/api/sun/nio/ch/SocketChannelImpl.java.html

The old io Socket stuff is OS-specific, so you will need to find out your own OS code in order to know exactly (and this may differ from OS to OS) ...

Just look at java.net.SocketOutputStream.java, which returns Socket.getOutputStream.

(unless, of course, I missed something).

oh, one more thing, they could put synchronization in their own code in every JVM on every OS, but who knows for sure. Only nio is obvious that there is synchronization.

0
source

This is how socketWrite is in native code, so it does not protect streams from code

 JNIEXPORT void JNICALL Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this, jobject fdObj, jbyteArray data, jint off, jint len) { char *bufP; char BUF[MAX_BUFFER_LEN]; int buflen; int fd; if (IS_NULL(fdObj)) { JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); return; } else { fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); /* Bug 4086704 - If the Socket associated with this file descriptor * was closed (sysCloseFD), the the file descriptor is set to -1. */ if (fd == -1) { JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); return; } } if (len <= MAX_BUFFER_LEN) { bufP = BUF; buflen = MAX_BUFFER_LEN; } else { buflen = min(MAX_HEAP_BUFFER_LEN, len); bufP = (char *)malloc((size_t)buflen); /* if heap exhausted resort to stack buffer */ if (bufP == NULL) { bufP = BUF; buflen = MAX_BUFFER_LEN; } } while(len > 0) { int loff = 0; int chunkLen = min(buflen, len); int llen = chunkLen; (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP); while(llen > 0) { int n = NET_Send(fd, bufP + loff, llen, 0); if (n > 0) { llen -= n; loff += n; continue; } if (n == JVM_IO_INTR) { JNU_ThrowByName(env, "java/io/InterruptedIOException", 0); } else { if (errno == ECONNRESET) { JNU_ThrowByName(env, "sun/net/ConnectionResetException", "Connection reset"); } else { NET_ThrowByNameWithLastError(env, "java/net/SocketException", "Write failed"); } } if (bufP != BUF) { free(bufP); } return; } len -= chunkLen; off += chunkLen; } if (bufP != BUF) { free(bufP); } } 
0
source

All Articles