NetworkStream cuts off first 4 bytes when reading - c#

I ran into a strange problem. When I'm trying to send the file via a TCP socket, the first 4 bytes of sended information cuts off.
That is sending and receives pieces of code.
Client side
for (var i = 0; i < fileContentByte.Length; i += buffer.Length)
{
var size = (i + buffer.Length > fileContentByte.Length) ? fileContentByte.Length - i : buffer.Length;
clientSocket.Write(fileContentByte, i, size);
}
Server side
using(var file = File.Create("C:\\test\\"+fileName.Substring(0, fileName.IndexOf('\0'))))
while(bytesReceived < numberOfBytes && (count = clientStream.Read(buffer, 0, buffer.Length)) > 0)
{
file.Write(buffer, 0, count);
bytesReceived += count;
}
Here is link on full code - http://pastebin.com/VwTgTxgb

You're doing something very strange here.
First of all, retrieval of file name can be greatly simplified down to Path.GetFileName() call.
Second, are you sure ASCII will suffice?
Third, reading the entire file into memory is OK-ish for a proof-of-concept project, but be ready to switch to streaming operations.
Fourth, your protocol is somewhat wonky. When sending variable-size payload, it is required to first tell the receiving party exactly how much bytes are you going to send. This is exactly what you don't do when sending file name.
Here's a snippet to get you started:
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace FolderSync
{
class Program
{
static void Main()
{
var server = new Server();
server.Start();
new Client().TransmitFile(
new IPEndPoint(IPAddress.Loopback, 35434),
#"f:\downloads\ubuntu-14.04.3-desktop-amd64.iso");
Console.ReadLine();
server.Stop();
}
}
class Server
{
private readonly TcpListener tcpListener;
public Server()
{
tcpListener = new TcpListener(IPAddress.Loopback, 35434);
}
public void Start()
{
tcpListener.Start();
tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
}
public void Stop()
{
tcpListener.Stop();
}
private void AcceptTcpClientCallback(IAsyncResult asyncResult)
{
//
// Big fat warning: http://stackoverflow.com/a/1230266/60188
tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
using(var tcpClient = tcpListener.EndAcceptTcpClient(asyncResult))
using(var networkStream = tcpClient.GetStream())
using(var binaryReader = new BinaryReader(networkStream, Encoding.UTF8))
{
var fileName = binaryReader.ReadString();
var length = binaryReader.ReadInt64();
var mib = length / 1024.0 / 1024.0;
Console.WriteLine("Receiving '{0}' ({1:N1} MiB)", fileName, mib);
var stopwatch = Stopwatch.StartNew();
var fullFilePath = Path.Combine(Path.GetTempPath(), fileName);
using(var fileStream = File.Create(fullFilePath))
networkStream.CopyTo(fileStream);
var elapsed = stopwatch.Elapsed;
Console.WriteLine("Received in {0} ({1:N1} MiB/sec)",
elapsed, mib / elapsed.TotalSeconds);
}
}
}
class Client
{
public void TransmitFile(IPEndPoint endPoint, string fileFullPath)
{
if(!File.Exists(fileFullPath)) return;
using(var tcpClient = new TcpClient())
{
tcpClient.Connect(endPoint);
using(var networkStream = tcpClient.GetStream())
using(var binaryWriter = new BinaryWriter(networkStream, Encoding.UTF8))
{
var fileName = Path.GetFileName(fileFullPath);
Debug.Assert(fileName != null, "fileName != null");
//
// BinaryWriter.Write(string) does length-prefixing automatically
binaryWriter.Write(fileName);
using(var fileStream = File.OpenRead(fileFullPath))
{
binaryWriter.Write(fileStream.Length);
fileStream.CopyTo(networkStream);
}
}
}
}
}
}

Related

c# TCP NetworkStream is not receiving data

I'm trying to send files after sending their's information via TCP connection. At the end of receiver host, the data packets are received. I used Wireshark to confirm it. However the data couldn't be received in NetworkStream.
public class FileTransporter
{
public void ReceiveFiles(IPAddress IP, int port)
{
TcpListener tcpListener = new TcpListener(IP, port);
tcpListener.Start();
using (TcpClient tcpClient = tcpListener.AcceptTcpClient())
{
if (tcpClient.Connected)
{
using (NetworkStream networkStream = tcpClient.GetStream())
{
int pointer = 0;
byte[] fileNameLengthBytes = new byte[sizeof(int)];
networkStream.Read(fileNameLengthBytes, pointer, fileNameLengthBytes.Length);
int fileNameLength = BitConverter.ToInt32(fileNameLengthBytes, pointer);
// code to read fileName and it's size
networkStream.Close();
}
}
tcpClient.Close();
}
tcpListener.Stop();
}
public void SendFiles(IPAddress IP, int port, string[] paths)
{
for(int i=0; i<paths.Length; i++)
{
FilePackage filePackage = new FilePackage(paths[i]);
byte[] infoBytes = filePackage.EncodeInfoToByte();
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.Connect(IP, port);
using (NetworkStream networkStream = tcpClient.GetStream())
{
networkStream.Write(infoBytes, 0, infoBytes.Length);
networkStream.Close();
}
tcpClient.Close();
}
}
}
}
public class FilePackage
{
public FilePackage(string fileName)
{
this.Info = new FileInfo(fileName);
}
public byte[] EncodeInfoToByte()
{
List<byte> infoByte = new List<byte>();
infoByte.AddRange(BitConverter.GetBytes(this.Info.Name.Length));
infoByte.AddRange(Encoding.UTF8.GetBytes(this.Info.Name));
infoByte.AddRange(BitConverter.GetBytes(this.Info.Length));
return infoByte.ToArray();
}
I am going to Assume that ReadFiles is invoked somehow / somewhere else.
I have a very similar implementation, however my "Read" of the stream is much smaller:
// Read the first batch of the TcpServer response bytes.
var bytes = new byte[512];
// Loop to receive all the data sent by the Server.
var sb = new StringBuilder();
do
{
var i = stream.Read(bytes, 0, bytes.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(bytes, 0, i));
} while (stream.DataAvailable);
Perhaps using "stream.DataAvailable" will allow you to test for data existence and that way you can make sure that you only process when data is available.
Also I don't see where "pointer" is being initialized in your code.
If it is not set to 0 each time, you will not be processing from the beginning of the data packet.
Your problem is probably being caused by the nagle algorithm, prevent small amounts of data being sent to reduce congestion. You could try disabling it by setting the following properties on your tcpClient
tcpClient.NoDelay = true;
tcpClient.Client.NoDelay = true

getting exception from server in c# socket

I have created a simple server and client program in c#. The server will send a string array to the client and the client will display it and the client will sent an id to server and the server will display it. My sample code is given below. When I run them, I get an exception in the server side. I have marked the line in which I am getting the exception.My sample code is given below:
server:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace server
{
class Program
{
static void Main(string[] args)
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
string[] arr1 = new string[] { "one", "two", "three" };
var serializer = new XmlSerializer(typeof(string[]));
serializer.Serialize(tcpClient.GetStream(), arr1);
tcpClient.Close();
int recv = ns.Read(data, 0, data.Length); //getting exception in this line
string id = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(id);
}
}
}
}
client :
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace Client
{
class Program
{
static void Main(string[] args)
{
try
{
byte[] data = new byte[1024];
string stringData;
TcpClient tcpClient = new TcpClient("127.0.0.1", 1234);
NetworkStream ns = tcpClient.GetStream();
var serializer = new XmlSerializer(typeof(string[]));
var stringArr = (string[])serializer.Deserialize(tcpClient.GetStream());
foreach (string s in stringArr)
{
Console.WriteLine(s);
}
string input = Console.ReadLine();
ns.Write(Encoding.ASCII.GetBytes(input), 0, input.Length);
ns.Flush();
}
catch (Exception e)
{
Console.Write(e.Message);
}
Console.Read();
}
}
}
The exception I am getting is:
An unhandled exception of type 'System.ObjectDisposedException' occurred in System.dll
Additional information: Cannot access a disposed object.
Is there anything wrong in the code? What will I need to do to avoid this exception?
It seems to me that in your server code you are closing the TCP client before you continue with reading the data. This is why you are getting the exception.
Also, you are trying to read 1024 bytes, but the client does not send 1024 (unless by an unlikely chance that the string that the client sends which is an input from the user is encoded into a 1024 byte array) so the server will simply block and do nothing because it is waiting for the client to send 1024 bytes.
One good way to manage reading and writing data from/to a stream is through the BinaryReader and BinaryWriter classes.
Consider the following code to solve your issue (it contains some improvements to your code):
Server:
class Program
{
static void Main(string[] args)
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
while (true)
{
using (TcpClient tcpClient = tcpListener.AcceptTcpClient())
{
using (var network_stream = tcpClient.GetStream())
{
using (BinaryReader reader = new BinaryReader(network_stream))
{
using (BinaryWriter writer = new BinaryWriter(network_stream))
{
string[] arr1 = new string[] { "one", "two", "three" };
writer.Write(arr1.Length);
foreach (var item in arr1)
{
writer.Write(item);
}
var id = reader.ReadString();
Console.WriteLine("Id: " + id);
}
}
}
}
}
}
}
Client:
class Program
{
static void Main(string[] args)
{
try
{
using (TcpClient tcpClient = new TcpClient("127.0.0.1", 1234))
{
using (NetworkStream network_stream = tcpClient.GetStream())
{
using (BinaryReader reader = new BinaryReader(network_stream))
{
using (BinaryWriter writer = new BinaryWriter(network_stream))
{
int number_of_strings = reader.ReadInt32();
string[] lines = new string[number_of_strings];
for(int i = 0 ; i < number_of_strings ; i++)
{
lines[i] = reader.ReadString(); //Store the strings if you want to
Console.WriteLine(lines[i]);
}
Console.WriteLine("Please input id:");
string id = Console.ReadLine();
writer.Write(id);
}
}
}
}
}
catch (Exception e)
{
Console.Write(e.Message);
}
Console.Read();
}
}
You are using the NetworkStream after you have Closed the TcpClient (which disposed it). See updated while below:
while (true)
{
var tcpClient = tcpListener.AcceptTcpClient();
var data = new byte[1024];
var arr1 = new string[] { "one", "two", "three" };
var serializer = new XmlSerializer(typeof(string[]));
serializer.Serialize(tcpClient.GetStream(), arr1);
var ns = tcpClient.GetStream();
var recv = ns.Read(data, 0, data.Length); //getting exception in this line
var id = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(id);
ns.Close();
tcpClient.Close();
}
tcpClient Implementing Idisposible interface it is better to call dispose method in tcpclient
tcpClient.Dispose();
else
tcpClient.GetStream().Close();
tcpClient.Close();
Closing the client does not close the stream.
var serializer = new XmlSerializer(typeof(string[]));
serializer.Serialize(tcpClient.GetStream(), arr1);
tcpClient.GetStream().Close()
tcpClient.Close();

