Retrieve partially downloaded byte chunks from DownloadDataAsync - c#

I need to download a binary file and access the raw data as it arrives.
private void Downloadfile(string url)
{
WebClient client = new WebClient();
client.DownloadDataCompleted += DownloadDataCompleted;
client.DownloadProgressChanged += DownloadProgressCallback;
client.DownloadDataAsync(new Uri(url));
}
public void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
long bytes = e.BytesReceived;
long total = e.TotalBytesToReceive;
int progress = e.ProgressPercentage;
string userstate = (string)e.UserState;
byte[] received = ?
}
Alternatively, writing to a stream would also be helpful. I don't mind using another download method either, the primary goal is to read a download on the fly.

You can use the WebClient.OpenRead as suggested by Søren Lorentzen
using (var client = new WebClient())
using (var stream = client.OpenRead(address))
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
}
}

Related

C# file transfer with tcpclient and server

When I send a file with the code below, some data (small amout) is missing. The file size doess not match on the receiver side. Sending a regular string is fine so theres no connection issue here. Im just looking for a minimal improvement to fix the issue, I will add error checking etc later. Thanks! The code is mostly copied from some tutorial but i dont remember which though...
Client is the std .Net TcpClient class
Client.Client is it's socket
public void SendFile2(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
{
byte[] lenBytes = BitConverter.GetBytes((int)fs.Length);
Client.Client.Send(lenBytes);
byte[] buffer = new byte[1024];
int bytesRead;
fs.Position = 0;
while ((bytesRead = fs.Read(buffer, 0, 1024)) > 0)
Client.Client.Send(buffer, bytesRead, SocketFlags.None);
}
}
public bool ReceiveFile2(string fileName)
{
using (FileStream fs = File.Create(fileName))
{
byte[] lenBytes = new byte[4];
if (Client.Client.Receive(lenBytes) < 4)
return false;
long len = BitConverter.ToInt32(lenBytes, 0);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = Client.Client.Receive(buffer)) > 0)
fs.Write(buffer, 0, bytesRead);
return len == fs.Position;
}
}
SOLUTION:
public void SendFile(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
{
byte[] lenBytes = BitConverter.GetBytes((int)fs.Length);
Client.Client.Send(lenBytes);
byte[] buffer = new byte[1024];
int bytesRead;
fs.Position = 0;
while ((bytesRead = fs.Read(buffer, 0, 1024)) > 0)
Client.Client.Send(buffer, bytesRead, SocketFlags.None);
}
}
public bool ReceiveFile(string fileName)
{
using (FileStream fs = File.Create(fileName))
{
byte[] lenBytes = new byte[4];
if (Client.Client.Receive(lenBytes) < 4)
return false;
long len = BitConverter.ToInt32(lenBytes, 0);
byte[] buffer = new byte[1024];
int bytesRead;
// Changed from here
while (fs.Position < len)
{
bytesRead = Client.Client.Receive(buffer);
fs.Write(buffer, 0, bytesRead);
}
// To here
return len == fs.Position;
}
}
I think this line can be a problem.
if (Client.Client.Receive(lenBytes) < 4)
and
while ((bytesRead = Client.Client.Receive(buffer)) > 0)
You have two receives in your code.
So you drop first bytes.
That can explain the differences you see in files sizes.

C# Multi threaded Server

