Skip to main content

Socket - Socket communication unbelievable slow

3 replies [Last post]
prontector
Offline
Joined: 2009-01-06

Hello,

I am trying to create a small network application using java.net.ServerSocket and java.net.Socket.
When I send and receive data it is very slow and CPU load goes to 100%. I don't get more than 20kbyte/s speed.

Example to test out:

<br />
import java.io.IOException;<br />
import java.net.ServerSocket;<br />
import java.net.Socket;</p>
<p>public class NetworkTest<br />
{<br />
	ServerSocket server = null;<br />
	Socket client_serverside = null;<br />
	Socket client_clientside = null;</p>
<p>	class ServerConnectionWaiter implements Runnable<br />
	{<br />
		@Override public void run()<br />
		{<br />
			try<br />
			{<br />
				client_serverside = server.accept();<br />
			}<br />
			catch (IOException e)<br />
			{<br />
				e.printStackTrace();<br />
			}<br />
		}<br />
	}</p>
<p>	class MessageSender implements Runnable<br />
	{<br />
		@Override public void run()<br />
		{<br />
			try<br />
			{<br />
				while(true)<br />
				{<br />
					client_clientside.getOutputStream().write(0);<br />
				}<br />
			}<br />
			catch (IOException e)<br />
			{<br />
				e.printStackTrace();<br />
			}<br />
		}<br />
	}</p>
<p>	class MessageReceiver implements Runnable<br />
	{<br />
		@Override public void run()<br />
		{<br />
			double starttime = System.currentTimeMillis();<br />
			double counter = 0;<br />
			try<br />
			{<br />
				while(true)<br />
				{<br />
					client_serverside.getInputStream().read();<br />
					counter++;<br />
					double time = System.currentTimeMillis()-starttime;<br />
					System.out.println("Read bytes/second: " + (counter/(time/1000d)));<br />
				}<br />
			}<br />
			catch (IOException e)<br />
			{<br />
				e.printStackTrace();<br />
			}<br />
		}<br />
	}</p>
<p>	public NetworkTest()<br />
	{<br />
		try<br />
		{<br />
			server = new ServerSocket(12345);<br />
			new Thread(new ServerConnectionWaiter()).start();<br />
			client_clientside = new Socket("localhost", 12345);</p>
<p>			while(client_serverside == null);	//wait</p>
<p>			System.out.println("Connected!");</p>
<p>			new Thread(new MessageReceiver()).start();<br />
			new Thread(new MessageSender()).start();</p>
<p>		}<br />
		catch (IOException e)<br />
		{<br />
			e.printStackTrace();<br />
		}<br />
	}</p>
<p>	public static void main(String[] args)<br />
	{<br />
		new NetworkTest();<br />
	}</p>
<p>}<br />

With this example my data throughput is around 18kbyte/s, with peaks at 20kbyte/s. Console output:

<br />
Read bytes/second: 18792.828685258963<br />
Read bytes/second: 18792.994687915005<br />
Read bytes/second: 18793.16069057105<br />
Read bytes/second: 18793.326693227093<br />
Read bytes/second: 18793.492695883135<br />
Read bytes/second: 18790.539419087138<br />

How can I enhance speed and performance? My computer easily supports gigabit, so at least I expect something around 100mbyte/s?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
linuxhippy
Offline
Joined: 2004-01-07

Hi,

yes, there are a few problems in your code...

> client_serverside = server.accept();
1.) you set client_serverside in one thread and use it in another one.
Probably wont cause you any problems, but not always guaranteed to work.

> while(true)
> {
> client_clientside.getOutputStream().write(0);
> }
2.)
This means you generate a new OutputStream for every single byte you write.
Furthermore the stream is not buffered, causing a downcall into kernel-code for every written byte.

Better would be:
BufferedOutputStream bof = new BufferedOutputStream(client_clientside.getOutputStream());
while(true) {
bof.write(0);
}

3.) The same is true for the input stream. Generate a BufferedInputStream outside the loop, and just call read() on it in the loop.
Btw. have a look at the array-reading/writing methods, they usually tend to be even faster.

I would be interested in your findings, good luck!
You should be able to get at least to a few hundred mb/s if your're running client and server over the same machine.

- Clemens

prontector
Offline
Joined: 2009-01-06

Thank you both for your quick responses. It helped a lot.

I enhanced the example application based on your suggestions and got this:

[code]
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class NetworkTest
{
ServerSocket server = null;
Socket client_serverside = null;
Socket client_clientside = null;

class ServerConnectionWaiter implements Runnable
{
@Override public void run()
{
try
{
client_serverside = server.accept();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

class MessageSender implements Runnable
{
@Override public void run()
{
try
{
byte[] array = new byte[1024*1024];
BufferedOutputStream bout = new BufferedOutputStream(client_clientside.getOutputStream());
while(true)
{
bout.write(array);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

class MessageReceiver implements Runnable
{
@Override public void run()
{
double starttime = System.currentTimeMillis();
double counter = 0;
try
{
BufferedInputStream bin = new BufferedInputStream(client_serverside.getInputStream());
while(true)
{
int available = bin.available();
int read = bin.read(new byte[available]);
counter+=read;
double time = System.currentTimeMillis()-starttime;
double bytes_per_second = (counter/(time/1000d));
String additional = "";
if (bytes_per_second > 1024d)
{
additional = "k";
bytes_per_second = bytes_per_second / 1024d;
}
if (bytes_per_second > 1024d)
{
additional = "m";
bytes_per_second = bytes_per_second / 1024d;
}
System.out.println("Read " + (int)bytes_per_second + " " + additional + "bytes/second!");
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

public NetworkTest()
{
try
{
server = new ServerSocket(12345);
new Thread(new ServerConnectionWaiter()).start();
client_clientside = new Socket("localhost", 12345);

while(client_serverside == null); //wait

System.out.println("Connected!");

new Thread(new MessageReceiver()).start();
new Thread(new MessageSender()).start();

}
catch (IOException e)
{
e.printStackTrace();
}
}

public static void main(String[] args)
{
new NetworkTest();
}

}
[/code]

Console output:
[code]
Read 73 mbytes/second!
Read 73 mbytes/second!
Read 73 mbytes/second!
Read 73 mbytes/second!
Read 72 mbytes/second!
Read 72 mbytes/second!
[/code]

As for the thread: That shouldn't be a problem, I can access data from any thread I want as long as I don't write to it from two threads simultaneously.

Thanks again, you both helped me alot!

peter__lawrey
Offline
Joined: 2005-11-01

You testing the number of reads/write per second your system can do, not the bandwidth. Somewhere between 20K and 60K unbuffered/batched read/writes per second sounds about right for Java.

Sending one byte at a time is the slowest way to send data, so you should not expect to break any speed records.

Try sending blocks of 16KB i.e. new byte[16*1024] and see what transfer rate you get then.
BTW: Remember to look at at the return value for read() to see the number of bytes actually read.