Send a large file over tcp connection

I need to send a few large files to a computer over the internet. As a result I opened the ports that I plan to use on the router and forward the correspoinding ip addresses. anyways let me show you the classes that I have been working on in order to achieve this. This classes work great with small files but sometimes they fail with large files.
here is the code for the server: (it is a console application)
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace ConsoleApplication20
{
//server
class Program
{
static Server s;
public static void mm()
{
s = new Server("192.168.0.196");
s.startServer();
Console.Read();
}
static void Main(string[] args)
{
// Thread t = new Thread(new ThreadStart(mm));
// t.Start();
mm();
Console.Read();
s.disconnect();
}
}
class MyTCP
{
protected const int MaxChunkSize = 4096;
protected Int32 port { get; set; }
protected string serverIP { get; set; }
protected TcpClient client { get; set; }
protected static NetworkStream stream { get; set; }
protected void sendData(NetworkStream stream, Byte[] data)
{
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
}
protected String receiveData(NetworkStream stream)
{
// Buffer to store the response bytes.
Byte[] data = new Byte[MaxChunkSize];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
return responseData;
}
protected static Byte[] textToBytes(string text)
{
return System.Text.Encoding.ASCII.GetBytes(text);
}
public virtual void disconnect() { }
public bool isServerConected { get { return client.Connected; } }
}
[Serializable]
public class FileProperties
{
public string FileName { get; set; }
public string DestPath { get; set; }
public double FileSize { get; set; }
public FileAttributes fileAttributes { get; set; }
public System.Security.AccessControl.FileSecurity FileSecurity { get; set; }
public DateTime creationTime { get; set; }
public DateTime lastAccessTime { get; set; }
public DateTime lastWriteTime { get; set; }
}
class Server: MyTCP
{
private System.IO.FileStream _FileStream;
private static TcpListener server;
private static bool disconect;
/// <summary>
/// Constructor
/// </summary>
/// <param name="localAddr">The ip address of the server</param>
/// <param name="port">on what port the server going to be listening to?</param>
/// <param name="autoStartServer">start listening for connections now? you may call the startserver() method latter...</param>
public Server(string localAddr, Int32 port = 13000, bool autoStartServer = false)
{
this.port = port;
this.serverIP = localAddr;
if (autoStartServer)
start();
}
/// <summary>
/// Start listening for connections
/// </summary>
public void startServer()
{
start();
}
public override void disconnect()
{
// Close everything.
stream.Close();
client.Close();
server.Stop();
disconect = true;
}
void start()
{
server = null;
try
{
// TcpListener server = new TcpListener(port);
server = new TcpListener(IPAddress.Parse(serverIP), port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[MaxChunkSize];
String data = null;
// Enter the listening loop.
while (disconect==false)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
stream = client.GetStream();
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
if (data.ToUpper().Contains("<sendFile>".ToUpper()))
{
receiveFile(bytes);
}
continue;
}
}
catch { }
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
void receiveFile(Byte[] bytes)
{
// send 1
sendData(stream, textToBytes("<1>"));
// receive 2
int length = stream.Read(bytes, 0, bytes.Length);
byte[] tempA = new byte[length];
for (int k = 0; k < length; k++)
tempA[k] = bytes[k];
Stream ms = new MemoryStream(tempA);
FileProperties p = new FileProperties();
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
try
{
p = (FileProperties)x.Deserialize(ms);
if (Directory.Exists(p.DestPath))
{
//send 3
sendData(stream, textToBytes("<3>"));
}
else
{
//send 3
sendData(stream, textToBytes("<no>"));
return;
}
}
catch
{
//send 3
sendData(stream, textToBytes("<no>"));
return;
}
int i;
string temp = Path.Combine(new string[]{ p.DestPath, p.FileName + ".temp"});
_FileStream = new System.IO.FileStream(temp, System.IO.FileMode.Create, System.IO.FileAccess.Write);
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
if (i == 11 & System.Text.Encoding.ASCII.GetString(bytes, 0, i).ToUpper().Equals("</sendFile>".ToUpper()))
{
_FileStream.Close();
Console.WriteLine("D!");
File.SetAttributes(temp, p.fileAttributes);
File.SetAccessControl(temp, p.FileSecurity);
File.SetCreationTime(temp, p.creationTime);
File.SetLastAccessTime(temp, p.lastAccessTime);
File.SetLastWriteTime(temp, p.lastWriteTime);
if(File.Exists(temp.Substring(0, temp.Length - 4)))
File.Delete(temp.Substring(0, temp.Length - 4));
File.Move(temp, temp.Substring(0, temp.Length - 4));
//sendData(stream, textToBytes("<done>"));
Console.WriteLine("Done!");
return;
}
_FileStream.Write(bytes, 0, i);
}
return;
}
}
}
and the code for my client is:
using System;
using System.Net.Sockets;
using System.Windows;
using System.IO;
namespace WpfApplication23sdfd
{
[Serializable]
public class FileProperties
{
public string FileName { get; set; }
public string DestPath { get; set; }
public double FileSize { get; set; }
public FileAttributes fileAttributes { get; set; }
public System.Security.AccessControl.FileSecurity FileSecurity { get; set; }
public DateTime creationTime { get; set; }
public DateTime lastAccessTime { get; set; }
public DateTime lastWriteTime { get; set; }
}
abstract class MyTCP
{
protected const int MaxChunkSize = 4096;
protected Int32 port { get; set; }
protected string serverIP { get; set; }
protected TcpClient client { get; set; }
protected static NetworkStream stream { get; set; }
protected void sendData(NetworkStream stream, Byte[] data)
{
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
// Receive the TcpServer.response.
}
protected String receiveData(NetworkStream stream)
{
// Buffer to store the response bytes.
Byte[] data = new Byte[MaxChunkSize];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
return responseData;
}
protected static Byte[] textToBytes(string text)
{
return System.Text.Encoding.ASCII.GetBytes(text);
}
public virtual void disconnect() { }
public bool isServerConected { get { return client.Connected; } }
}
//client
class Client: MyTCP
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="serverIP">the ip address of the server</param>
/// <param name="port">through what port is the connection going to be established</param>
public Client(string serverIP, Int32 port = 13000, bool autoConnect = false)
{
this.port = port;
this.serverIP = serverIP;
if (autoConnect)
connect();
}
public bool connect()
{
Byte[] data = System.Text.Encoding.ASCII.GetBytes("connect");
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
try
{
client = new TcpClient(serverIP, port);
// Get a client stream for reading and writing.
// Stream stream = client.GetStream();
stream = client.GetStream();
return true;
}
catch
{
return false;
}
}
public override void disconnect()
{
// Close everything.
stream.Close();
client.Close();
}
static void ConnectOld(String server, Byte[] data)
{
try
{
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
Int32 port = 13000;
TcpClient client = new TcpClient(server, port);
// Get a client stream for reading and writing.
// Stream stream = client.GetStream();
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
// Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
// Close everything.
stream.Close();
client.Close();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.WriteLine("\n Press Enter to continue...");
Console.Read();
}
public void sendFile(string file, string destPath = "c:\\")
{
//let server know what you are going to be doing...
sendData(stream, textToBytes("<sendFile>"));
FileProperties p = new FileProperties {
creationTime = File.GetCreationTime(file),
fileAttributes = File.GetAttributes(file),
FileSecurity = File.GetAccessControl(file),
lastAccessTime = File.GetLastAccessTime(file),
lastWriteTime = File.GetLastWriteTime(file),
DestPath = destPath,
FileName = Path.GetFileName(file)
};
// receive 1
if (!receiveData(stream).ToUpper().Contains("<1>".ToUpper()))
{
MessageBox.Show("Error comunicating with server");
return;
}
// send object p to server
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
x.Serialize(stream, p); // send 2
//recieve 3
if (!receiveData(stream).ToUpper().Contains("<3>".ToUpper()))
{
MessageBox.Show("Error incorrect parameters sent to server");
return;
}
System.IO.FileStream streamFile = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read);
while (true)
{
byte[] chunk = new byte[MaxChunkSize];
int index = 0;
// There are various different ways of structuring this bit of code.
// Fundamentally we're trying to keep reading in to our chunk until
// either we reach the end of the stream, or we've read everything we need.
while (index < chunk.Length)
{
int bytesRead = streamFile.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
if (bytesRead < MaxChunkSize)
{
byte[] temp = new byte[bytesRead];
for (var i = 0; i < bytesRead; i++)
temp[i] = chunk[i];
chunk = temp;
}
index += bytesRead;
}
if (index != 0) // Our previous chunk may have been the last one
{
sendData(stream,chunk); // index is the number of bytes in the chunk
}
if (index != chunk.Length) // We didn't read a full chunk: we're done
{
sendData(stream, textToBytes("</sendFile>".ToUpper()));
//receiveData(stream);//wait recall missing to check results
return;
}
}
}
}
}
the way I instantiate the client class is by providing the IP address of the server as:
Client c = new Client("192.168.0.196");
c.sendFile(#"A:\Users\Tono\Desktop\a.mp4");
the server has to be running first before executing that code.
I don't know why is so complicated to send a file over the internet using sockets. I don't konw WCF that's why I been loosing a lot of time creating this classes. Maybe there are already some built in classes that will enable me to send files over the internet to a different computer. I know just the basics of networking thereofore it will be nice if I could do it with a simple class. I don't undersatnd why my classes do not work all the time? if I increase the buffer size will my classes be more efficient? do I have to wait or pause my program a little bit before sending more bytes? It will be nice if someone can tell me what is wrong with this classes. They work nice with small files but with large files sometimes it does not work...
Here is my code to send a large file.
Some tips:
Check your buffer size. If it's too big it will fail.
Socket flags. The partial flag works the best.
Socket timeout is needed due to the transfer time.
Client :
string IPAddress = "";
int Port = 500;
string Filename = #"C:\Users\Ben\Desktop\TT.zip";
int bufferSize = 1024;
byte[] buffer = null;
byte[] header = null;
FileStream fs = new FileStream(Filename, FileMode.Open);
bool read = true;
int bufferCount = Convert.ToInt32(Math.Ceiling((double)fs.Length / (double)bufferSize));
TcpClient tcpClient = new TcpClient(IPAddress, Port);
tcpClient.SendTimeout = 600000;
tcpClient.ReceiveTimeout = 600000;
string headerStr = "Content-length:" + fs.Length.ToString() + "\r\nFilename:" + #"C:\Users\Administrator\Desktop\" + "test.zip\r\n";
header = new byte[bufferSize];
Array.Copy(Encoding.ASCII.GetBytes(headerStr), header, Encoding.ASCII.GetBytes(headerStr).Length);
tcpClient.Client.Send(header);
for (int i = 0; i < bufferCount; i++)
{
buffer = new byte[bufferSize];
int size = fs.Read(buffer, 0, bufferSize);
tcpClient.Client.Send(buffer,size,SocketFlags.Partial);
}
tcpClient.Client.Close();
fs.Close();
Server :
int Port = 500;
TcpListener listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
Socket socket = listener.AcceptSocket();
int bufferSize = 1024;
byte[] buffer = null;
byte[] header = null;
string headerStr = "";
string filename = "";
int filesize = 0;
header = new byte[bufferSize];
socket.Receive(header);
headerStr = Encoding.ASCII.GetString(header);
string[] splitted = headerStr.Split(new string[] { "\r\n" }, StringSplitOptions.None);
Dictionary<string, string> headers = new Dictionary<string, string>();
foreach (string s in splitted)
{
if (s.Contains(":"))
{
headers.Add(s.Substring(0,s.IndexOf(":")), s.Substring(s.IndexOf(":") + 1));
}
}
//Get filesize from header
filesize = Convert.ToInt32(headers["Content-length"]);
//Get filename from header
filename = headers["Filename"];
int bufferCount = Convert.ToInt32(Math.Ceiling((double)filesize / (double)bufferSize));
FileStream fs = new FileStream(filename, FileMode.OpenOrCreate);
while(filesize > 0)
{
buffer = new byte[bufferSize];
int size = socket.Receive(buffer,SocketFlags.Partial);
fs.Write(buffer,0,size);
filesize -= size;
}
fs.Close();
Hope this will help someone.
There are a few issues that I can see immediately. The one that may be causing your program to only work some of the time is the fact that sending via TCP will not guarantee that every send will result in an identically-sized receive on the other side.
Your protocol seems to assume it will, because you're waiting for a read of exactly 11 bytes for the </sendFile>, whereas it could be received in multiple separate reads. E.g.: "[file data...]". If this happens, your code will not correctly finish.
It's also worth noting that the ASCII encoding is 7-bit, and so binary files (such as the MP4) will be received incorrectly (even if you fix the above). If it is binary data, you should not attempt to convert it to a string, but instead write it to file directly from the byte[].
If you wish to contine down this route (rather than using the many existing file transfer systems already available as mentioned in another answer) then you may also want to change your protocol so that instead of delimiting the file with <sendFile>...</sendFile>, you send the file's length initially, which will allow you to send files that may contain one of these special tags.
Sending files / directories over sockets is not trivial. I would recommend using some file transfer library (over sockets, or maybe higher level protocol, i.e. rsync, ftp, http, etc), rather than trying to code the thing from scratch.
After skimming over the code - try sending a large file containing some uniform content (filled with '0's or something). If it would pass through - your xml thing doesn't work.
Basically what you are doing is correct. The main point I could suggest for improvement is setting the MaxChunkSize to a larger value, as much as 65000. This will enable the socket code to handle any fragmentation, which will be much more efficient than any splitting you will do by yourself.
Also, you are aware to the fact that sending a large file should take some time. At a 100 Mbit LAN, the bandwidth would be (theoretically) 12.5 MByte per second. Thus sending a 700 MByte file will still take 56 seconds. Of course that the actual throughput depends and many factors in the network and the computers and network hardware involved, so it would be expected to be slower.
Finally, Wireshark (or any other sniffer program) is the most basic and invaluable tool in the networking programmer toolbox. Use it on both the server and the client to see how the TCP packets are transmitted, to see if you can identify any causes for the slow trasnfer.

File Transfer using sockets and multiple clients

I have a large application written using .Net remoting for file transfer. This was borking in some circumstances with the sockets being forcibly closed - I wasn't using sockets directly, but a .Net remoting call with byte arrays (I wasn't sending the whole file in one transfer, I was splitting it up).
So, I decided to change the actual file transfer part to use sockets.
As a proof of concept, to see if I got the principles right, I have written a simple console client and a server.
I am using ASynch recieves but synchronous writes - I have tried with both being ASync but same reseult, and keeping it synchronous made debugging easier.
What the apps do (code below) is the server sits and waits for files to be transfered, and it stores them in a directory at a given name.
When enter is pressed, the server then reads the files recieved and sends them back to the clients who store them under a different name. I wanted to test file transfer both ways.
Using one instance of the client application, all is well - the server recieves it and then sends it back to the client. All is well. Yes, the client throws an exception when you terminate the server - but that is fine - I know that the socket was forcibly closed...I can deal with tidying upu the code when it is working.
However, when I create 2 instances of the client code (not forgetting to modify the code slightly to read a different file to send, and also to store the received file under a different name) - the server receives both files from the clients, sends the first one back just fine, and then a few segments into the second file it throws with a "non blocking socket operation could not be completed immediatly" - which is odd because nothing is blocking, and the recieves are async - and the sends are actually blocking!
Any suggestions please as to what I am doing wrong - no doubt it is something stupid, but still...
The aim of the final code is to be able to have n clients contact the server and send files to it, and also, at random intervals have the server send 1 or more files back to some/all of the clients.
Cheers folks!
Server code
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace SocketServer
{
class ConnectionInfo
{
public Socket Socket;
public byte[] Buffer;
public int client;
}
class Program
{
static int chunkSize = 16 * 1024;
static int chucksizeWithoutHeaderData = chunkSize - 8;
static List<ConnectionInfo> list = new List<ConnectionInfo>();
static Socket serverSocket;
static int nClient = 0;
static void AcceptCallback(IAsyncResult result)
{
ConnectionInfo info = new ConnectionInfo();
info.Socket = serverSocket.EndAccept(result);
info.Buffer = new byte[chunkSize];
Console.WriteLine("Client connected");
nClient++;
info.client = nClient;
list.Add(info);
info.Socket.BeginReceive(info.Buffer,0,info.Buffer.Length,SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback),null);
}
static void ReceiveCallBack(IAsyncResult result)
{
ConnectionInfo info = result.AsyncState as ConnectionInfo;
try
{
Int32 nSegmentNumber = BitConverter.ToInt32(info.Buffer,0);
Int32 nMaxSegment = BitConverter.ToInt32(info.Buffer,4);
string strFileName = string.Format(#"c:\temp\from-client-{0}.dat",info.client);
int bySize = info.Socket.EndReceive(result);
using (FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate))
{
Console.WriteLine("Received segment {0} of {1} from client {2}", nSegmentNumber, nMaxSegment, info.client);
fs.Position = fs.Length;
fs.Write(info.Buffer, 8, bySize-8);
if (nSegmentNumber >= nMaxSegment)
{
Console.WriteLine("Completed receipt from client {0}", info.client);
}
}
info.Socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void Main(string[] args)
{
try
{
Console.WriteLine("Server");
IPAddress address = IPAddress.Parse("127.0.0.1"); //The IP address of the server
IPEndPoint myEndPoint = new IPEndPoint(address, 6503);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(myEndPoint);
serverSocket.Listen(1000);
for (int n = 0; n < 10; ++n)
{
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
Console.WriteLine("Server now waiting");
Console.ReadLine();
foreach (ConnectionInfo info in list)
{
string strFileName = string.Format(#"c:\temp\from-client-{0}.dat", info.client);
using (FileStream fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
int nMaxChunk = 0;
int nCurrentChunk = 0;
nMaxChunk = (int)(fs.Length / chucksizeWithoutHeaderData);
if ((nMaxChunk * chucksizeWithoutHeaderData) < fs.Length)
{
++nMaxChunk;
}
using (BinaryReader br = new BinaryReader(fs))
{
byte[] byBuffer;
Int64 nAmount = 0;
byte[] byMaxChunk = BitConverter.GetBytes(nMaxChunk);
while (fs.Length > nAmount)
{
++nCurrentChunk;
byte[] byCurrentChunk = BitConverter.GetBytes(nCurrentChunk);
byBuffer = br.ReadBytes(chucksizeWithoutHeaderData);
Console.WriteLine("Sending {0}bytes, chunk {1} of {2} to client {3}", byBuffer.Length,nCurrentChunk,nMaxChunk, info.client);
byte [] byTransmitBuffer = new byte[byBuffer.Length + 8];
Array.Copy(byCurrentChunk, byTransmitBuffer, 4);
Array.Copy(byMaxChunk, 0,byTransmitBuffer, 4, 4);
Array.Copy(byBuffer, 0, byTransmitBuffer, 8, byBuffer.Length);
info.Socket.Send(byTransmitBuffer);
nAmount += byBuffer.Length;
}
}
}
}
Console.WriteLine("Press enter to end server");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
}
}
Client code
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace SocketClient
{
class Program
{
static TcpClient socket = new TcpClient();
static int chunkSize = 16 * 1024;
static int chucksizeWithoutHeaderData = chunkSize - 8;
static byte[] byReceiveBuffer = new byte[chunkSize];
static void ReceiveCallBack(IAsyncResult result)
{
Socket socket = result.AsyncState as Socket;
try
{
int bySize = socket.EndReceive(result);
Console.WriteLine("Recieved bytes {0}", bySize);
if (bySize != 0)
{
Int32 nSegmentNumber = BitConverter.ToInt32(byReceiveBuffer, 0);
Int32 nMaxSegment = BitConverter.ToInt32(byReceiveBuffer, 4);
Console.WriteLine("Received segment {0} of {1}", nSegmentNumber, nMaxSegment);
string strFileName = string.Format(#"c:\temp\client-from-server.dat");
using (FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate))
{
fs.Position = fs.Length;
fs.Write(byReceiveBuffer, 8, bySize-8);
}
if (nSegmentNumber >= nMaxSegment)
{
Console.WriteLine("all done");
}
}
socket.BeginReceive(byReceiveBuffer, 0, byReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void Main(string[] args)
{
Console.WriteLine("Press enter to go");
Console.ReadLine();
socket.Connect("127.0.0.1", 6503);
Console.WriteLine("Client");
Console.ReadLine();
byte[] byBuffer;
socket.Client.BeginReceive(byReceiveBuffer, 0, byReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket.Client);
using (FileStream fs = new FileStream(#"c:\temp\filetosend.jpg", FileMode.Open, FileAccess.Read, FileShare.None))
{
using (BinaryReader br = new BinaryReader(fs))
{
int nMaxChunk = 0;
int nCurrentChunk = 0;
nMaxChunk = (int)(fs.Length / chucksizeWithoutHeaderData);
if ((nMaxChunk * chucksizeWithoutHeaderData) < fs.Length)
{
++nMaxChunk;
}
byte[] byMaxChunk = BitConverter.GetBytes(nMaxChunk);
Int64 nAmount = 0;
while (fs.Length > nAmount)
{
++nCurrentChunk;
byte[] byCurrentChunk = BitConverter.GetBytes(nCurrentChunk);
byBuffer = br.ReadBytes(chucksizeWithoutHeaderData);
Console.WriteLine("Sending {0}bytes, chunk {1} of {2}", byBuffer.Length, nCurrentChunk, nMaxChunk);
byte[] byTransmitBuffer = new byte[byBuffer.Length + 8];
Array.Copy(byCurrentChunk, byTransmitBuffer, 4);
Array.Copy(byMaxChunk, 0, byTransmitBuffer, 4, 4);
Array.Copy(byBuffer, 0, byTransmitBuffer, 8, byBuffer.Length);
socket.Client.Send(byTransmitBuffer);
nAmount += byBuffer.Length;
}
}
}
Console.WriteLine("done");
Console.ReadLine();
}
}
}
Since you are modifyng the infrastructure, use an FTP library in C# and install some free FTP server ( ie FileZilla or anyone else ). You can easily use some FTP library as for example this one that is reliable ( i used it on production code ).
Socket programming can be tricky. If you send 100 bytes, it doesn't mean you will receive 100 bytes in your server. You can receive those 100 bytes in multiple packets, you have to add code to control that.
I said that because of this line in your server code:
fs.Write(info.Buffer, 8, bySize-8);
you are assuming you will receive at least 8 bits and it can be wrong. bySize can be smaller than your chunk size (and it can be zero if the connection has been closed by the client or <0 if there was an error.)
About your error, I tested your code and I could replicate your problem:
start the server
start the client and transfer the file
exit the client pressing enter
the server crashes
The server crashes because the socket is waiting for more data after all the file is transferred. And the client closed it.
I solved the problem closing the connection in the client after the file is sent:
socket.Client.Disconnect(false);
Then the server receives bySize=0 bytes, meaning that the connection was closed. In the server I replaced this:
int bySize = socket.EndReceive(result);
for this:
int bySize = 0;
try
{
bySize = info.Socket.EndReceive(result);
}
catch (Exception ex)
{
Console.WriteLine("Error from client {0}: {1}", info.client, ex.Message);
return;
}
if (bySize <= 0)
return;
Have a look here: http://msdn.microsoft.com/en-us/library/5w7b7x5f.aspx#Y240
and here: http://msdn.microsoft.com/en-us/library/fx6588te.aspx
EDIT: I forgot to mention this, you only need to call BeginAccept once. I removed the for statement.
// for (int n = 0; n < 10; ++n)
// {
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
// }
I think that I may have a solution - although I am not 100% confident...I will keep testing and report back if it fails.
Anyways - I have set the socket.SendBufferSize and RecieveBufferSize to 4 x the chunk size, and now all seems to be well.
The thing there (re buffer size) just put the problem off, as I thought it might.
However, I came across a snippet of code elsewhere, and putting these lines into the code fixed the issue.
try
{
bySent = info.Socket.Send(byTransmitBuffer);
}
catch (SocketException ex)
{
Console.WriteLine("Only sent {0}, remaining = {1}", bySent,fs.Length -nAmount);
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}

How can i get more than one jpg. or txt file from any folder?

i have two Application to listen network Stream : Server.cs on the other hand; send file Client.cs. But i want to send more files on a stream from any folder. For example. i have C:/folder whish has got 3 jpg files. My client must run. Also My server.cs get files on stream:
Client.cs:
private void btn_send2_Click(object sender, EventArgs e)
{
string[] paths= null;
paths= System.IO.Directory.GetFiles(#"C:\folder" + #"\", "*.jpg", System.IO.SearchOption.AllDirectories);
byte[] Dizi;
TcpClient Gonder = new TcpClient("127.0.0.1", 51124);
FileStream Dosya;
FileInfo Dos;
NetworkStream Akis;
foreach (string path in paths)
{
Dosya = new FileStream(path , FileMode.OpenOrCreate);
Dos = new FileInfo(path );
Dizi = new byte[(int)Dos.Length];
Dosya.Read(Dizi, 0, (int)Dos.Length);
Akis = Gonder.GetStream();
Akis.Write(Dizi, 0, (int)Dosya.Length);
Gonder.Close();
Akis.Flush();
Dosya.Close();
}
}
Also i have Server.cs
void Dinle()
{
TcpListener server = null;
try
{
Int32 port = 51124;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[1024 * 250000];
// string ReceivedPath = "C:/recieved";
while (true)
{
MessageBox.Show("Waiting for a connection... ");
TcpClient client = server.AcceptTcpClient();
MessageBox.Show("Connected!");
NetworkStream stream = client.GetStream();
if (stream.CanRead)
{
saveFileDialog1.ShowDialog();
// burası degişecek
string pathfolder = saveFileDialog1.FileName;
StreamWriter yaz = new StreamWriter(pathfolder);
string satir;
StreamReader oku = new StreamReader(stream);
while ((satir = oku.ReadLine()) != null)
{
satir = satir + (char)13 + (char)10;
yaz.WriteLine(satir);
}
oku.Close();
yaz.Close();
client.Close();
}
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
Please look Client.cs: icollected all files from "c:\folder"
paths= System.IO.Directory.GetFiles(#"C:\folder" + #"\", "*.jpg", System.IO.SearchOption.AllDirectories);
My Server.cs how to get all files from stream?
It's not a typical way of doing things.
Usually you would write a single file in a single stream and repeat the process for multiple files. You risk data corruption this way as you'll have to place some kind of marker in the stream to know where to split it.
The easiest way is to use multiple sockets, one for commands and one (or more) for sending files.
The below code have NOT been tested, just wrote it up to show what I mean. It's multithreaded and can receive multiple files from the same client, just call sendfiles multiple times in the client.
You might want to add error/exception handling if you decide to finish the code.
Server.cs
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Test2
{
public class Server
{
private readonly TcpListener _listener = new TcpListener(1234);
public void Start()
{
_listener.BeginAcceptTcpClient(OnClient, null);
}
private void OnClient(IAsyncResult ar)
{
// End async accept and start wait for a new connection again
TcpClient client = _listener.EndAcceptTcpClient(ar);
_listener.BeginAcceptTcpClient(OnClient, null);
// Let's start receiving files from the accepted client.
var context = new Context {Client = client, Buffer = new byte[8196]};
client.GetStream().BeginRead(context.Buffer, 0, context.Buffer.Length, OnReceive, context);
}
/// <summary>
/// Got some stuff from a client
/// </summary>
/// <param name="ar"></param>
private void OnReceive(IAsyncResult ar)
{
// got a file command
var context = (Context) ar.AsyncState;
int bytesRead = context.Client.GetStream().EndRead(ar);
string cmd = Encoding.UTF8.GetString(context.Buffer, 0, bytesRead);
string[] parts = cmd.Split(';');
string command = parts[0];
// want to send another file
if (command == "sendfile")
{
// context info for receiving files
var client = new FileClient();
client.FileName = parts[1];
client.Size = long.Parse(parts[2]);
client.FileStream = new FileStream("C:\\" + client.FileName, FileMode.CreateNew, FileAccess.Write);
// startup listener where we are going to receive the file.
var listener = new TcpListener(IPAddress.Any, 0); // get a kernelassigned number
client.Listener = listener;
listener.Start();
listener.BeginAcceptTcpClient(OnFileSocket, client);
// send reply
var ep = (IPEndPoint) listener.LocalEndpoint;
byte[] reply = Encoding.UTF8.GetBytes(ep.Port.ToString());
context.Client.GetStream().Write(reply, 0, reply.Length);
}
}
// Receiving the actual files.
private void OnFileSocket(IAsyncResult ar)
{
var client = (FileClient) ar.AsyncState;
client.Socket = client.Listener.EndAcceptTcpClient(ar);
var buffer = new byte[8192];
client.Buffer = buffer;
client.Socket.GetStream().BeginRead(buffer, 0, buffer.Length, OnReceiveFile, client);
}
private void OnReceiveFile(IAsyncResult ar)
{
var client = (FileClient) ar.AsyncState;
int bytesRead = client.Socket.GetStream().EndRead(ar);
client.Received += bytesRead;
client.FileStream.Write(client.Buffer, 0, bytesRead);
// recieved complete file, disconnect and exit.
if (client.Received == client.Size)
{
client.FileStream.Close();
client.Socket.Close();
return;
}
client.Socket.GetStream().BeginRead(client.Buffer, 0, client.Buffer.Length, OnReceiveFile, client);
}
#region Nested type: Context
private class Context
{
public byte[] Buffer;
public TcpClient Client;
}
#endregion
#region Nested type: FileClient
private class FileClient
{
public byte[] Buffer;
public string FileName;
public FileStream FileStream;
public TcpListener Listener;
public long Received;
public long Size;
public TcpClient Socket;
}
#endregion
}
}
Client.cs
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Test2
{
internal class Client
{
private readonly IPAddress _server;
private readonly TcpClient _tcpClient = new TcpClient();
public Client(IPAddress server)
{
_server = server;
_tcpClient = new TcpClient();
}
public void Connect()
{
_tcpClient.Connect(new IPEndPoint(_server, 1234));
}
// asks server on which port the file should be sent.
private int RequestPort(string fileName, long length)
{
// lock tpcClient for each request, so we dont mix up the responses.
lock (_tcpClient)
{
// send request
byte[] bytes = Encoding.UTF8.GetBytes("sendfile;" + fileName + ";" + length);
_tcpClient.GetStream().Write(bytes, 0, bytes.Length);
// get reply
var buffer = new byte[1024];
int bytesRead = _tcpClient.GetStream().Read(buffer, 0, buffer.Length);
string reply = Encoding.UTF8.GetString(buffer, 0, bytesRead);
// error message or port?
int port;
if (!int.TryParse(reply, out port))
throw new InvalidOperationException("Server sent an error:" + reply);
return port;
}
}
public void SendFiles(string[] fileNames)
{
// Use a buffer to not preserve memory (instead of reading whole file into memory)
var buffer = new byte[8192];
foreach (string fileName in fileNames)
{
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Send on commandchannel that we want to send a file.
int filePort = RequestPort(Path.GetFileName(fileName), fileStream.Length);
var client = new TcpClient(new IPEndPoint(_server, filePort));
NetworkStream stream = client.GetStream();
// repeat until there are no more bytes to read.
int bytesRead = fileStream.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
stream.Write(buffer, 0, bytesRead);
bytesRead = fileStream.Read(buffer, 0, buffer.Length);
}
stream.Close();
client.Close();
}
}
}
}
}

Categories