-
Gigabit TCP Transfer
Hello,
I'm trying to achieve gigabit file transfer in c#. It is a speed test, so there is a packet of bytes, which is send out until the speed test is done.
Code:
while (!Stopped)
{
stream.Write(data, 0, 524288);
transferred += data.Length;
[...]
}
The point is that I'm reaching like 500 MBit/s, not at all gigabit. Let alone the CPU usage is extremely high (about 70%)
The question here is: How can I minimize the CPU usage and how can I achieve maximum data throughput?
-
Well you could add at the top of your while loop...
That should take care of your CPU usage issue, however, it won't help in aspiring for higher throughput rates.
-
Well, it would lower the CPU usage, but make the test results useless.. any other suggestions?
-
You could reduce the size of the packets you are sending so that you're not forcing the CPU to fragment the data before it is sent. The maximum TCP payload size for a packet is a little over 1400 bytes, so I would just send packets of 1400 to be sure.
Also, make sure you are including the TCP and Ethernet header data when you perform your calculations.
EDIT: Keep in mind that when you use TCP, there is the additional overhead of acknowledgements and resent packets that would not be present in your calculations.
-
Uisng 1400 bytes, it is far slower (say 5 MB/s). With 512 KB packets the speed is about 60 MB/s.
the more data I send, the faster it gets... Don't know why.
This is the other side, reading the packets:
Code:
private void ClientThread(TcpClient client)
{
try
{
NetworkStream stream = client.GetStream();
BinaryReader bin = new BinaryReader(stream);
byte[] buffer = new byte[bin.ReadInt32()]; // read the size of the packets
while (true)
{
stream.Read(buffer, 0, buffer.Length);
}
}
catch { }
}
And yes, I know that TCP has an overhead of about 20% ;)
-
Is the machine you're dumping all this data on just as fast as this one? It's all very well having a super highway, but if it ends in a dirt track, you're stuck all the same.
Bear in mind that TCP connections are reliable, so there is a certain amount of traffic to 'ack' the transmission, wait for packet retransmission, and buffering to limit the number of un-acked packets.
You would get higher throughput with UDP.
Further, the OS is unlikely to allow a single user land process to saturate the link, when it needs a certain amount of bandwidth for it's own use, and to satisfy Quality of service - Wikipedia, the free encyclopedia levels for other active links.
Do you have a firewall that scans all outbound traffic?
-
Both machines have about the same performance. The firewall doesn't seem to slow down anything (same speed when turned off).
I will try it with UDP now.
-
UDP isn't much faster, because of the datagram size. When I'm sending 1400 bytes or 10 KB via UDP, the speed is between 5 MB/s and 30 MB/s. When using TCP and 1400 bytes it is also 5 MB/s. But using TCP and 512 KB speeds up to 60 MB/s. It seems more like there is a problem with the packet size or the way I'm sending.
Here's the source: http://xload.dev-ch.de/f690bc45828e7...1.0.0b-src.zip
If you could look into it, I would be happy :)
Maybe you'll see the mistake I'm making right away.
-
Your best bet for responses is to actually post the relevant code here with code tags. If you aren't sure what parts of the code are in question, then either post the whole thing with tags or attach the actual files. Very few people are going to download a zip file from someone that do not know.
-
Ok, good point. So here is the source code of the most important parts:
This happens, when a client joins the server. Here, the data is read until the connection is closed.
Code:
private void ClientThread(TcpClient client)
{
try
{
NetworkStream stream = client.GetStream();
BinaryReader bin = new BinaryReader(stream);
byte[] buffer = new byte[bin.ReadInt32()];
while (true)
{
stream.Read(buffer, 0, buffer.Length);
}
}
catch { }
}
This is the connection code for a TCP client:
Code:
public TcpClient Connect(string ip)
{
try
{
TcpClient client = new TcpClient(ip, Port);
client.NoDelay = true;
return client;
}
catch
{
return null;
}
}
and this is the code, which sends tcp packets:
Code:
private void btnRun_Click(object sender, EventArgs e)
{
btnStop.Text = "Stop";
Stopped = false;
lblSpeed.Text = "0 Bytes/s";
lblSpeedBit.Text = "0 Bits/s";
netGauge.KBitsPerSecond = 0;
netGauge.Invalidate();
lblConnectionLost.Visible = false;
try
{
if (lstComputers.SelectedItems.Count == 1)
{
tabMain.SelectedIndex = 2;
btnNext.Visible = false;
btnRun.Visible = false;
btnStop.Visible = true;
lblConnectedTo.Text = lstComputers.SelectedItems[0].Text;
lblConnectedIP.Text = (string)lstComputers.SelectedItems[0].Tag;
TcpClient client = Analyzer.Connect(lblConnectedIP.Text);
NetworkStream stream = client.GetStream();
BinaryWriter bin = new BinaryWriter(stream);
int len = (int)edtPacketSize.Value;
bin.Write(len);
byte[] data = new byte[len];
if (chkRandomData.Checked)
{
RandomNumberGenerator.Create().GetBytes(data);
}
long transferred = 0, transferredthissecond = 0;
DateTime start = DateTime.Now, lastrefresh = DateTime.Now, lastmeasured = DateTime.Now;
while (!Stopped)
{
stream.Write(data, 0, data.Length);
transferred += data.Length;
transferredthissecond += data.Length;
if ((DateTime.Now - lastmeasured).TotalMilliseconds > 500)
{
lastmeasured = DateTime.Now;
transferredthissecond *= 2;
lblSpeed.Text = GetSizeName(transferredthissecond) + "/s";
lblSpeedBit.Text = GetBitSizeName(transferredthissecond) + "/s";
netGauge.KBitsPerSecond = (int)(transferredthissecond * 8 / 1000);
netGauge.Invalidate();
transferredthissecond = 0;
}
lblTransferred.Text = GetSizeName(transferred);
if ((DateTime.Now - lastrefresh).TotalMilliseconds > 25)
{
TimeSpan timespan = DateTime.Now - start;
lblTimeElapsed.Text = (timespan).ToString().PadRight(11).Substring(0, 11);
int avg = (int)(transferred / timespan.TotalSeconds);
lblAverageSpeed.Text = GetSizeName(avg) + "/s - " + GetBitSizeName(avg) + "/s";
Application.DoEvents();
lastrefresh = DateTime.Now;
}
}
client.Close();
}
}
catch
{
lblConnectionLost.Visible = true;
}
btnStop.Text = "<< First";
}
-
a standard 33MHz/32-bit PCI bus can only move about a gigabit per second of data, so unless you're using a 64-bit or 66MHz PCI or PCI-e bus, there's a good chance that your machine just doesn't have the bus bandwidth to push that kind of data, when everything else is also going on inside the machine. a lot of computers/motherboards are still made with the ethernet port connected to a PCI bus instead of a PCI-e bus, so this is a real possibility.
on another note, gigabit ethernet supports jumbo frames, up to (and maybe over) 16k. if both machines and your switch are set to support jumbo frames (9000 bytes is usually a good number for a few reasons) you may be able to get higher transfer rates, assuming you also have machines that can handle data at that rate.
-
The transfer rates are slow, when using such small packet sizes. For example 1400 bytes packet size slows the speed down to 5 MB/s. It seems to be some kind of coding issue...
Btw: you seem to have pretty well knowledge of TCP and networking :)