Its a very weird thing.
I created a client and a server to upload and download files. When uploading I can upload a lot of files without a problem but when I download a file the client for turn to not responding and doesn't show MessageBox.show("Downloaded"); its the first tie to see this :D.
The code that make the problem when used :
private void button3_Click(object sender, EventArgs e)
{
try
{
String fileToDownload = filePathDownload.Text;
TcpClient clientSocket = new TcpClient(serverIPDownload.Text, 8880);
NetworkStream networkStream = clientSocket.GetStream();
ASCIIEncoding asci = new ASCIIEncoding();
byte[] b = asci.GetBytes(fileToDownload + "?");
byte[] bb = asci.GetBytes("Download?");
int thisRead = 0;
int blockSize = 1024;
Byte[] dataByte = new Byte[blockSize];
networkStream.Write(bb, 0, bb.Length);
networkStream.Flush();
networkStream.Write(b, 0, b.Length);
networkStream.Flush();
using (FileStream fileStream = new FileStream(
"C:/Users/Laptop/Documents/Downloads/" + fileToDownload,
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
while (true)
{
thisRead = networkStream.Read(dataByte, 0, blockSize);
fileStream.Write(dataByte, 0, thisRead);
if (thisRead == 0) break;
}
MessageBox.Show("File Downloaded");
fileStream.Close();
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
Thanks. This maybe off topic but its the problem I faced.
Your code appears to be ok, so I suspect the problem is in the Download method you are reading from.
Also, I would personally move the loop termination (if (thisRead == 0) break;) before the fileStream.Write statement.
And for production code, I would add some sort of timeout limit so that you don't end up in an infinite loop.
Related
I try to send a file with an sslStream of tcp client. File is about 250kb.
When i don't write dataLength to stream, server closes the connection i thing because of max receive buffer size. When i write into stream the dataLength, i have no exception but server has an error of type (connection closed gracefully). One reason is that, because the Tcp client close event, the server
can not receive the data that i have sent; Here is my code. Server code is missing that i know that it has be writen in delphi with indy sockets library
Here is my code
TcpClient sendClient = new TcpClient(serverName, port);
LingerOption lingerOption = new LingerOption(true, 20);
sendClient.LingerState = lingerOption;
using (SslStream sendStream = new SslStream(sendClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null))
{
try
{
sendStream.AuthenticateAsClient(serverName, null, SslProtocols.Ssl2, true);
sendStream.Write(Encoding.UTF8.GetBytes("Login\r\n" + username + "\r\n" + password + "\r\n"));
sendStream.Flush();
int bytesResp = -1;
byte[] buffer = new byte[1024];
bytesResp = sendStream.Read(buffer, 0, buffer.Length);
string response = Encoding.UTF8.GetString(buffer, 0, bytesResp);
if (response.Trim() == "OK")
{
sendStream.Write(Encoding.ASCII.GetBytes("Send\r\n"));
FileStream inputStream = File.OpenRead(filePath);
FileInfo f = new FileInfo(filePath);
int size = unchecked((int)f.Length);
byte[] byteSize = Encoding.ASCII.GetBytes(size.ToString());
sendStream.Write(byteSize);
sendStream.Write(Encoding.ASCII.GetBytes("\r\n"));
sendStream.Write(Encoding.ASCII.GetBytes(fileName + "\r\n"));
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
long sum = 0;
int count = 0;
byte[] data = new byte[1024];
while (sum < size)
{
count = fs.Read(data, 0, data.Length);
sendStream.Write(data, 0, count);
sum += count;
Array.Clear(data, 0, data.Length);
}
sendStream.Flush();
}
sendStream.Write(Encoding.UTF8.GetBytes("\r\n"));
sendStream.Write(Encoding.UTF8.GetBytes("Quit\r\n"));
}
MessageBox.Show("end the procedure");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
if (sendClient.Client.Connected)
{
sendClient.Client.Disconnect(false);
sendClient.Client.Dispose();
}
}
I'm not sure if it will be of help but I had a similar issue with using(){} which for some reason it closed the sslstream.
So potentially remove
using (SslStream sendStream = new SslStream(sendClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null)){}
into
SslStream sendStream = new SslStream(sendClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
After a lot more of study and research i was suggested on Stackoverflow to betterly use FileStream to open a file on client machine ,send file-name before sending data to server(listening at a pre-defined port),read a fixed-sized data in a buffer chunk-by-chunk ,send it to the remote server.All these operations were tested by me using various buffer-size starting from 10kb to 100MB now.I tested it for small-files and it worked nice.I went with the useful idea of sending 2GB file.it took almost an hour .
Following is the brief coded-idea.
Client-side:
try
{
clientSocket.Connect(new IPEndPoint(ipaddrcl, port));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
NetworkStream netstream = clientSocket.GetStream();
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
try
{
TransmitFileName(netstream, Path.GetFileName(path));
int data_len = (int)fs.Length;
byte[] buffer = new byte[bufferSize];
int totalbytes = 0;
while (totalbytes < data_len)
{
var bytesread = fs.Read(buffer, 0, buffer.Length);
if (totalbytes == data_len)
{
break;
}
try
{
netstream.Write(buffer, 0, bytesread);
totalbytes += bytesread;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
pictureBox.Image = Properties.Resources.Warning;
labelProgress.Text = "Error in transmission";
}
}
}
finally
{
MessageBox.Show("Data transfer completed");
pictureBox.Image = Properties.Resources.Information;
labelProgress.Text = "Copying Done";
fs.Close();
netstream.Close();
// change button states
btnSend.Enabled = true;
btn_Cancel.Enabled = false;
}
}
Server-side:
Directory.CreateDirectory(Path.GetDirectoryName(fileloc));
try
{
using (FileStream fs = new FileStream(fileloc, FileMode.OpenOrCreate, FileAccess.Write))
{
netStream.CopyTo(fs);
pictureBox2.Image = Properties.Resources.spinningDisc1;
// label_server.Text = "Receiving Data";
}
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
finally
{
//check the size of file recieved
FileInfo fi = new FileInfo(fileloc);
long siz = fi.Length;
MessageBox.Show("Data Recieved: File Size is " + SizeSuffix(siz));
pictureBox2.Image = null;
// Thread();
}
In order to enhance speed ,i came across here and tested CopyFileEx for copying folders and trees on local-host and it worked superb.
Now the issue is,Can i use CopyFileEx on WLAN and if,yes, how will this ensures me to write a chunk-by-chunk piece of data and still ensures speedy process.
PS.I tried my best to not make it not so-lengthy but efforts are worth to show first before asking.I didn't find any working example for WLAN..if you have please give me a start-up with it.
In my client/server application my client wiil communicate with the server for 2 functions: the client will either request data from the server or it will send data so the server will save it. I'm using one socket for both methods, and the method to be used is defined by the first byte sent. If the first byte is "1" it is requesting data. If it is "2", it will send data (data bytes are sent after the "2" byte). It works perfectly for sending data. But when I'm requesting data it works, as long as I don't read the socket stream in the client. It's like if I make the client read data after sending data, the server will have no data to read, and it just crashes when trying to read the data.
Here is my server code:
private const int BufferSize = 1024;
NetworkStream netstream = null;
byte[] RecData = new byte[BufferSize];
int RecBytes;
try {
netstream = clientSocket.GetStream();
int totalrecbytes = 0;
using (MemoryStream ms = new MemoryStream()) {
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
byte[] bytes = ms.ToArray();
byte b = bytes[0];
switch (b) {
case 1:
//Here I gather data and put it in "stream" variable
byte[] SendingBuffer = null;
int NoOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(stream.Length) / Convert.ToDouble(BufferSize)));
int TotalLength = (int)stream.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++) {
if (TotalLength > BufferSize) {
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
stream.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
}
netstream.Flush();
}
catch (Exception e) {
Console.WriteLine("EXCEPTION:\n" + e.ToString());
}
break;
case 2:
//Code to read data
break;
}
}
netstream.Close()
clientSocket.Close();
And here is my client code:
using (System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient()) {
string returnData = "";
IAsyncResult ar = clientSocket.BeginConnect("127.0.0.1", 8080, null, null);
System.Threading.WaitHandle wh = ar.AsyncWaitHandle;
try {
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false)) {
clientSocket.Close();
Console.WriteLine("Timeout");
return;
}
System.Net.Sockets.NetworkStream serverStream = clientSocket.GetStream();
byte b = 1;
byte[] outStream = { b };
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
//If I comment following lines, the server can read sent data, but server can't otherwise
byte[] RecData = new byte[1024];
int RecBytes;
int totalrecbytes = 0;
MemoryStream MS = new MemoryStream();
while ((RecBytes = serverStream.Read(RecData, 0, RecData.Length)) > 0) {
MS.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
serverStream.Close();
clientSocket.Close();
clientSocket.EndConnect(ar);
}
catch (Exception ex) {
Console.WriteLine("Exceção: " + ex.ToString());
}
finally {
wh.Close();
}
}
So, how can I send data to server and read the response? (I tried even putting the thread to sleep after sending data, with no luck.)
Thanks in advance.
EDIT:
With some debug messages I discovered that the server do read the "1" byte that was sent, but somehow it gets stuck inside the while loop, like, the server just stops there, no more loops and it does not leave the while loop. I saw that after writing "loop" in console inside the while loop, and writing read bytes also in console. It wrote "loop" once, and the read byte.
This code worries me:
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
You are reading until the client closes the connection (or shuts down sending, which you don't do). But the client only closes when the server has replied. The server reply will never come. It is a deadlock.
Solution: Read a single byte to determine the requests command (b).
Unrelated to the question, your "packetised" sending (NoOfPackets, ...) does not seem to serve any purpose. Just use Stream.Copy to write. TCP does not have packets.
An even better solution would be to abandon your custom TCP protocol and use an HTTP library. All these concerns just go away. There are various smaller problems with your code that are very typical to see in TCP code.
Hello I'm trying to implement a server and client couple that can transfer files of any kind and any size but there is a problem I somehow corrupt files. I tried lots of methods but can't figure it out. So basicly I can connect ,I can understand which file does client want, and can send it through sockets. When I try to open that file it shows me an error message(Tried winrar, mp4, avi files) Here is my code:
//Server
private void Receive(string receivedFileName, string fileSize)
{
try
{
int receivedBytesLen = 0;
byte[] incomingFile = new byte[int.Parse(fileSize)];
activity.AppendText("Preparing to download... \n");
while (incomingFile != null && int.Parse(fileSize) > receivedBytesLen)
{
tempSocket.Receive(incomingFile);
receivedBytesLen = incomingFile.Length;
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
File.WriteAllBytes(fileDir + "//" + receivedFileName, incomingFile);
}
activity.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//////////////////////////////////////////////////////////////////////
//server option 2
private void Receive(string receivedFileName, string fileSize)
{
try
{
byte[] incomingFile = new byte[10124 * 5000];
activity.AppendText("Preparing to download... \n");
BinaryWriter bWrite = new BinaryWriter(File.Open(folderBrowserDialog1.SelectedPath + "//" + receivedFileName, FileMode.Append));
int receivedBytesLen = tempSocket.Receive(incomingFile, incomingFile.Length, 0);
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
//string fileName = Encoding.UTF8.GetString(incomingFile, 4, fileNameLen);
//bWrite.Write(incomingFile, 4 + fileNameLen, receivedBytesLen - 4 - fileNameLen);
while (receivedBytesLen > 0)
{
receivedBytesLen = tempSocket.Receive(incomingFile, incomingFile.Length, 0);
if (receivedBytesLen == 0)
{
bWrite.Close();
}
else
{
bWrite.Write(incomingFile, 0, receivedBytesLen);
}
}
activity.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/////////////////////////////////////////////////////////////////////
//client
private void Upload_Click(object sender, EventArgs e)
{//Uploads selected file after clicking upload button.
try
{
if (clientSocket.Connected)
{
byte[] buffer = new byte[1024];
byte[] sendingFile = null;
sendingFile = File.ReadAllBytes(openFileDialog1.FileName);
FileInfo f = new FileInfo(openFileDialog1.FileName);
string fileSize = f.Length.ToString();
buffer = Encoding.Default.GetBytes(getUserName.Text + "Upload" + openFileDialog1.SafeFileName + "size" + fileSize + "end");
clientSocket.Send(buffer);
activityLog.AppendText("Sending File \n");
int bytesToBeSent = sendingFile.Length;
int bytesActuallySent = 0;
while(bytesActuallySent < bytesToBeSent){
bytesActuallySent += clientSocket.Send(sendingFile, bytesActuallySent, bytesToBeSent -bytesActuallySent, 0);
}
activityLog.AppendText("File Sent.\n");
}
}
catch(Exception ex){
MessageBox.Show(ex.Message);
}
}
server option #2 is better. But there are some improvements
socket receive buffer is limited decided by OS, generally is 8192
use FileStream in client and server and do not forget to close filestream after file download
client:
FileStream fileStream = new FileStream(filePath, FileMode.Open)
byte[] buff = new byte[8192];
do
{
bytesRead = fileStream.Read(buff, 0, buff.Length);
sock.send(dataSock, buff, bytesRead);
}while (bytesRead > 0);
fileStream.close();
server:
FileStream fileStream = new FileStream(filePath, FileMode.Open)
do
{
bytesRead = sock.receive(buff, 0, buff.Lenght);
fileStream.Write(buff, 0, bytesRead );
}while (bytesRead > 0);
fileStream.close();
In order to satisfy ANY sized file you need an option #3, one that reads a block of bytes til all bytes are received, your option #1 wouldn't do so well on a 3 GIG file running on 2 GIG box...
Here is a link: http://www.yoda.arachsys.com/csharp/readbinary.html
I like option #2 from this link.
However in the example they write to a memoryStream, you should write to a filestream, the target file.
I am trying to send files with a bunch of strings from Android client to C# server. The strings, among other things, will also contain details with regards to the file being sent eg: File Size, File Name, etc. The issue I am having is that all the file bytes is not received thus the original file cannot be reconstructed at the destination even though I can properly retrieve all the strings.
My C# Server Code
while (true)
{
Socket socket = listener.AcceptSocket();
setStatus(socket.RemoteEndPoint + " Connected");
try
{
// Open the stream
NetworkStream stream = new NetworkStream(socket);
System.IO.StreamReader sr = new StreamReader(stream);
//Get string data
//********************************************
Teststr = sr.ReadLine();
setStatus(Teststr);
FileSize = sr.ReadLine();
long fileSizeLong = Convert.ToInt64(FileSize);
int length = (int)fileSizeLong;
setStatus("File size: " + length + " bytes");
//********************************************
//read bytes to buffer
byte[] buffer = new byte[length];
int toRead = (int)length;
int read = 0;
while (toRead > 0)
{
int noChars = stream.Read(buffer, read, toRead);
read += noChars;
toRead -= noChars;
}
setStatus("File Recieved. Total bytes: " + Convert.ToString(buffer.Length));
setStatus("Saving File");
String recievedPath = "C:\\Test\\";
BinaryWriter bWrite = new BinaryWriter(File.Open(recievedPath + "Test.png", FileMode.Create));
bWrite.Write(buffer);
setStatus("File Saved to: " + recievedPath);
bWrite.Flush();
bWrite.Close();
stream.Flush();
stream.Close();
}
catch (Exception e)
{
setStatus(e.Message);
}
setStatus("Disconnected");
socket.Close();
}
My Android Client Code
File file = new File(configstr[2]); //create file instance
try {
client = new Socket(configstr[0], Integer.valueOf(configstr[1]));
//Read file
fileInputStream = new FileInputStream(file);
outputStream = client.getOutputStream();
//Output database details to stream
//*****************************************
//Holds the string before conversion to bytes
String text = "";
text = "Test\n";
outputStream.write(text.getBytes());
text = String.valueOf(file.length()) + "\n";
outputStream.write(text.getBytes());
//*****************************************
outputStream.flush();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileInputStream.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
outputStream.write(bytes);
outputStream.flush();
return true;
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
NOTE: The code works well if I only send one string, eg: If I only send file size.
Any better way of getting this to work as I am trying to send many strings through the stream as well as binary data from the file.
BufferedWriter with flush() at the end of every write() solved the issue for me.