I'm trying to write at least 5 messages in the same java socket outputstream, from two different Threads, almost instantaneously.
But to simplify let's say I have two threads writting to the same socket outputstream.
When I write them with more than 1 second interval, I get both messages in the other end, but if I send them below 1 second interval, the first one seems to be overriden(i guess), and only the second one gets the other end.
My writes are performed within a syncronized block:
this.sock =new Socket(InetAddress.getByName(hstName), hstPort);
this.os = this.sock.getOutputStream();
synchronized(this.os) {
this.os.write(buffer, ofset, blen);
this.os.flush();
}
Anyone knows why my first message is obliterated, whether this is supposed or not, and how can go around this issue.
Notice I can't change the code responsible for receiving the messages. I own the code to send the messages only.
Thanks in advance
Related
I'm new to working with Socket and have perhaps painted myself into a corner with a spurious design. I think I'd like to find a way to purge or flush the contents of a line decorating a Socket's InputStream. But maybe I've set things up incorrectly?
The Socket is tasked with repeatedly running the following cycle, on demand, on a background thread. A Runnable is instantiated that does the following tasks, then completes:
Send a message to server
Listen for an "ACK"
Wait for response from server
Read and "log" response
Send "ACK"
The runnable holds a class variable that is responsible for reading messages from the ServerSocket. inLine is instantiated in a separate method which is used to establish the connection.
inLine = new BufferedReader(new InputStreamReader(socket.getInputStream()));
My issue is that I am trying to figure out how to handle a test case scenario where the SocketServer sends an "extraneous" message during the interval when the client is dormant. On the next iteration of the cycle, this "extra" message is in the cue ahead of the expected "ACK" in step 2.
I was thinking I would remove any pending messages from the inLine variable prior to launching the runnable. But I don't see any means to do this. There are no flush or clear methods on BufferedReader or InputStreamReader. Nor are there any methods that I can find which allow one to inspect if there are any messages in the queue, along the lines of an iterator's hasNext() method.
Is there something I am missing?
Should I just declare and instantiate the inLine anew with each cycle? I was hesitating to do this because I don't know how expensive it is to continually repeat this operation. (As I said, I'm new to working with Socket-based communications.)
Would something like the following at the top of the cycle be considered ugly, or reasonable?
// clear out any messages sent during dormant time
socket.setSoTimeout(10); // arbitrary, very short timeout
while (true) {
try {
in.readLine();
} catch (SocketTimeoutException ex) {
break;
}
}
EDIT: There are wonderful folks at StackOverflow who I know are doing their best to keep questions in conformance with site standards. If you have a suggestion to help me improve the question, it would be appreciated. Should a question like this perhaps be better posted at "Code Review" now that I have added a plausible routine for clearing the input line?
Suppose that i have a class ServerReader which is a Thread that runs all the time. the ServerReader have a loop that reads all the messages from all client in a way like this:
while(true) {
for(Socket socket: sockets_arraylist) {
ObjectInputStream object_stream = new ObjectInputStream(socket.getInputStream());
String str = (String) object_stream.readObject();
System.out.println("message from client: " + str);
object_stream.close();
}
}
As i understand, when the loop encounter readObject() method, the Thread is going to sleep until the client actually sending an object.
So imagine this scenerio:
the ArrayList "sockets_arraylist" contains 2 sockets. The second socket on the list, which belongs to client number 2 waiting to recieve a message. Client number 2 sending this message and wait for the server to read it. But there is a problem: the loop above stuck at readObject() method that waits for the message from client 1. so until client 1 will not send his message to the server, client`s 2 message will not be read.
Do i need to make on the server a separete thread for each client? or there is another solution?
There are two solutions:
1) Use a separate thread for each client.
2) Use asynchronous IO using java.nio - in this case you'd probably want SocketChannel.
Using a separate thread for each client is likely to be conceptually simpler, although it does mean you need to consider race conditions more carefully. Using NIO may be more scalable (different benchmarks show different results, and it may well depend on your OS as well, in terms of how costly threads and scheduling are.)
I am running 2 threads in my applciation. One to check for incoming packets and one to process and send packets. They both do it on the SAME STREAM.
Example for 1:
while (connection open) {
in.readObject() instanceof ...
}
Example for 2:
while (connection open) {
processPacket(in)
}
I'm pretty sure EOFException is when the threads try and use the stream at the same time. It's not a constant EOF but only like every 1 second I get an EOF the rest works fine. So that's why I suspect that they overlap and try to use the stream at the same time.
If that is the problem, anyone know how do I synchronize them to do it after another while still keeping the current update speed and using two threads?
I need two threads because the check for incoming waits in a line until a packet gets recived and I need the server to constantly send process and check for packets.
How do I fix the EOFException?
If your getting an EOFException, it typically means the other side hung up. You usually get these on the read side.
Here's a similar SO question
Edit 1: The question is really why is the socket closed. It can be for any number of reasons, a programmable timer on the server side checking for no data within X minutes, a firewall closing the connection, a network interruption, etc..
Both threads shouldn't be reading the same Stream.
You should read the objects and put them in a ConcurrentLinkedQueue, then from the second thread you can check the queue for objects ready to process.
EOFException is 'normal'. It happens on one thread too. Your architecture of reading in two threads simultaneously cannot possibly work, but it isn't the cause of this problem. The cause is that the peer closed the connection. This is going to happen. Unless your application protocol contains message counts or a close notify or some other means of predicting EOS, it is going to get EOFExceptions, or readLine() returning null, or read() returning -1, depending which read methods you are calling.
I have this weird problem with my (multithreaded) server when I get more than 500 players connected simultaneously, the PrinterWriter take more than 100 seconds or more (2 minutes) to finish flush() or print() sometimes.
Here is the code:
public static void send(Player p, String packet)
{
PrintWriter out = p.get_out();
if(out != null && !packet.equals("") && !packet.equals(""+(char)0x00))
{
packet = Crypter.toUtf(packet);
out.print((packet)+(char)0x00);
out.flush();
}
}
the printWriter is something like this:
_in = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
_out = new PrintWriter(_socket.getOutputStream());
If I add the keyword synchronized to the send() method, the whole server starts to lag every 2 seconds, if I don't then some random player starts to lag for no reason.
Anyone have any idea ? Where is this coming from? What should I do?
The print writer is wrapped around a socket's output stream, so I'm going to guess and say that the socket's output buffer is full, and so the write/flush call will block until the buffer has enough room to accommodate the message being sent.
The socket send buffer may become full if data is being written to it faster than it can be transmitted to the client (or faster than the client can receive it).
Edit:
P.S. If you're having scalability problems, it may be due to using java.io (which requires one thread per socket) instead of java.nio (in which case a single thread can detect and perform operations on those sockets which have pending data). nio is intended to support applications which must scale to a large number of connections, but the programming model is more difficult.
The reason is that your send() method is static, so all threads that write to any socket are being syncrhonized on the containing class object. Make it non-static, then only threads that are writing to the same socket will be synchronized.
I am using Java NIO's SocketChannel to write : int n = socketChannel.write(byteBuffer); Most of the times the data is sent in one or two parts; i.e. if the data could not be sent in one attemmpt, remaining data is retried.
The issue here is, sometimes, the data is not being sent completely in one attempt, rest of the data when tried to send multiple times, it occurs that even after trying several times, not a single character is being written to channel, finally after some time the remaning data is sent. This data may not be large, could be approx 2000 characters.
What could be the cause of such behaviour? Could external factors such as RAM, OS, etc cause the hindarance?
Please help me solve this issue. If any other information is required please let me know.
Thanks
EDIT:
Is there a way in NIO SocketChannel, to check, if the channel could be provided with data to write before actual writing. The intention here is, after attempting to write complete data, if some data hasn't been written on channel, before writing the remaining data can we check if the SocketChannel can take any more data; so instead of attempting multiple times fruitlessly, the thread responsible for writing this data could wait or do something else.
TCP/IP is a streaming protocol. There is no guarantee anywhere at any level that the data you send won't be broken up into single-byte segments, or anything in between that and a single segment as you wrote it.
Your expectations are misplaced.
Re your EDIT, write() will return zero when the socket send buffer fills. When you get that, register the channel for OP_WRITE and stop the write loop. When you get OP_WRITE, deregister it (very important) and continue writing. If write() returns zero again, repeat.
While using TCP, we can write over sender side socket channel only until the socket buffers are filled up and not after that. So, in case the receiver is slow in consuming the data, sender side socket buffers fill up and as you mentioned, write() might return zero.
In any case, when there is some data to be sent on the sender side, we should register the SocketChannel with the selector with OP_WRITE as the interested operation and when selector returns the SelectionKey, check key.isWritable() and try writing on that channel. As mentioned by Nilesh above, don't forget to unregister the OP_WRITE bit with the selector after writing the complete data.