C# TCP socket high network usage - c#

I have the following code that sends eight images per second to a connected TCP client:
static void HandleServer()
{
Console.WriteLine("Server is starting...");
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket newsock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(ipep);
newsock.Listen(10);
Console.WriteLine("Waiting for a client...");
Socket client = newsock.Accept();
IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}",
newclient.Address, newclient.Port);
HandleImage(client, newsock);
}
private static void HandleImage(Socket client, Socket s)
{
int sent;
int imageCount = 0;
double totalSize = 0;
try
{
while (true)
{
Image bmp = getImage();
MemoryStream ms = new MemoryStream();
// Save to memory using the bmp format
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();
bmp.Dispose();
ms.Close();
sent = SendVarData(client, bmpBytes);
imageCount++;
totalSize += sent;
Console.WriteLine("Sent " + sent + " bytes");
Thread.Sleep(125);
}
}
catch (Exception e)
{
Console.WriteLine("Exception catched, probably an interrupted connection. Restarting server...");
s.Close();
Console.WriteLine("Transferred {0} images with a total size of {1}", imageCount, totalSize);
Console.WriteLine("Average JPEG size: " + totalSize / imageCount + " byte");
HandleServer();
}
}
private static int SendVarData(Socket s, byte[] data)
{
int total = 0;
int size = data.Length;
int dataleft = size;
int sent;
byte[] datasize = new byte[4];
datasize = BitConverter.GetBytes(size);
sent = s.Send(datasize);
while (total < size)
{
sent = s.Send(data, total, dataleft, SocketFlags.None);
total += sent;
dataleft -= sent;
}
return total;
}
}
}
Each image has an average size of 0.046 megabyte, which brought me to a calculated network bandwith of 0.37 megabyte per second for eight images per second.
I monitored the applicaton in the Windows 10 task manager and saw, that the network usage goes up to 35-40 Mbps after two to three seconds.
Could this be in context with my source code?
Thanks a lot

Related

Sending and receiving files keeps hanging