I have this client and server code.
Client:
namespace ClientTest
{
internal class Program
{
private static TcpClient client;
private static NetworkStream stream;
private static void Main(string[] args)
{
string temp;
client = new TcpClient("192.168.1.2",5052);
stream = client.GetStream();
Console.WriteLine(client.SendBufferSize);
while ((temp = Console.ReadLine()) != "exit")
{
Send(temp);
}
Thread one=new Thread(()=> SendFile(new FileInfo(#"1.doc")));
one.Start();
Thread two=new Thread(()=> SendFile(new FileInfo(#"2.docx")));
two.Start();
// Console.ReadKey(true);
}
public static void SendFile(FileInfo file)
{
stream = client.GetStream();
byte[] id = BitConverter.GetBytes((ushort)1);
byte[] size = BitConverter.GetBytes(file.Length);
byte[] fileName = Encoding.UTF8.GetBytes(file.Name);
byte[] fileNameLength = BitConverter.GetBytes((ushort)fileName.Length);
byte[] fileInfo = new byte[12 + fileName.Length];
id.CopyTo(fileInfo, 0);
size.CopyTo(fileInfo, 2);
fileNameLength.CopyTo(fileInfo, 10);
fileName.CopyTo(fileInfo, 12);
stream.Write(fileInfo, 0, fileInfo.Length); //Размер файла, имя
byte[] buffer = new byte[1024 * 32];
int count;
long sended = 0;
using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open))
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, count);
sended += count;
Console.WriteLine("{0} bytes sended.", sended);
}
stream.Flush();
}
private static void Send(string message)
{
byte[] id = BitConverter.GetBytes((ushort)0);
byte[] msg = Encoding.UTF8.GetBytes(message);
byte[] msgLength = BitConverter.GetBytes((ushort)msg.Length);
byte[] fileInfo = new byte[12 + msg.Length];
id.CopyTo(fileInfo, 0);
msgLength.CopyTo(fileInfo, 10);
msg.CopyTo(fileInfo, 12);
stream.Write(fileInfo, 0, fileInfo.Length);
stream.Flush();
}
}
}
Server:
namespace Server_Test
{
class Server
{
static void Main(string[] args)
{
Server serv = new Server();
}
private TcpListener listener { get; set; }
private NetworkStream stream { get; set; }
public Server()
{
listener = new TcpListener(IPAddress.Parse("192.168.1.2"), 5052);
listener.Start();
new Thread(ListenForClients).Start();
}
private void ListenForClients()
{
while (true)
{
TcpClient client = this.listener.AcceptTcpClient();
new Thread(HandleClient).Start(client);
}
}
private void HandleClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
while (client.Connected)
{
Recieve(client);
}
}
private void Recieve(TcpClient client)
{
byte[] buffer = new byte[client.ReceiveBufferSize];
try
{
stream = client.GetStream();
int bytesRead = stream.Read(buffer, 0, 12);
if (bytesRead == 0) return;
ushort id = BitConverter.ToUInt16(buffer, 0);
long len = BitConverter.ToInt64(buffer, 2);
ushort nameLen = BitConverter.ToUInt16(buffer, 10);
stream.Read(buffer, 0, nameLen);
string fileName = Encoding.UTF8.GetString(buffer, 0, nameLen);
if (id == 1)
{
using (BinaryWriter writer = new BinaryWriter(new FileStream(fileName, FileMode.Create)))
{
int recieved = 0;
while (recieved < len)
{
bytesRead = stream.Read(buffer, 0, client.ReceiveBufferSize);
recieved += bytesRead;
writer.Write(buffer, 0, bytesRead);
Console.WriteLine("{0} bytes recieved.", recieved);
}
}
Console.WriteLine("File length: {0}", len);
Console.WriteLine("File Name: {0}", fileName);
Console.WriteLine("Recieved!");
}
else
{
Console.WriteLine(fileName);
}
}
catch (Exception ex)
{
stream.Close();
client.Close();
Console.WriteLine(ex);
}
finally
{
stream.Flush();
}
}
}
}
The problem:i can't send 2 files in threads. If i send 1 file, server receives it and correctly saves.
What changes needed in this code to let client transfer 2 or more files and to let server receive it?
UDP. Added modified SendFile, but in doesn't work.
public static void SendFile(FileInfo file)
{
TcpClient client;
NetworkStream stream;
client = new TcpClient("192.168.1.2", 5052);
stream = client.GetStream();
byte[] id = BitConverter.GetBytes((ushort)1);
byte[] size = BitConverter.GetBytes(file.Length);
byte[] fileName = Encoding.UTF8.GetBytes(file.Name);
byte[] fileNameLength = BitConverter.GetBytes((ushort)fileName.Length);
byte[] fileInfo = new byte[12 + fileName.Length];
id.CopyTo(fileInfo, 0);
size.CopyTo(fileInfo, 2);
fileNameLength.CopyTo(fileInfo, 10);
fileName.CopyTo(fileInfo, 12);
stream.Write(fileInfo, 0, fileInfo.Length); //Размер файла, имя
byte[] buffer = new byte[1024 * 32];
int count;
long sended = 0;
using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open))
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, count);
sended += count;
Console.WriteLine("{0} bytes sended.", sended);
}
}
On the client side, your two separate sending threads cannot share the same instance of client = new TcpClient("192.168.1.2",5052); to simultaneously send data. Each thread should have its own instance. Note, however, that it is fine for 2 client sockets to hit the same server-side IP:port simultaneously. It is just that the outbound port on the client-side has to be different between the 2 connections. When you create an additional outbound TCP connection on the client, the TcpClient will automatically use the next available outbound port.
For example, you could try something like the following:
internal class Program
{
private static void Main(string[] args)
{
SenderThreadClass stc1 = SenderThreadClass("192.168.1.2", 5052);
SenderThreadClass stc2 = SenderThreadClass("192.168.1.2", 5052);
Thread one = new Thread(()=> stc1.SendFile(new FileInfo(#"1.doc")));
one.Start();
Thread two = new Thread(()=> stc2.SendFile(new FileInfo(#"2.docx")));
two.Start();
}
}
public class SenderThreadClass
{
private TcpClient client;
private NetworkStream stream;
public SenderThreadClass(string serverIP, int serverPort)
{
client = new TcpClient(serverIP, serverPort);
stream = client.GetStream();
}
public void SendFile(FileInfo file)
{
byte[] id = BitConverter.GetBytes((ushort)1);
byte[] size = BitConverter.GetBytes(file.Length);
byte[] fileName = Encoding.UTF8.GetBytes(file.Name);
byte[] fileNameLength = BitConverter.GetBytes((ushort)fileName.Length);
byte[] fileInfo = new byte[12 + fileName.Length];
id.CopyTo(fileInfo, 0);
size.CopyTo(fileInfo, 2);
fileNameLength.CopyTo(fileInfo, 10);
fileName.CopyTo(fileInfo, 12);
stream.Write(fileInfo, 0, fileInfo.Length); //Размер файла, имя
byte[] buffer = new byte[1024 * 32];
int count;
long sended = 0;
using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open))
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, count);
sended += count;
Console.WriteLine("{0} bytes sended.", sended);
}
stream.Flush();
}
}

Download a torrent file result is corrupt WP8

in an app I am making some of the files required are torrent files but i'm having an odd issue, whenever I download a torrent file through the app the files ends up corrupt and wont open in any torrent app, I used wptools to extract them to a pc and test it and still corrupt here is my code I can't see what 'im doing wrong, I am fairly new to using webclient. I assume it has something to do with the way im saving the file any help would be great thanks.
private void tbLink_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
string[] linkInfo = (sender as TextBlock).Tag as string[];
fileurl = linkInfo[0];
System.Diagnostics.Debug.WriteLine(fileurl);
WebClient client = new WebClient();
client.OpenReadCompleted += client_OpenReadCompleted;
client.OpenReadAsync(new Uri(fileurl), linkInfo);
client.AllowReadStreamBuffering = true;
}
async void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
string[] linkInfo = e.UserState as string[];
filetitle = linkInfo[1];
filesave = (filetitle);
var isolatedfile = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream stream = isolatedfile.OpenFile(filesave, System.IO.FileMode.Create))
{
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
}
try
{
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile torrentfile = await local.GetFileAsync(filesave);
Windows.System.Launcher.LaunchFileAsync(torrentfile);
}
catch (Exception)
{
MessageBox.Show("File Not Found");
}
This is incorrect:
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
The Read method will return the number of bytes read, it can be less than buffer.Length. So the code should read:
int byteCount;
// Select an appropriate buffer size.
// This is a buffer, not space for the entire file.
byte[] buffer = new byte[4096];
while ((byteCount = e.Result.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, byteCount);
}
UPDATE: If the data is compressed, as in the question that you posted in your comment, then you can decompress the stream:
int byteCount;
byte[] buffer = new byte[4096];
using (GZipStream zs = new GZipStream(e.Result, CompressionMode.Decompress))
{
while ((byteCount = zs.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, byteCount);
}
}
Note that I have not tested this code, I'm assuming that e.Result is a stream.

