PrintWriter very slow flush() and print(). Multithreads and sockets - java

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.

Related

Lost messages in Multi-thread writting to Socket Outputstream

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

Checking if there is an incoming socket

Im creating a server for my game but this question is more java related. So i want to check of their is an incomming socket but i still want to run the game becouse the server is hosted by an user and not seperate by an external program. But still i want to check if someone is connection using an socket. What i now have is:
public void updateConnection() throws IOException {
Socket connection = server.accept();
System.out.println("Ape is connecting");
ServerClient client = new ServerClient(connection);
clientsWaiting.add(client);
}
I want this method to be used every frame and not continuously checking if thats posible. If it isn't posible what else shall i use to create my server and check if some ones connecting each frame.
You're best bet would be to have your game check for incoming socket connections in a separate thread. You could create a Runnable that just listens for connections continuously.
When you check for an incoming connection: Socket connection = server.accept();, what is actually happening is you are placing a block on that particular thread until you receive a connection. This will cause your code to stop executing. The only way around this is parallelization. You can handle all of your networking tasks on one thread, whilst handling your gaming logic and rendering on another.
Be aware though, writing code to be run on multiple threads has many pit falls. Java provides some tools to minimize the potential problems, but it is up to you, the programmer, to ensure that your code will be thread safe. Going into detail about the many concerns regarding parallel programming is beyond the scope of this question. I suggest that you do a bit of research on it, because bugs that arise from this type of programming are sometimes hard to reproduce and to track.
Now that I have given you this disclaimer, to use Runnable to accomplish what you are trying to do, you could do something similar to this:
Runnable networkListener = () -> {
//declare and instantiate server here
while(true){
Socket connection = server.accept();
//whatever you would like to do with the connection would go here
}
}
Thread networkThread = new Thread(networkListener);
networkThread.start();
You would place that before your game loop and it would spawn a thread that would listen for connections without interrupting your game. There are a lot of good idioms out there on how to handle Sockets using ThreadPools to track them, spawning a new Thread each time a new connection is made, so I suggest you do some research on that as well.
Good luck to you, this isn't an easy road you are about to venture down.
One more addition: when you establish TCP connection you are not dealing with frames(UDP is frame based protocol), you are dealing with stream of bytes.
The lower lever Byteoutpustream example:
InputStream inputStream = socket.getInputStream();
// read from the stream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] content = new byte[ 2048 ];
int bytesRead = -1;
while( ( bytesRead = inputStream.read( content ) ) != -1 ) {
baos.write( content, 0, bytesRead );
} // while
So when client finishes writing, but stream is still open, your read method blocks. If you expect certain data from client, you read it and then call your print method or however you want to notify, etc...

Trying to fill buffer while buffer is written to the channel