my program should be able to send and receive files but for some reason whenever i click on the send (button1) and receive (button2) buttons, it keeps hanging. Not sure if its something wrong my my codes? Also, I feel like my codes are pretty long as compared to other examples i found online but I'm not sure how to rectify.
Client codes
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9000);
private void Form1_Load(object sender, EventArgs e)
{
try
{
socket.Connect(remoteEP);
textBox2.Text = "Connected to Server";
}
catch (Exception ex)
{
textBox2.Text = "Unable to connect to Server";
textBox2.Text = ex.Message;
}
}
public const string SEND = "[SEND]";
public const string RECEIVE = "[RECEIVE]";
public const string QUIT = "[QUIT]";
private void button1_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox2.Clear();
NetworkStream stream = new NetworkStream(socket);
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(stream);
try
{
writer.WriteLine(RECEIVE);
writer.Flush();
writer.WriteLine(textBox1.Text);
writer.Flush();
Bitmap bmp = new Bitmap(#"C:\Users\Y400\Desktop\Lectures\Year 3\WAD\Week 11" + textBox1.Text);
MemoryStream ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] bmpBytes = ms.GetBuffer();
bmp.Dispose();
ms.Close();
int sent;
sent = sendData(socket, bmpBytes);
textBox1.Text = "Transferring file complete\r\n";
textBox1.Text += bmpBytes.Length + " bytes sent to Server.";
}
catch (Exception ex)
{
textBox2.Text = ex.Message;
}
}
public static int sendData (Socket s, byte[] data)
{
int total = 0;
int size = data.Length;
int left = size;
int sent;
byte[] datasize = new byte[4];
datasize = BitConverter.GetBytes(size);
sent = s.Send(datasize);
while(total<size)
{
sent = s.Send(data, total, left, SocketFlags.None);
total += sent;
left -= sent;
}
return total;
}
private void button2_Click(object sender, EventArgs e)
{
textBox2.Clear();
textBox1.Clear();
byte[] data = new byte[1024];
string fileN = textBox2.Text.Trim();
NetworkStream ns = new NetworkStream(socket);
StreamReader reader = new StreamReader(ns);
StreamWriter writer = new StreamWriter(ns);
writer.WriteLine(SEND);
writer.Flush();
writer.WriteLine(fileN);
writer.Flush();
try
{
while (true)
{
data = receiveData(socket);
MemoryStream ms = new MemoryStream(data);
break;
}
textBox2.Text = ("Receiving file from server ...\r\n" + data.Length + " bytes copied");
}
catch (Exception ex)
{
textBox2.Text = ex.Message;
}
}
public static byte[] receiveData (Socket s)
{
int total = 0;
int recv;
byte[] datasize = new byte[4];
recv = s.Receive(datasize, 0, 4, 0);
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;
byte[] data = new byte[size];
while (total < size)
{
recv = s.Receive(data, total, dataleft, 0);
if (recv == 0)
{
break;
}
total += recv;
dataleft -= recv;
}
return data;
}
private void button3_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox2.Clear();
textBox2.Text = "Connection closed";
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
Server codes
class Program
{
public const string SEND = "[SEND]";
public const string RECV = "[RECV]";
public const string QUIT = "[QUIT]";
static void Main(string[] args)
{
runServer();
}
static void runServer()
{
try
{
byte[] data = new byte[1024];
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 9000);
server.Bind(localEP);
server.Listen(10);
Console.WriteLine("Waiting for Client ...");
Socket client = server.Accept();
Console.WriteLine("Client connected");
NetworkStream stream = new NetworkStream(client);
StreamReader reader = new StreamReader(stream);
StreamWriter writer = new StreamWriter(stream);
try
{
while(true)
{
string request = reader.ReadLine();
string filename = reader.ReadLine();
if (request == QUIT)
{
Console.WriteLine("Client disconnected");
break;
}
else if (request == SEND)
{
getFileFromClient(filename, client);
}
else if (request == RECV)
{
receiveFileFromClient(filename, client);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void getFileFromClient(string filename, Socket client)
{
try
{
FileStream output = File.OpenWrite(filename);
Console.WriteLine(filename + " created");
int count = 0;
while(true)
{
byte[] data = new byte[1024];
int size = client.Receive(data);
output.Write(data, 0, size);
count += size;
if(size<1024)
{
break;
}
}
output.Close();
Console.WriteLine(count + " bytes read from client");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void receiveFileFromClient(string filename, Socket client)
{
int count = 0;
FileStream input = File.OpenRead(filename);
Console.WriteLine("Reading " + filename);
while(true)
{
byte[] data = new byte[1024];
int bytesRead = input.Read(data, 0, 1024);
client.Send(data, bytesRead, SocketFlags.None);
count += bytesRead;
if(bytesRead < 1024)
{
break;
}
}
Console.WriteLine("Transferring file completed\r\n" + count + " bytes sent to Client");
input.Close();
}
}
Generally speaking
...try to approach the problem differently.
You can't just copy paste stuff from the Internet and hope for the best. You need to understand what you're doing thoroughly.
Regarding your exact problem
Take a look at the button2_Click method.
It contains a while loop which apparently never finishes.
while (true)
{
data = receiveData(socket);
MemoryStream ms = new MemoryStream(data);
break;
}
It does finish because of the break command. But this is all very hard to read.
When you copy paste code around and then apply quick fixes you end up with a pile of code which is very hard to debug.
It took me about 10 minutes to notice the fact that the client defines it's "message verbs" like so:
public const string SEND = "[SEND]";
public const string RECEIVE = "[RECEIVE]";
public const string QUIT = "[QUIT]";
while the server defines them like so:
public const string SEND = "[SEND]";
public const string RECV = "[RECV]";
public const string QUIT = "[QUIT]";
This is maybe not the only problem, but it is sufficient to create a deadlock,
because the server never executes the positive branch of this if statement:
else if (request == RECV)
{
receiveFileFromClient(filename, client);
}
so the client believes it is about to receive something, which proves to be false.
Also make sure you send the "SEND" and "RECEIVE" message verbs when you should and not mix them up.
Good luck!
PS: I would suggest you take a look at more simpler to use techniques for sending and receiving data, such as:
WCF
ASP.NET Web Services
Web API
Ignoring any logic errors that may occur in your programs, the way you are handling things in your client whenever it is doing an action it is doing it on the GUI thread. This will make your application seem like it is locking but instead it is executing your logic on the GUI thread.
The same problem is occurring on the server. It accepts a connection, and then goes on to receive the file. It will not be able to receive any other connection until it finished receiving the file.
The server is not without problems either because it is never checking if it receives 0 bytes from the socket. Which means that the client closed its end of the connection. You are simply assuming that if you receive less than 1024 you are receiving your last part of the file. This is simply not true for TCP. You only know you received the last part if you receive 0 bytes. TCP is a byte streaming protocol you cannot assume you will be receiving blocks of 1024 bytes. It is likely that this will be in fact the case, but you should not code it like that. Check for reception of 0 bytes. On the client you did check for 0 bytes, I am puzzled why you did not do the same on the server. The problematic part is this :
byte[] data = new byte[1024];
int size = client.Receive(data);
output.Write(data, 0, size);
count += size;
if(size<1024) //you can only break if the size is 0
{
break;
}
There are probably more bugs. As the other answer also indicated some other issues.

How to write data to buffer before writing on to disk in C#

In C++ it is possible to write buffered i/o using setvbuf. how to achieve the same in C#. Is there any method available to write buffered i/o in C#
As already commented there is a BufferedStream class
Adds a buffering layer to read and write operations on another stream. This class cannot be inherited.
Example code from MSDN:
Server side:
// This is a Windows Sockets 2 error code.
const int WSAETIMEDOUT = 10060;
Socket serverSocket;
int bytesReceived, totalReceived = 0;
byte[] receivedData = new byte[2000000];
// Create random data to send to the client.
byte[] dataToSend = new byte[2000000];
new Random().NextBytes(dataToSend);
IPAddress ipAddress =
Dns.Resolve(Dns.GetHostName()).AddressList[0];
IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, 1800);
// Create a socket and listen for incoming connections.
using(Socket listenSocket = new Socket(
AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp))
{
listenSocket.Bind(ipEndpoint);
listenSocket.Listen(1);
// Accept a connection and create a socket to handle it.
serverSocket = listenSocket.Accept();
Console.WriteLine("Server is connected.\n");
}
try
{
// Send data to the client.
Console.Write("Sending data ... ");
int bytesSent = serverSocket.Send(
dataToSend, 0, dataToSend.Length, SocketFlags.None);
Console.WriteLine("{0} bytes sent.\n",
bytesSent.ToString());
// Set the timeout for receiving data to 2 seconds.
serverSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, 2000);
// Receive data from the client.
Console.Write("Receiving data ... ");
try
{
do
{
bytesReceived = serverSocket.Receive(receivedData,
0, receivedData.Length, SocketFlags.None);
totalReceived += bytesReceived;
}
while(bytesReceived != 0);
}
catch(SocketException e)
{
if(e.ErrorCode == WSAETIMEDOUT)
{
// Data was not received within the given time.
// Assume that the transmission has ended.
}
else
{
Console.WriteLine("{0}: {1}\n",
e.GetType().Name, e.Message);
}
}
finally
{
Console.WriteLine("{0} bytes received.\n",
totalReceived.ToString());
}
}
finally
{
serverSocket.Shutdown(SocketShutdown.Both);
Console.WriteLine("Connection shut down.");
serverSocket.Close();
}
}
Client side:
public class Client
{
const int dataArraySize = 100;
const int streamBufferSize = 1000;
const int numberOfLoops = 10000;
static void Main(string[] args)
{
// Check that an argument was specified when the
// program was invoked.
if(args.Length == 0)
{
Console.WriteLine("Error: The name of the host computer" +
" must be specified when the program is invoked.");
return;
}
string remoteName = args[0];
// Create the underlying socket and connect to the server.
Socket clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(new IPEndPoint(
Dns.Resolve(remoteName).AddressList[0], 1800));
Console.WriteLine("Client is connected.\n");
// Create a NetworkStream that owns clientSocket and
// then create a BufferedStream on top of the NetworkStream.
// Both streams are disposed when execution exits the
// using statement.
using(Stream
netStream = new NetworkStream(clientSocket, true),
bufStream =
new BufferedStream(netStream, streamBufferSize))
{
// Check whether the underlying stream supports seeking.
Console.WriteLine("NetworkStream {0} seeking.\n",
bufStream.CanSeek ? "supports" : "does not support");
// Send and receive data.
if(bufStream.CanWrite)
{
SendData(netStream, bufStream);
}
if(bufStream.CanRead)
{
ReceiveData(netStream, bufStream);
}
// When bufStream is closed, netStream is in turn
// closed, which in turn shuts down the connection
// and closes clientSocket.
Console.WriteLine("\nShutting down the connection.");
bufStream.Close();
}
}
static void SendData(Stream netStream, Stream bufStream)
{
DateTime startTime;
double networkTime, bufferedTime;
// Create random data to send to the server.
byte[] dataToSend = new byte[dataArraySize];
new Random().NextBytes(dataToSend);
// Send the data using the NetworkStream.
Console.WriteLine("Sending data using NetworkStream.");
startTime = DateTime.Now;
for(int i = 0; i < numberOfLoops; i++)
{
netStream.Write(dataToSend, 0, dataToSend.Length);
}
networkTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes sent in {1} seconds.\n",
numberOfLoops * dataToSend.Length,
networkTime.ToString("F1"));
// Send the data using the BufferedStream.
Console.WriteLine("Sending data using BufferedStream.");
startTime = DateTime.Now;
for(int i = 0; i < numberOfLoops; i++)
{
bufStream.Write(dataToSend, 0, dataToSend.Length);
}
bufStream.Flush();
bufferedTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes sent in {1} seconds.\n",
numberOfLoops * dataToSend.Length,
bufferedTime.ToString("F1"));
// Print the ratio of write times.
Console.WriteLine("Sending data using the buffered " +
"network stream was {0} {1} than using the network " +
"stream alone.\n",
(networkTime/bufferedTime).ToString("P0"),
bufferedTime < networkTime ? "faster" : "slower");
}
static void ReceiveData(Stream netStream, Stream bufStream)
{
DateTime startTime;
double networkTime, bufferedTime = 0;
int bytesReceived = 0;
byte[] receivedData = new byte[dataArraySize];
// Receive data using the NetworkStream.
Console.WriteLine("Receiving data using NetworkStream.");
startTime = DateTime.Now;
while(bytesReceived < numberOfLoops * receivedData.Length)
{
bytesReceived += netStream.Read(
receivedData, 0, receivedData.Length);
}
networkTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes received in {1} seconds.\n",
bytesReceived.ToString(),
networkTime.ToString("F1"));
// Receive data using the BufferedStream.
Console.WriteLine("Receiving data using BufferedStream.");
bytesReceived = 0;
startTime = DateTime.Now;
int numBytesToRead = receivedData.Length;
while (numBytesToRead > 0)
{
// Read may return anything from 0 to numBytesToRead.
int n = bufStream.Read(receivedData,0, receivedData.Length);
// The end of the file is reached.
if (n == 0)
break;
bytesReceived += n;
numBytesToRead -= n;
}
bufferedTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes received in {1} seconds.\n",
bytesReceived.ToString(),
bufferedTime.ToString("F1"));
// Print the ratio of read times.
Console.WriteLine("Receiving data using the buffered network" +
" stream was {0} {1} than using the network stream alone.",
(networkTime/bufferedTime).ToString("P0"),
bufferedTime < networkTime ? "faster" : "slower");
}
}
Both FileStream and StreamWriter are internally buffered (they have a default buffer size of 4096 and 1024 bytes and constructors able to modify it).
The complex question would be how to write to a file without using a buffer :-) And note that, thanks to how they work, a StreamWriter that writes to a file will be double-buffered (the buffer of StreamWriter is independent of the one of FileStream). At least StreamWriter has an AutoFlush property that, when set to true, will flush after each write.