ReadAsync get data from buffer

I've been banging my head around this for some while (and know it's something silly).
I'm downloading files with a ProgressBar which shows fine, but how do I get the data from the ReadAsync Stream to save?
public static readonly int BufferSize = 4096;
int receivedBytes = 0;
int totalBytes = 0;
WebClient client = new WebClient();
byte[] result;
using (var stream = await client.OpenReadTaskAsync(urlToDownload))
{
byte[] buffer = new byte[BufferSize];
totalBytes = Int32.Parse(client.ResponseHeaders[HttpResponseHeader.ContentLength]);
for (;;)
{
result = new byte[stream.Length];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
await Task.Yield();
break;
}
receivedBytes += bytesRead;
if (progessReporter != null)
{
DownloadBytesProgress args =
new DownloadBytesProgress(urlToDownload, receivedBytes, totalBytes);
progessReporter.Report(args);
}
}
}
I was trying via the result var, but that is obviously wrong. I'd appreciate any pointers on this long Sunday afternoon.
The content that was downloaded is inside your byte[] buffer variable:
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
From Stream.ReadAsync:
buffer:
Type: System.Byte[]
The buffer to write the data into.
You never use your result variable at all. Not sure why its there.
Edit
So the problem is how to read the full content of your stream. You can do the following:
public static readonly int BufferSize = 4096;
int receivedBytes = 0;
WebClient client = new WebClient();
using (var stream = await client.OpenReadTaskAsync(urlToDownload))
using (MemoryStream ms = new MemoryStream())
{
var buffer = new byte[BufferSize];
int read = 0;
totalBytes = Int32.Parse(client.ResponseHeaders[HttpResponseHeader.ContentLength]);
while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
receivedBytes += read;
if (progessReporter != null)
{
DownloadBytesProgress args =
new DownloadBytesProgress(urlToDownload, receivedBytes, totalBytes);
progessReporter.Report(args);
}
}
return ms.ToArray();
}
}
The data you read should be in the buffer array. Actually the beginning bytesRead bytes of the array. Check ReadAsync method on MSDN.

Base64 from e.ChosenPhoto apparently corrupted

//convert photo to baos
var memoryStream = new System.IO.MemoryStream();
e.ChosenPhoto.CopyTo(memoryStream);
//string baos = memoryStream.ToString();
byte[] result = memoryStream.ToArray();
String base64 = System.Convert.ToBase64String(result);
String post_data = "&image=" + base64;
...
wc.UploadStringAsync(imgur_api,"POST",post_data);
I am using this code to upload an image to the Imgur API v3 using WebClient. The image being selected is either one of the 7 photos provided by the Windows Phone 7.1 emulator, or the simulated camera images. When I try to load the images, they are a largely-grey corrupted mess. Am I generating the base64 properly and/or do I need to render a Bitmap of the picture first before creating the byte[] and base64?
Thanks in advance!
Use something like Uri.EscapeDataString to escape the data so that special URL characters are not interpreted.
I use this
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult != TaskResult.OK) return;
var bimg = new BitmapImage();
bimg.SetSource(e.ChosenPhoto);
var sbytedata = ReadToEnd(e.ChosenPhoto);
}
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = stream.Position;
stream.Position = 0;
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
stream.Position = originalPosition;
}
}
And upload byte[] to server. Hope it's help

Categories