Here is my server code for reading a mp4 file and sending to the client
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 3400);
sock.Bind(ep);
sock.Listen(10);
sock = sock.Accept();
FileStream fs = new FileStream(#"E:\Entertainment\Songs\Video song\song.mp4",FileMode.Open);
BinaryReader br = new BinaryReader(fs);
byte[] data = new byte[fs.Length];
br.Read(data, 0, data.Length);
sock.Send(data);
fs.Close();
sock.Close();
Here is the client code
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3400);
sock.Connect(ep);
MemoryStream ms = new MemoryStream();
int size = 3190551; // I know the file size is about 30 mb
int rec;
while (size > 0)
{
byte[] buffer;
if (size < sock.ReceiveBufferSize)
{
buffer = new byte[size];
}
else
{
buffer = new byte[sock.ReceiveBufferSize];
}
rec = sock.Receive(buffer, 0, buffer.Length, 0);
size = size - rec;
ms.Write(buffer, 0, buffer.Length);
}
byte[] data = ms.ToArray();
FileStream fs = new FileStream("E:/song.mp4",FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs)
bw.Write(data);
fs.Close();
sock.Close();
**At the end i just get the data in between 3 to 4 mb.... im new to socket programming and I don't know where the problem is... whether its sending side or receiving !!!! it looks like I just receive a single chunk of data from the server side **
I think the problem is here
int size = 3190551; // I know the file size is about 30 mb
you are reading just 3190551 byte which is 3.04mb not 30mb.
try to send length of your file at the beginning of your message so client will know how many bytes it should get from server.
Related
I'm creating a file transfer app which works with TcpListener and TcpClient. My app works perfectly, I'm just wondering how I can show the download/upload speed while data is transferring. I also want the app to show how many MBs are downloaded or uploaded.
Server code:
IPAddress ip = IPAddress.Parse("192.168.1.2");
int port = 9999;
TcpListener server = new TcpListener(ip, port);
server.Start();
Console.WriteLine("Waiting for client...");
TcpClient tcpClient = server.AcceptTcpClient();
Console.WriteLine("Client connected!");
NetworkStream networkStream = tcpClient.GetStream();
string path = string.Empty;
string fileName = string.Empty;
Console.Write("File:");
path = Console.ReadLine();
fileName = Path.GetFileName(path);
byte[] bytes = File.ReadAllBytes(path);
BinaryWriter bwFileName = new BinaryWriter(networkStream);
bwFileName.Write(fileName);
BinaryWriter bw = new BinaryWriter(networkStream);
bw.Write(bytes.Length);
networkStream.Write(bytes, 0, bytes.Length);
Console.ReadLine();
Client code:
IPAddress ip = IPAddress.Parse("192.168.1.2");
int port = 9999;
TcpClient client = new TcpClient();
client.Connect(ip, port);
while (true)
{
NetworkStream networkStream = client.GetStream();
int byteLenght;
string fileName = string.Empty;
BinaryReader brFilename = new BinaryReader(networkStream);
fileName = brFilename.ReadString();
BinaryReader br = new BinaryReader(networkStream);
byteLenght = br.ReadInt32();
byte[] bytes = new byte[byteLenght];
networkStream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes("C:\\Users\\XANDRO\\Desktop\\client\\" + fileName,bytes);
break;
}
Console.ReadLine();
the general approach would be to split the download/upload into chunks. I.e. instead of writing the entire byte array in one go, write chunks using the offset/length parameters.
This gives an opportunity to measure the time and report the progress after each chunk. You might also consider using a file stream and write/read chunks from this as well. Since this will limit memory usage.
Edit: Example code:
public static void Copy(Stream from, Stream to, IProgress<int> progress, int bufferSize = 4096)
{
var bytesCopied = 0;
var buffer = new byte[bufferSize];
int bytesRead;
do
{
bytesRead = from.Read(buffer, 0, buffer.Length);
to.Write(buffer, 0, bytesRead);
bytesCopied += bytesRead;
progress.Report(bytesCopied);
} while (bytesRead != 0);
}
I have Client layer and Server Layer. Client send converted to byte array integer varible.
I am using TcpClient and TcpListener, and use NetworkStream to write and read data. For some reason Server do not read data from NetworkStream, inspite that i use advice from this question: How to get all data from NetworkStream
Client Layer:
TcpClient sender1 = new TcpClient();
sender1.Connect(ip, port);
using (NetworkStream stream1 = client.GetStream())
{
int isCorrect = 1;
byte[] data = BitConverter.GetBytes(isCorrect);
stream1.Write(data, 0, data.Length);
}
sender1.Close();
Server Layer
TcpListener server = new TcpListener(IPAddress.Parse(ip), serverPort);
server.Start();
while (true)
{
TcpClient enterWaiter = server.AcceptTcpClient();
using (NetworkStream stream1 = enterWaiter.GetStream())
{
byte[] buffer = new byte[4];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = stream1.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
Console.WriteLine($"{ms.ToArray()}");
}
}
server.Stop();
break;
}
It is because you are closing the server prior to receiving your data, move or remove the Server.Stop and break lines, such as:
TcpListener server = new TcpListener(IPAddress.Parse(ip), serverPort);
server.Start();
while (true)
{
TcpClient enterWaiter = server.AcceptTcpClient();
using (NetworkStream stream1 = enterWaiter.GetStream())
{
byte[] buffer = new byte[4];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = stream1.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
Console.WriteLine($"{ms.ToArray()}");
}
}
//server.Stop(); <-- (Re)move
//break; <-- (Re)move
}
private byte[] ResponseAsync(byte[] buffer, string ip, int port)
{
byte[] buffer_ = new byte[10000]; // receiving buffer 10KB
TcpClient client = new TcpClient(ip, port);
NetworkStream stream = client.GetStream();
stream.Write(buffer, 0, buffer.Length);
//await write;
int i = 0;
while (stream.DataAvailable)
{
MessageBox.Show(i.ToString());
i = stream.Read(buffer_, 0, 1024);
}
return buffer_.Take(i).ToArray();
}
the code was async but I thought I was doing somethign wrong so made it synchrone
You're overwriting the beginning of your buffer each time you do a read and will only return the data read in the last iteration of the while loop.
As such you'll need to increment i with the amount of data read and then use that as the offset when copying data in to your buffer.
private byte[] ResponseAsync(byte[] buffer, string ip, int port)
{
byte[] buffer_ = new byte[10000]; // receiving buffer 10KB
TcpClient client = new TcpClient(ip, port);
NetworkStream stream = client.GetStream();
stream.Write(buffer, 0, buffer.Length);
//await write;
int i = 0;
while (stream.DataAvailable)
{
MessageBox.Show(i.ToString());
// write data to the appropriate point in buffer_ and update i
i += stream.Read(buffer_, i, 1024);
}
return buffer_.Take(i).ToArray();
}
Be aware though that if you receive more than 10,000 bytes this will throw an exception.
The chances are that you'll not read all the data from the stream as stream.DataAvailable will only say whether there's data available to be read not that the stream has finished.
To put my toe in the water of Network programming, I wrote a little Console App to send a png file to a server (another console app). The file being written by the server is slightly bigger than the source png file. And it will not open.
The code for the client app is:
private static void SendFile()
{
using (TcpClient tcpClient = new TcpClient("localhost", 6576))
{
using (NetworkStream networkStream = tcpClient.GetStream())
{
//FileStream fileStream = File.Open(#"E:\carry on baggage.PNG", FileMode.Open);
byte[] dataToSend = File.ReadAllBytes(#"E:\carry on baggage.PNG");
networkStream.Write(dataToSend, 0, dataToSend.Length);
networkStream.Flush();
}
}
}
The code for the Server app is :
private static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(Listen));
thread.Start();
Console.WriteLine("Listening...");
Console.ReadLine();
}
private static void Listen()
{
IPAddress localAddress = IPAddress.Parse("127.0.0.1");
int port = 6576;
TcpListener tcpListener = new TcpListener(localAddress, port);
tcpListener.Start();
using (TcpClient tcpClient = tcpListener.AcceptTcpClient())
{
using (NetworkStream networkStream = tcpClient.GetStream())
{
using (Stream stream = new FileStream(#"D:\carry on baggage.PNG", FileMode.Create, FileAccess.ReadWrite))
{
// Buffer for reading data
Byte[] bytes = new Byte[1024];
var data = new List<byte>();
int length;
while ((length = networkStream.Read(bytes, 0, bytes.Length)) != 0)
{
var copy = new byte[length];
Array.Copy(bytes, 0, copy, 0, length);
data.AddRange(copy);
}
BinaryFormatter binaryFormatter = new BinaryFormatter();
stream.Position = 0;
binaryFormatter.Serialize(stream, data.ToArray());
}
}
}
tcpListener.Stop();
The size of the written file is 24,103Kb, whereas the source file is only 24,079Kb.
Is it apparent to anyone why this operation is failing?
Cheers
You are writing your output using a BinaryFormatter. I'm pretty sure that this will add some bytes at the start of the output to indicate the type that you're outputting (in this case System.Byte[]).
Just write the bytes out directly to the file without using the formatter:
using (Stream stream = new FileStream(#"D:\carry on baggage.PNG", FileMode.Create, FileAccess.ReadWrite))
{
// Buffer for reading data
Byte[] bytes = new Byte[1024];
int length;
while ((length = networkStream.Read(bytes, 0, bytes.Length)) != 0)
{
stream.Write(bytes, 0, length);
}
}
I am trying to receive the image form Server and want to display it into a Picturebox in WM Application. I am successfully receiving the Image Stream and I don’t find any way to display it into a PictureBox. In windows program we have a method in Image class that is FromStream (Image.FromStream) but this function is not available in Compact Framework 3.5. I also tried the following code to do so:
private void button1_Click(object sender, EventArgs e)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress IP = IPAddress.Parse("192.168.1.2");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
s.Connect(IPE);
byte[] buffer = new byte[55296];
s.Receive(buffer, buffer.Length, SocketFlags.None);
MemoryStream ms = new MemoryStream(buffer);
Image im = new Bitmap(ms); //EXCEPTION
pictureBox1.Image = im;
}
But it gives an Exception. No detail is provided with the exception and VS is only displaying a dialogbox with the text "Exception".
Does your image size is less than the size of the buffer? If not all the excess data is lost and an exception is thrown.
Also could you try without the buffer length specified.
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
IPAddress IP = IPAddress.Parse("192.168.1.2");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
s.Connect(IPE);
byte[] buffer = new byte[55296];
int rec = s.Receive(buffer, SocketFlags.None);
using (MemoryStream ms = new MemoryStream(buffer, 0, rec))
{
Image im = new Bitmap(ms);
pictureBox1.Image = im;
}
}
You do have to check the return value of the socket's Receive method in order to determine
how large your bitmap buffer is:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress IP = IPAddress.Parse("192.168.1.2");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
s.Connect(IPE);
byte[] buffer = new byte[55296];
int rec = s.Receive(buffer, buffer.Length, SocketFlags.None);
MemoryStream ms = new MemoryStream(buffer, 0, rec);
Image im = new Bitmap(ms);
pictureBox1.Image = im;
Hope, this helps.