Why is this way of reading from a NetworkStream so much faster?

At my company we've run into an issue that we cannot seem to explain. We're reading from a NetworkStream using a buffer of 2048 bytes. When both the client and server use that buffersize to write and read with, it's hideously slow (1 second extra on top of other processing times). If we use a buffersize that's very large, like 32k everything works really fast. The message we're sending is usually much larger than 32k so the entire message does not entirely fit in that buffer. The way we're reading is shown in the code below in the HandleDataLargeBuffer method.
To build a testcase for this issue I've written the code below, and I've posted my output below that.
My questions:
Any idea why a larger buffer size would be faster (less read calls but those shouldn't take too much time)?
In the code below, HandleDataVariableBuffer is much much faster than the other methods of reading, why?
Which is the best way of reading anyway?
Using a Proxy class to simulate slowdowns, pasted below the main file.
class Program
{
private StreamWriter Writer;
private int Count = 0;
static void Main(string[] args)
{
new Program();
}
public Program()
{
Writer = new StreamWriter(new FileStream("C:\\test.txt", FileMode.Create));
Start();
}
public void Start()
{
Proxy p = new Proxy();
new Thread(p.Start).Start();
Thread.Sleep(500);
new Thread(SetupServer).Start();
Thread.Sleep(1000); // Wait for TCP Server setup.
for (int i = 0; i != 3; ++i)
{
TcpClient client = new TcpClient("127.0.0.1", 50001);
Send(client.GetStream());
client.Close();
Thread.Sleep(1000);
}
WriteLine("Tests done.");
Console.ReadLine();
Writer.Close();
}
private void SetupServer()
{
WriteLine("[Server] Starting server.");
TcpListener listener = new TcpListener(IPAddress.Any, 50000);
listener.Start();
WriteLine("[Server] Started listening on port 50000.");
while (true) // We'll just forcibly end, obviously you'd use the callback methods for this normally.
{
TcpClient client = listener.AcceptTcpClient();
WriteLine(String.Format("[Server] Accepted client with IP: {0}", client.Client.RemoteEndPoint.ToString()));
new Thread(HandleClient).Start(client);
}
}
private void HandleClient(object argument)
{
TcpClient client = (TcpClient)argument;
NetworkStream stream = client.GetStream();
// Now there are multiple ways to handle this data, however first we read the int at the start.
byte[] length = new byte[4];
stream.Read(length, 0, 4);
int lengthInt = BitConverter.ToInt32(length, 0);
if (lengthInt <= 0) return; // Shouldn't happen.
// Test data read in multiple ways.
Stopwatch watch = new Stopwatch();
watch.Start();
string handler = "";
if (Count == 0)
{
handler = "LargeBuffer";
HandleDataLargeBuffer(lengthInt, stream);
++Count;
}
else if (Count == 1)
{
handler = "SmallBuffer";
HandleDataSmallBuffer(lengthInt, stream);
++Count;
}
else if (Count == 2)
{
handler = "VariableBuffer";
HandleDataVariableBuffer(lengthInt, stream);
Count = 0;
}
watch.Stop();
WriteLine(String.Format("\t[Server] [{3}] Read {0} bytes from client {1} in {2} ms", lengthInt.ToString(), client.Client.RemoteEndPoint.ToString(), watch.ElapsedMilliseconds.ToString(), handler));
}
private void HandleDataLargeBuffer(int length, NetworkStream stream)
{
int read = 0;
int totalRead = 0;
MemoryStream dataBuffer = new MemoryStream(); // I'm writing to a memory stream because in my real life situation I write (stream) to another NetworkStream
byte[] buffer = new byte[8192 * 4];
while ((read = stream.Read(buffer, 0, 8192 * 4)) != 0 && totalRead < length)
{
totalRead += read;
dataBuffer.Write(buffer, 0, read);
}
}
private void HandleDataSmallBuffer(int length, NetworkStream stream)
{
int read = 0;
int totalRead = 0;
MemoryStream dataBuffer = new MemoryStream(); // I'm writing to a memory stream because in my real life situation I write (stream) to another NetworkStream
byte[] buffer = new byte[512];
while ((read = stream.Read(buffer, 0, 512)) != 0 && totalRead < length)
{
totalRead += read;
dataBuffer.Write(buffer, 0, read);
}
}
private void HandleDataVariableBuffer(int length, NetworkStream stream)
{
int read = 0;
int totalRead = 0;
MemoryStream dataBuffer = new MemoryStream(); // I'm writing to a memory stream because in my real life situation I write (stream) to another NetworkStream
while (totalRead < length)
{
byte[] buffer = new byte[length - totalRead]; // You'd obviously do some additional checks on 'length' to make sure no foul play is involved.
read = stream.Read(buffer, 0, length - totalRead);
totalRead += read;
dataBuffer.Write(buffer, 0, read);
}
}
public void Send(NetworkStream stream)
{
// Generate some random data
Random r = new Random();
byte[] buf = new byte[1024 * 420]; // Buffer of 420k to simulate a decently large message
byte[] length = BitConverter.GetBytes(1024 * 420);
r.NextBytes(buf);
// Create the total message array: [Length][Message]
byte[] totalMessage = new byte[4 + 1024 * 420];
System.Buffer.BlockCopy(length, 0, totalMessage, 0, 4);
System.Buffer.BlockCopy(buf, 0, totalMessage, 4, buf.Length);
// Use a memory stream for ease of use
Stopwatch watch = new Stopwatch();
watch.Start();
using (MemoryStream memStream = new MemoryStream(totalMessage))
{
int read = -1;
byte[] buffer = new byte[8192];
while ((read = memStream.Read(buffer, 0, 8192)) != 0)
{
stream.Write(buffer, 0, read);
}
}
stream.Flush();
watch.Stop();
WriteLine("[Send] Took " + watch.ElapsedMilliseconds + " ms to send " + totalMessage.Length + " bytes of data.");
}
public void WriteLine(string str)
{
Writer.WriteLine(str);
Writer.Flush();
}
}
Proxy.cs
public class Proxy
{
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 50001);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
new Thread(HandleClient).Start(client);
}
}
private void HandleClient(object argument)
{
TcpClient client = (TcpClient)argument;
Thread.Sleep(1000);
NetworkStream clientStream = client.GetStream();
int read = 0;
byte[] length = new byte[4];
clientStream.Read(length, 0, 4);
int lengthInt = BitConverter.ToInt32(length, 0);
if (lengthInt <= 0)
{
client.Close();
return;
}
TcpClient serverClient = new TcpClient("127.0.0.1", 50000);
NetworkStream serverStream = serverClient.GetStream();
int totalRead = 0;
serverStream.Write(length, 0, 4);
while (totalRead < lengthInt)
{
Thread.Sleep(50);
byte[] buffer = new byte[lengthInt - totalRead]; // You'd obviously do some additional checks on 'length' to make sure no foul play is involved.
read = clientStream.Read(buffer, 0, lengthInt - totalRead);
totalRead += read;
serverStream.Write(buffer, 0, read);
}
serverStream.Flush();
Thread.Sleep(1000);
client.Close();
serverClient.Close();
}
}
I'm sorry for the heap of code posted, when I first started I hoped it'd be smaller. Here's the output on my machine.
[Server] Starting server.
[Server] Started listening on port 50000.
[Server] Accepted client with IP: 127.0.0.1:3985
[Send] Took 1047 ms to send 430084 bytes of data.
[Server] [LargeBuffer] Read 430080 bytes from client 127.0.0.1:3985 in 1148 ms
[Server] Accepted client with IP: 127.0.0.1:3987
[Send] Took 1049 ms to send 430084 bytes of data.
[Server] [SmallBuffer] Read 430080 bytes from client 127.0.0.1:3987 in 1150 ms
[Server] Accepted client with IP: 127.0.0.1:3989
[Send] Took 1051 ms to send 430084 bytes of data.
[Server] [VariableBuffer] Read 430080 bytes from client 127.0.0.1:3989 in 100 ms
Tests done.