I'm trying to make a simple network client. The client should be able to write into a queue (buffer) and a second thread should take this buffer and write it to the server.
I tried it with java.nio and created a Thread with a static ByteBuffer. This ByteBuffer is being used in the while(true) of the Thread for writing into the channel.
In my main loop at some point I'm putting some Bytes into the static buffer via the put() Method.
In the debug mode I suspended the channel-writing-thread and then I filled the buffer via my main program loop (just pushed 'A' to write into the buffer).
After three or four button pushes I started the channel-writing-thread again and it worked just fine.
But when I try the program just normal I'm getting a buffer overflow error in the main-loop-thread. I believe my program is trying to put data into the buffer while the buffer is accessed by my channel-writing-thread. I tried to use the synchronized keyword around both parts in both threads, but that didn't help.
Main loop:
[...]
if(Gdx.app.getInput().isKeyPressed(Input.Keys.A) && (now.getTime() - lastPush.getTime()) > 1000 )
{
lastPush = now;
//synchronized (PacketReader.writeBuffer)
//{
PacketReader.writeBuffer.put(("KeKe").getBytes());
//}
}
[...]
My Thread named "PacketReader" (well it's actually reading and writing):
class PacketReader implements Runnable
{
public static ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
[...]
public void run()
{
while (true) {
[...]
if (selKey.isValid() && selKey.isWritable())
{
SocketChannel sChannel = (SocketChannel)selKey.channel();
//synchronized (PacketReader.writeBuffer)
//{
if(PacketReader.writeBuffer.hasRemaining())
{
PacketReader.writeBuffer.flip();
int numBytesWritten = sChannel.write(PacketReader.writeBuffer);
PacketReader.writeBuffer.flip();
}
//}
}
[...]
Any idea how to create such a buffered write system? I think it's a common problem, but I don't know what to search. All NIO tutorials seem to think that the buffer is filled within the channel loop.
In the end I'm trying to have a program, which has the network component started once and within my program I just wanted to use some static send method to send packets without thinking about the queue handling or waiting for the queue.
Is there maybe somewhere a tutorial? Most games should use a similar concept, but I couldn't find any opensource simple java games with a NIO implementation (I'll use it for android so I'm trying it without a framework)
You might try keeping a queue (say, ConcurrentLinkedQueue) of buffers to write, instead of putting into the same buffer you are sending out to the channel.
To enqueue something to be sent:
ByteBuffer buff = /* get buffer to write in */;
buff.put("KeKe".getBytes());
queue.add(buff);
Then in your select loop, when the channel is writable:
for(ByteBuffer buff = queue.poll(); buff != null; buff = queue.poll()) {
sChannel.write(buff);
/* maybe recycle buff */
}
You may also need to set/remove write interest on the channel depending on whether the queue is empty or not.
Not a direct answer to your question, but you should consider using an existing NIO framework to make this easier. Netty and Grizzly are popular examples. I would personnally use Netty instead of writing my own server from scratch using NIO.
You could probably also look at how Netty handles reading / writing to the buffers since I assume that they have optimized their implementation.
The whole point of NIO is that you don't need separate threads. The thread doing the filling should also do the writing.

How to reliably tell when finished reading from a socket in Java?

We are integrating with an external product that requires us to communicate with it using Java sockets. We've been able to read small responses from the server with no issues, but larger responses are causing some headaches.
I made some changes to the socket handling logic and now we seem to be able to read large responses 90% of the time. It does still fail occasionally. Failure, in this case, means that the Java client stops reading from the socket before the entire response has been read. The client thinks that the read operation is finished, and stops normally - there are no exceptions or timeouts involved.
Here's what the current logic looks like:
StringWriter response = new StringWriter();
PrintWriter writer = new PrintWriter(response);
char[] buf = new char[4096];
int readChars;
do {
readChars = responseBufferedReader.read(buf);
writer.write(buf, 0, readChars);
} while(readChars != -1 && responseBufferedReader.ready());
responseBufferedReader is a BufferedReader wrapped around an InputStreamReader wrapped around the Socket's InputStream.
This code works most of the time, but it seems like checking for readChars != -1 and ready() are not reliable enough to indicate if we've read all of the content from the server. Comparing the number of read characters to the buffer size is also not reliable, since the server seems to be a little slow at sending the response back causing these numbers to differ.
I've tried changing the size of the character buffer; it helped, but it's still not working 100% of the time.
Is there a better and more reliable way to read entirely from a Socket without knowing the size of the expected response? I've been doing some research on SocketChannels, but I'm not sure if there's any benefit to be had by switching.
In case it helps, we're making a single, blocking Socket connection to the server. The Socket is configured for a 100 second timeout
You shouldn't be checking whether the BufferedReader is ready() to tell if you're done. It's possible that bytes are still being read off of the wire and the BufferedReader has nothing for you, but the Socket is not yet closed.
I'm not sure what value the BufferedReader is getting you (well, it might help your performance). I would expect the following to work better:
StringWriter response = new StringWriter();
PrintWriter writer = new PrintWriter(response);
char[] buf = new char[4096];
int readChars;
do {
readChars = inputStreamReader.read(buf);
writer.write(buf, 0, readChars);
} while(readChars != -1);
I think that you're probably dropping out of the loop when the network is the bottleneck - the loop processes the results fast enough so that the Reader isn't ready yet and you assume that you're done reading (even though you're not).
See the answers to the question at Java blocking socket returning incomplete ByteBuffer
If the network breaks the message into packets, you will drop out of your loop before reading all packets.
See my answer to this question. The same answer applies whenever you are reading from a stream, and the only reliable way to know when you're done if EOF doesn't apply (as in this case) is to encode the end-of-message in the protocol somehow -- how you do it is up to you.
Edit:
If you can't modify the protocol to include message boundaries, you might investigate a timeout-based approach. You have to decide how long to wait before detecting the end of a message... but then you have to handle the case where you get two messages in the same stream. Can your code handle this situation now? If so, then your answer is to buffer the input and use that logic to detect record boundaries.

How to read and write network sockets in Java ME on a device with simplex connectivity?

I am working on a mobile communicator and after establishing connection to the server using following method (to illustrate that I am using StreamConnection, InputStream and OutputStream) I distribute inputStream and outputStream between two separate threads, lets call them Sender and Receiver.
Connection method:
private InputStream inputStream;
private OutputStream outputStream;
private StreamConnection connection;
public void connect(String host, String port) throws IOException {
String connectionString = "socket://" + host + ":" + port;
connection = (StreamConnection) Connector.open(connectionString);
inputStream = connection.openDataInputStream();
outputStream = connection.openOutputStream();
}
Sender thread is waiting for anything to appear in the out buffer. When output buffer is empty, Sender waits (by calling wait() method on sender thread). Any input into the output buffer calls notify() method on the sending thread.
Receiver thread polls the InputStream using int available() method and when there is something to receive, it calls blocking int read() method. Everything works like a charm in various emulators and few devicdes I have handy around.
However there is one phone that seems to missbehave. Whenever one thread calls available() or read() on InputThread object, while the other thread calls write() on the OutputStream object, the Input stream finishes. All subsequent reads will return value -1, which means that the InputStream got closed.
After massive google-fu, I came accross this post on nokia forums, where simplex/duplex properties of a device are being discussed and that seems to be the case with the device I have troubles with. Normally (99% of the time) calls to read() and write() can be simultaneous without any problems.
My question is then: Did anybody came accross similar problems? How did/would you sort out the issue of one thread independently reading, while another is independently writing into the established connection, so that they do not call read() or available() while calling write()?
Any pointers in any directions greatly appreciated!
Normally, very little is guaranteed when we talk about multi-threaded applications. I would recommend to use a single thread in your application and try to manage it using a single worker. Some devices do have behavioral problems and so what we see on one device does not appear to work on some other device.
I have worked a lot with mobile games where a lot of animation has to be rendered without compromising the speed of the game. I have realized that you can do more with a single thread and it makes your application very portable (with almost no changes).
If you are waiting for the threads to complete either READ or WRITE operation, so it looks like you are actually doing this sequentially. So more or less, things would be complicated with more than one thread. Instead, built a wait-notify mechanism, based on some predetermined factor and allow the SINGLE thread to either read or write to the socket stream. Switching between threads is a very costly operation, than this scheme.
Hope this answers your question.
Between that kind of problem and mobile network operators filterning data, most mobile java developers use the "http://" protocol instead of "socket://".
Of course, that means not using duplex connection anymore and making many GET and POST requests instead.
Far from ideal, I know.

Categories

Resources