C# Socket Send Picture JPEG

So I have found here in stackoverflow One code for sending through sockets a binary file, an image.. So i used it for test to my Project
private void send_ss()
{
byte[] data = new byte[1024];
int sent;
IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 306);
Socket server = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
server.Connect(ipep);
}
catch (SocketException e)
{
//Console.WriteLine("Unable to connect to server.");
//Console.WriteLine(e.ToString());
//Console.ReadLine();
}
Bitmap bmp = new Bitmap("C:\\Windows\\Web\\Wallpaper\\Theme2\\img7.jpg");
MemoryStream ms = new MemoryStream();
// Save to memory using the Jpeg format
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
// read to end
byte[] bmpBytes = ms.ToArray();
bmp.Dispose();
ms.Close();
sent = SendVarData(server, bmpBytes);
//Console.WriteLine("Disconnecting from server...");
server.Shutdown(SocketShutdown.Both);
server.Close();
}
private static int SendVarData(Socket s, byte[] data)
{
int total = 0;
int size = data.Length;
int dataleft = size;
int sent;
byte[] datasize = new byte[4];
datasize = BitConverter.GetBytes(size);
sent = s.Send(datasize);
while (total < size)
{
sent = s.Send(data, total, dataleft, SocketFlags.None);
total += sent;
dataleft -= sent;
}
return total;
}
so i tried to send this picture on one of my Listening Sockets in Port 306 (listened with m IRC)
on *:socklisten:ac_img:{
var %p = $ticks $+ $time(hhnnss) $+ $ctime
sockaccept ac_img_ $+ %p
echo -s [] Image Connection Established On -> ac_img_ $+ %p
}
on *:sockread:ac_img_*:{
sockread &picture
bwrite $qt($mIRCdir $+ $sockname $+ .jpg) -1 -1 &picture
}
So i'm getting files like ac_img_2920385501147471360792067.jpg and so on. Same size with the original BUT the images just not appearing , so i opened Both files with word pad and they were a bit different... dunno why...
So any ideas why i'm facing this issue? i mean... I'm taking every single data from my socket and saving them to the file? Maybe a corrupt on file read through c#?
The image is different because you read it, parse it into a Bitmap and reencode it. The wordpad screenshot shows that both are JPEG's but with different metadata (for example "adobe" missing").
Just use File.ReadAllBytes or other lossless methods to read the image.
The sending code looks sound. Not sure why you're looping. Sending never does partial IOs AFAIK on blocking sockets.

how to fix file transfer , received files is corrupted?

i have file transfer application [server- client] using tcp sockets.
when i send a single file, it success, but when i send a folder that contains many files, the received files got corrupted ,note that both of sent files from client and received files from the server have the same size(same count of bytes).
server:
private void ReceiveX(Socket client, string destPath, long size, int bufferSize)
{
using (Stream stream = File.Create(destPath))
{
byte[] buffer = new byte[bufferSize];
long sum = 0;
int count = 0;
do
{
count = client.Receive(buffer, 0, buffer.Length, SocketFlags.None);
stream.Write(buffer, 0, count);
sum += count;
} while (sum < size);
}
}
client :
private void SendX(Socket socket, string filePath, long size, int bufferSize, DoWorkEventArgs e)
{
using (Stream stream = File.OpenRead(filePath))
{
byte[] buffer = new byte[bufferSize];
long sum = 0;
int count = 0;
do
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
count = stream.Read(buffer, 0, buffer.Length);
socket.Send(buffer, 0, count, SocketFlags.None);
sum += count;
worker.ReportProgress((int)((sum * 100) / size));
} while (sum < size);
}
}
the bufferSize is [4 * 1024] for both client and server
Is there any wrong with the code above?
client : here i loop over the folder to send files:
private void SendDir(string path, int bufferSize, DoWorkEventArgs e)
{
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
listener.Bind(endpoint);
listener.Listen(1);
client.ReceiveFolder((IPEndPoint)listener.LocalEndPoint, fileList, Path.Combine(currAddress,Path.GetFileName(path)),bufferSize);
Socket socket = listener.Accept();
int count = 0;
foreach (_File file in fileList)
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
Console.WriteLine(++count);
SendX(socket, file.Path, file.Size, bufferSize, e);
}
socket.Dispose();
}
server ,loop over files in list<_File> which received from the server before, it contains the files info (name,path,size) that client is going to send :
private void ReceiveFolderTh(IPEndPoint endpoint, List<_File> Files, string destDir, int bufferSize)
{
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(IPAddress.Parse("127.0.0.1"), endpoint.Port);
foreach (_File file in Files)
{
Directory.CreateDirectory(destDir + Path.GetDirectoryName(file.Name));
ReceiveX(client, destDir + file.Name, file.Size, bufferSize);
}
client.Dispose();
}
so how can i fix that?
Quite possibly the problem is that your client is receiving too much data on the first file because you have no clear separation between files. Your receive code is:
do
{
count = client.Receive(buffer, 0, buffer.Length, SocketFlags.None);
stream.Write(buffer, 0, count);
sum += count;
} while (sum < size);
You always receive up to buffer.Length (which you say is 4,096) bytes. So if the first file is 100 bytes long and the next file is 5,000 bytes long, it's quite possible that the server is sending a packet of 4,096 bytes, which your code will dutifully receive and store in the first file.
You need to change the number of bytes to receive in your call to client.Receive. Something like:
int bytesToReceive = Math.Min(buffer.Length, size - sum);
count = client.Receive(buffer, 0, bytesToReceive, SocketFlags.None);
That will prevent you from reading beyond the end of one file and into the start of the next one.

Categories