I have a client and server, client sending file to server. When i transfer files on my computer(in local) everything is ok(try to sen file over 700mb).
When i try to sent file use Internet to my friend in the end of sending appears error on server "Input string is not in correct format".This error appears in this expression fSize = Convert::ToUInt64(tokenes[0]); - and i don't mind wht it's appear. File should be transfered and wait other transferring
ps: sorry for too much code, but i want to find solution
private: void CreateServer()
{
try{
IPAddress ^ipAddres = IPAddress::Parse(ipAdress);
listener = gcnew System::Net::Sockets::TcpListener(ipAddres, port);
listener->Start();
clientsocket =listener->AcceptSocket();
bool keepalive = true;
array<wchar_t,1> ^split = gcnew array<wchar_t>(1){ '\0' };
array<wchar_t,1> ^split2 = gcnew array<wchar_t>(1){ '|' };
statusBar1->Text = "Connected" ;
//
while (keepalive)
{
array<Byte>^ size1 = gcnew array<Byte>(1024);
clientsocket->Receive(size1);
System::String ^notSplited = System::Text::Encoding::GetEncoding(1251)->GetString(size1);
array<String^> ^ tokenes = notSplited->Split(split2);
System::String ^fileName = tokenes[1]->ToString();
statusBar1->Text = "Receiving file" ;
unsigned long fSize = 0;
//IN THIS EXPRESSIN APPEARS ERROR
fSize = Convert::ToUInt64(tokenes[0]);
if (!Directory::Exists("Received"))
Directory::CreateDirectory("Received");
System::String ^path = "Received\\"+ fileName;
while (File::Exists(path))
{
int dotPos = path->LastIndexOf('.');
if (dotPos == -1)
{
path += "[1]";
}
else
{
path = path->Insert(dotPos, "[1]");
}
}
FileStream ^fs = gcnew FileStream(path, FileMode::CreateNew, FileAccess::Write);
BinaryWriter ^f = gcnew BinaryWriter(fs);
//bytes received
unsigned long processed = 0;
pBarFilesTr->Visible = true;
pBarFilesTr->Minimum = 0;
pBarFilesTr->Maximum = (int)fSize;
// Set the initial value of the ProgressBar.
pBarFilesTr->Value = 0;
pBarFilesTr->Step = 1024;
//loop for receive file
array<Byte>^ buffer = gcnew array<Byte>(1024);
while (processed < fSize)
{
if ((fSize - processed) < 1024)
{
int bytes ;
array<Byte>^ buf = gcnew array<Byte>(1024);
bytes = clientsocket->Receive(buf);
if (bytes != 0)
{
f->Write(buf, 0, bytes);
processed = processed + (unsigned long)bytes;
pBarFilesTr->PerformStep();
}
break;
}
else
{
int bytes = clientsocket->Receive(buffer);
if (bytes != 0)
{
f->Write(buffer, 0, 1024);
processed = processed + 1024;
pBarFilesTr->PerformStep();
}
else break;
}
}
statusBar1->Text = "File was received" ;
array<Byte>^ buf = gcnew array<Byte>(1);
clientsocket->Send(buf,buf->Length,SocketFlags::None);
f->Close();
fs->Close();
SystemSounds::Beep->Play();
}
}catch(System::Net::Sockets::SocketException ^es)
{
MessageBox::Show(es->ToString());
}
catch(System::Exception ^es)
{
MessageBox::Show(es->ToString());
}
}
private: void CreateClient()
{
clientsock = gcnew System::Net::Sockets::TcpClient(ipAdress, port);
ns = clientsock->GetStream();
sr = gcnew StreamReader(ns);
statusBar1->Text = "Connected" ;
}
private:void Send()
{
try{
OpenFileDialog ^openFileDialog1 = gcnew OpenFileDialog();
System::String ^filePath = "";
System::String ^fileName = "";
//file choose dialog
if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
filePath = openFileDialog1->FileName;
fileName = openFileDialog1->SafeFileName;
}
else
{
MessageBox::Show("You must select a file", "Error",
MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
return;
}
statusBar1->Text = "Sending file" ;
NetworkStream ^writerStream = clientsock->GetStream();
System::Runtime::Serialization::Formatters::Binary::BinaryFormatter ^format =
gcnew System::Runtime::Serialization::Formatters::Binary::BinaryFormatter();
array<Byte>^ buffer = gcnew array<Byte>(1024);
FileStream ^fs = gcnew FileStream(filePath, FileMode::Open);
BinaryReader ^br = gcnew BinaryReader(fs);
//file size
unsigned long fSize = (unsigned long)fs->Length;
//transfer file size + name
bFSize = Encoding::GetEncoding(1251)->GetBytes(Convert::ToString(fs->Length+"|"+fileName+"|"));
writerStream->Write(bFSize, 0, bFSize->Length);
//status bar
pBarFilesTr->Visible = true;
pBarFilesTr->Minimum = 0;
pBarFilesTr->Maximum = (int)fSize;
pBarFilesTr->Value = 0; // Set the initial value of the ProgressBar.
pBarFilesTr->Step = 1024;
//bytes transfered
unsigned long processed = 0;
int bytes = 1024;
//loop for transfer
while (processed < fSize)
{
if ((fSize - processed) < 1024)
{
bytes = (int)(fSize - processed);
array<Byte>^ buf = gcnew array<Byte>(bytes);
br->Read(buf, 0, bytes);
writerStream->Write(buf, 0, buf->Length);
pBarFilesTr->PerformStep();
processed = processed + (unsigned long)bytes;
break;
}
else
{
br->Read(buffer, 0, 1024);
writerStream->Write(buffer, 0, buffer->Length);
pBarFilesTr->PerformStep();
processed = processed + 1024;
}
}
array<Byte>^ bufsss = gcnew array<Byte>(100);
writerStream->Read(bufsss,0,bufsss->Length);
statusBar1->Text = "File was sent" ;
btnSend->Enabled = true;
fs->Close();
br->Close();
SystemSounds::Beep->Play();
newThread->Abort();
}
catch(System::Net::Sockets::SocketException ^es)
{
MessageBox::Show(es->ToString());
}
}
UPDATE: 2Ben Voigt - ok, i can add checking if clientsocket->Receive(size1); equal zero, but why he begin receiving data again , in the ending of receiving.
UPDATE:After adding this checking problem remains. AND WIN RAR SAY TO OPENING ARCHIVE - unexpected end of file!
UPDATE:2Kevin - http://img153.imageshack.us/img153/3760/erorr.gif
I think it continue receiving some bytes from client(that remains in the stream), but why? - exists cycle while (processed < fSize)
UPDATE: 2Ben Voigt -i did this fix processed += bytes; and file transfered successfully.Thanks!
I am not very good with english and I don't understand what you mean when said "Consider what happens if your initial read snags part of the file data..." What means snags? And what initial data do you mean?
Don't ignore the return value from clientsocket->Receive(size1).
DOC: "Socket.Receive Method (Byte[])"
EDIT: Consider what happens if your initial read snags part of the file data. Also consider what happens if your last read (which for some reason is still 1024 bytes instead of the remaining byte count) snags part of the header for the next request.
EDIT: You also haven't yet done anything useful with the return value from Receive. Your line of code:
processed = processed + 1024;
needs to be
processed += bytes;
EDIT: "snags" means "captures" or "grabs"
You have:
clientsocket->Receive(size1);
and a little later:
clientsocket->Receive(buf);
and you assume that all the header data is in size1 and all the file data is in buf. That's not a safe assumption on a stream socket. Datagram sockets preserve message boundaries, stream sockets like TCP do not. In fact, Nagle's algorithm might even cause the first part of the file data to be put into the same network packet as the header, but even if it doesn't, the receiver's TCP stack throws away the packet boundaries and just puts things into one big receive buffer.
Related
I'm trying to communicate with an XMPP (Jabber) server via a TCP network socket (StreamSocket) and I'm using the following code to read what the server has send to me:
StreamSocket tcpSocket;
StreamReader reader;
int BUFFER_SIZE = 4096;
// Connecting to a remote XMPP server ....
reader = new StreamReader(tcpSocket.InputStream.AsStreamForRead());
string result;
while (true)
{
result = "";
while (true)
{
char[] buffer = new char[BUFFER_SIZE];
await reader.ReadAsync(buffer, 0, BUFFER_SIZE);
string data = new string(buffer);
// Detecting if all elements in the buffer array got replaced => there is more to read
if (data.IndexOf("\0") >= 0 || reader.EndOfStream)
{
result + data.Substring(0, data.IndexOf("\0"));
break;
}
result += data;
}
Debug.WriteLine(result);
}
My Code works just fine for strings with a length < 4096 chars, but as soon as the string gets longer than 4096 chars it fails (won't detect the message end). It waits until it receives a new string < 4096 chars, concatenates both strings and returns them as one string.
Is there a way to get the actual length of a string and read them successively?
You have set 4096 to the BUFFER_SIZE and it is be set to the count parameter in StreamReader.ReadAsync and the char Array. When the string contain more than 4096 chars, it will fails.
You should be able to get the actual length in the Stream, we can use Stream.Length to get the length of the stream in bytes. The last char of Array is "\0". When you create the char Array, you should be able to set the Stream.Length plus one to the char Array.
For example:
StreamSocket socket;
StreamSocket tcpSocket;
StreamReader reader;
reader = new StreamReader(tcpSocket.InputStream.AsStreamForRead());
var BUFFER_SIZE=(int)(tcpSocket.InputStream.AsStreamForRead()).Length;
string result;
while (true)
{
result = "";
while (true)
{
char[] buffer = new char[BUFFER_SIZE+1];
await reader.ReadAsync(buffer, 0, BUFFER_SIZE);
string data = new string(buffer);
if (data.IndexOf("\0") >= 0 || reader.EndOfStream)
{
result = data.Substring(0, data.IndexOf("\0"));
break;
}
result += data;
}
Debug.WriteLine(result);
}
If you want to reads all characters from the current position to the end of the stream, you can use StreamReader.ReadToEnd or StreamReader.ReadToEndAsync method.
I finally figured out to read long messages:
I had to user DataReader and DataWriter instead of StreamReader and StreamWriter.
/// <summary>
/// How many characters should get read at once max.
/// </summary>
private static readonly int BUFFER_SIZE = 4096;
private StreamSocket socket;
private DataReader dataReader;
private DataWriter dataWriter;
public string readNextString() {
string result = "";
readingCTS = new CancellationTokenSource();
try {
uint readCount = 0;
// Read the first batch:
Task < uint > t = dataReader.LoadAsync(BUFFER_SIZE).AsTask();
t.Wait(readingCTS.Token);
readCount = t.Result;
if (dataReader == null) {
return result;
}
while (dataReader.UnconsumedBufferLength > 0) {
result +=dataReader.ReadString(dataReader.UnconsumedBufferLength);
}
// If there is still data left to read, continue until a timeout occurs or a close got requested:
while (!readingCTS.IsCancellationRequested && readCount >= BUFFER_SIZE) {
t = dataReader.LoadAsync(BUFFER_SIZE).AsTask();
t.Wait(100, readingCTS.Token);
readCount = t.Result;
while (dataReader.UnconsumedBufferLength > 0) {
result += dataReader.ReadString(dataReader.UnconsumedBufferLength);
}
}
}
catch(AggregateException) {}
catch(NullReferenceException) {}
return result;
}
I'm currently working on a TCPClient and Server. Lately I added an encryption for the messages, and had no trouble. Once I started noticing that I'm getting a weird error like this:
But It's totally random, and no idea why. It happens at larger messages, but as I said, not always.
Checking the byte[] length at the server side says 1920 (Sometimes it says 1920 on the client too, and thats the point when i dont have error)
On client it says a lot lesser.
I actually think that sometimes the client doesn't receive the full byte that It should, this is how I do It:
Client:
byte[] bb = new byte[12288];
int k = stm.Read(bb, 0, 12288);
string message = Encoding.UTF8.GetString(bb, 0, k);
MessageBox.Show(message.Length.ToString()); // This sometimes says 1460, and 1920
message = Encrypter.DecryptData(message); // Error here If the length is not 1920
Server:
bmsg = Encrypter.EncryptData(((int)Codes.XYZEnum) + "=" + data);
Logger.Log(bmsg.Length.ToString()); // Original msg, always says 1920
s.Send(asen.GetBytes(bmsg));
s.Close();
What could be the problem? Should I try async sending?
SOLUTION:
Server code, took me a little while to make it cool:
System.Net.Sockets.Socket s = myList.AcceptSocket(); // Accept the connection
Stream stream = new NetworkStream(s); // Create the stream object
byte[] leng = new byte[4]; // We will put the length of the upcoming message in a 4 length array
int k2 = s.Receive(leng); // Receive the upcoming message length
if (BitConverter.IsLittleEndian)
{
Array.Reverse(leng);
}
int upcominglength = (BitConverter.ToInt32(leng, 0)); // Convert it to int
byte[] b = ByteReader(upcominglength, stream); // Create the space for the bigger message, read all bytes until the received length!
string message = Encoding.UTF8.GetString(b, 0, b.Length); // Convert it to string!
internal byte[] ByteReader(int length, Stream stream)
{
byte[] data = new byte[length];
using (MemoryStream ms = new MemoryStream())
{
int numBytesRead;
int numBytesReadsofar = 0;
while (true)
{
numBytesRead = stream.Read(data, 0, data.Length);
numBytesReadsofar += numBytesRead;
ms.Write(data, 0, numBytesRead);
if (numBytesReadsofar == length)
{
break;
}
}
return ms.ToArray();
}
}
Client code, and it is working nicely!:
var result = tcpclnt.BeginConnect(User.IP, User.Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3)); // Connect with timeout
if (!success)
{
return "Failed to connect!";
}
Stream stm = tcpclnt.GetStream(); // get the stream
UTF8Encoding asen = new UTF8Encoding();
byte[] ba = asen.GetBytes(msg); // get the bytes of the message we are sending
byte[] intBytes = BitConverter.GetBytes(ba.Length); // Get the length of that in bytes
if (BitConverter.IsLittleEndian)
{
Array.Reverse(intBytes);
}
stm.Write(intBytes, 0, intBytes.Length); // Write the length in the stream!
stm.Flush(); // Clear the buffer!
stm.Write(ba, 0, ba.Length); // Write the message we are sending!
// If we have answers....
byte[] bb = new byte[10000];
int k = stm.Read(bb, 0, 10000);
string mmessage = Encoding.UTF8.GetString(bb, 0, k);
// If we have answers....
tcpclnt.Close(); // Close the socket
Because only 8Kb can to send by once packet. if you have large data you need use cycle.
I have one question regarding to the way of sending file and receiving file in C# language. I have created a simple file transfer windows form application but it only supports with .txt file format. If I try to send an image file or ms words document file, it could be completely received at the receiving side. But, the received file is unreadable and cannot be opened. I have done a similar application Java but it works for any file format and I am using the same logic to implement in the C# application. Can anyone give me some suggestion or advices on this?
SENDING SIDE:
// establish connection
int port = Convert.ToInt32(txtLocalPort.Text) - 5;
TcpListener listener = new TcpListener(IPAddress.Parse(txtLocalIP.Text), port);
listener.Start();
// get file size
byte[] data = File.ReadAllBytes(downFile);
int fSize = data.Length;
// calculate block numbers, 1024 bytes each block
int block = fSize / 1024;
// leftover file bytes, less than 1024 bytes
int byteLeft = fSize % 1024;
// convert String to byte
String cmd = "SEND_FILE" + fSize.ToString();
buff = new byte[1024];
buff = Encoding.ASCII.GetBytes(cmd);
// send message in byte
msgSocket.Send(buff);
// accept connection
TcpClient client = listener.AcceptTcpClient();
// remote host connected
if (client.Connected == true)
{
// medium to read file bytes from file chosen
BinaryReader readByte = new BinaryReader(File.Open(downFile, FileMode.Open));
// medium to send file bytes
NetworkStream dataOUT = client.GetStream();
// send file bytes based on calculated block numbers
for (int i = 0; i < block; i++)
{
// buffer size
buff = new byte[1024];
// read file bytes from file chosen
readByte.Read(buff, 0, buff.Length);
// send file bytes
dataOUT.Write(buff, 0, buff.Length);
dataOUT.Flush();
}
// leftover file bytes
// buffer size
buffLeft = new byte[byteLeft];
// read leftover file bytes from file chosen
readByte.Read(buffLeft, 0, buffLeft.Length);
// send leftover file bytes
dataOUT.Write(buff, 0, buffLeft.Length);
dataOUT.Flush();
MessageBox.Show("File sent successfully.", "File Share", MessageBoxButtons.OK, MessageBoxIcon.Information);
// close the medium
readByte.Close();
dataOUT.Close();
client.Close();
listener.Stop();
RECEIVING SIDE:
// establish connection
int port = Convert.ToInt32(txtRemotePort.Text) - 5;
TcpClient client = new TcpClient(Dns.GetHostEntry(IPAddress.Parse(txtRemoteIP.Text)).HostName.ToString(), port);
// connected to remote host
if (client.Connected == true)
{
// get invalid character
String invalid = new String(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
// remove invalid character
foreach (char c in invalid)
{
fileName = fileName.Replace(c.ToString(), "");
}
String downFile = Path.Combine(#"D:\", fileName);
// file size
int fSize = fileSize;
// calculate block numbers, 1024 bytes each block
int block = fSize / 1024;
// leftover file bytes, less than 1024 bytes
int byteLeft = fSize % 1024;
// medium to receive file bytes
NetworkStream dataIN = client.GetStream();
// medium to write file bytes to new file
BinaryWriter writeByte = new BinaryWriter(File.Open(downFile, FileMode.Create));
// receive file bytes based on calculated block numbers
for (int i = 0; i < block; i++)
{
// buffer size
buff = new byte[1024];
// receive file bytes
dataIN.Read(buff, 0, buff.Length);
dataIN.Flush();
// write file bytes to new file
writeByte.Write(buff, 0, buff.Length);
writeByte.Flush();
}
// receive leftover file bytes
// buffer size
buffLeft = new byte[byteLeft];
// receive file bytes
dataIN.Read(buffLeft, 0, buffLeft.Length);
dataIN.Flush();
// write file bytes to new file
writeByte.Write(buffLeft, 0, buffLeft.Length);
writeByte.Flush();
MessageBox.Show("File downloaded successfully.", "File Share", MessageBoxButtons.OK, MessageBoxIcon.Information);
// close the medium
writeByte.Close();
dataIN.Close();
client.Close();
I think I've found out what you did wrong:
Instead of
BinaryWriter writeByte = new BinaryWriter(File.Open(downFile, FileMode.Create));
Use
BinaryWriter writeByte = new BinaryWriter(File.Open(downFile, FileMode.Append));
I am trying to encrypt and then decrypt an XML file using RSA and C# and while I'm really close, there's a problem. Once it's decrypted, almost all of the file is there but there's a hiccup toward the end. It's either a gap toward the end of the file or more data is appended to the very end of the file.
Here is my encrypt method:
public static bool Encrypt(ProcessingHolder ph)
{
FileInfo inFile = ph.encryptedFI;
FileInfo outFile = ph.unEncryptedFI;
X509Certificate2 daCert = new X509Certificate2(keyFP, daCertPassword);
RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)daCert.PrivateKey;
bool done = false;
FileStream fs = null;
FileStream fso = null;
try
{
//opens the file to encrypt into a filestream object
fs = inFile.OpenRead();
//240 is what the iOS side is using
//algorithm that calculates max bytes ((KeySize - 384) / 8) + 37
//(returns 245)
int chunkSize = 245;
fso = outFile.OpenWrite();
byte[] buffer = new byte[chunkSize];
int totalRead = 0;
while (totalRead < fs.Length)
{
int readBytes = fs.Read(buffer,0, chunkSize);
totalRead += readBytes;
//check to see if the final chunk of data is less than 245 so as not to write empty buffer
if (readBytes < chunkSize) buffer = new byte[readBytes];
//byte[] encr = new byte[readBytes];
//actual encryption
//encr = RSA.Encrypt(buffer, false);
byte[] encr = RSA.Encrypt(buffer, false);
fso.Write(encr, 0, encr.Length);
}
fso.Flush();
fso.Close();
fs.Close();
done = true;
}
catch (Exception ex)
{
Debug.WriteLine("Decrypt failed with message " + ex.Message);
done = false;
}
finally
{
if (fs != null) fs.Close();
if (fso != null) fso.Close();
}
return done;
}
}
and here is my decrypt method:
public static bool Decrypt(ProcessingHolder ph)
{
FileInfo inFile = ph.encryptedFI;
FileInfo outFile = ph.unEncryptedFI;
X509Certificate2 daCert = new X509Certificate2(keyFP, daCertPassword);
RSACryptoServiceProvider RSA = (RSACryptoServiceProvider)daCert.PrivateKey;
bool done = false;
FileStream fs = null;
FileStream fso = null;
try
{
fs = inFile.OpenRead();
int chunkSize = 256;
fso = outFile.OpenWrite();
byte[] buffer = new byte[chunkSize];
int totalRead = 0;
while (totalRead < fs.Length)
{
int readBytes = fs.Read(buffer, 0, chunkSize);
totalRead += readBytes;
//check to see if the final chunk of data is less than 245 so as not to write empty buffer
//if (readBytes < chunkSize) buffer = new byte[readBytes];
byte[] decr = RSA.Decrypt(buffer, false);
fso.Write(decr, 0, decr.Length);
}
fso.Flush();
fso.Close();
fs.Close();
done = true;
}
catch (Exception ex)
{
Debug.WriteLine("Decrypt failed with message " + ex.Message);
done = false;
}
finally
{
if (fs != null) fs.Close();
if (fso != null) fso.Close();
}
return done;
}
banging my head against the wall here, thanks in advance
What happens during encrypting if the file is not a multiple of the length of the chunk size? Ie. a file 500 bytes long would read two sets of 245, but they have 10 bytes left over? This might be loosing the last few bytes at the end or adding extra values?
Maybe you need to add a header to the file with the size in bytes of the decrypted file so that the decrypter knows where to stop and a way to pad out the final block during encryption
I'm trying to securely transfer files between 2 devices, so I'm using an SslStream attached to a TcpClient. Documents and text files come across just fine, but image files don't show up correctly. The following is the server code:
listener = new TcpListener(IPAddress.Any, 1337);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidationCallback), new LocalCertificateSelectionCallback(CertificateSelectionCallback));
var certificate = Connection.GetClientCertificate(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
try
{
sslStream.AuthenticateAsServer(certificate, true, SslProtocols.Default, true);
sslStream.ReadTimeout = 5000;
sslStream.WriteTimeout = 5000;
var messageData = ReadMessage(sslStream);
var mode = messageData[0];
var tokenBytes = messageData.Splice(1, 16);
var fileNameBytes = messageData.Splice(17, 128);
var fileBytes = messageData.Splice(146);
var fileName = Encoding.ASCII.GetString(fileNameBytes).TrimEnd('\0');
using (var tempFile = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write))
{
tempFile.Write(fileBytes, 0, fileBytes.Length);
tempFile.Flush();
}
if (mode == 0)
tempFiles.Add(fileName);
Process.Start(fileName);
}
catch (AuthenticationException e)
{
MessageBox.Show("The other side failed to authenticate.");
}
finally
{
sslStream.Close();
client.Close();
}
}
And ReadMessage is defined as follows:
private static byte[] ReadMessage(SslStream sslStream)
{
byte[] buffer = new byte[2048];
MemoryStream stream = new MemoryStream();
int bytes = -1;
while (bytes != 0)
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
stream.Write(buffer, 0, bytes);
}
return stream.ToArray();
}
And then the client code is this:
TcpClient client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Parse(ip), 1337));
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidationCallback), new LocalCertificateSelectionCallback(CertificateSelectionCallback));
var certificate = Connection.GetClientCertificate(ip);
try
{
sslStream.AuthenticateAsClient(ip, new X509CertificateCollection() { certificate }, SslProtocols.Default, false);
sslStream.ReadTimeout = 5000;
sslStream.WriteTimeout = 5000;
sslStream.Write(data);
}
catch (AuthenticationException e)
{
MessageBox.Show("The other side failed to authenticate.");
}
finally
{
sslStream.Close();
client.Close();
}
And the code that calls into it just does:
var fileBytes = File.ReadAllBytes(file);
var tokenBytes = Encoding.UTF8.GetBytes(token);
var fileNameBytes = Encoding.UTF8.GetBytes(Path.GetFileName(file));
var buffer = new byte[145 + fileBytes.Length];
buffer[0] = 1;
for (int i = 0; i < 16; i++)
{
buffer[i + 1] = tokenBytes[i];
}
for (int i = 0; i < fileNameBytes.Length; i++)
{
buffer[i + 17] = fileNameBytes[i];
}
for (int i = 0; i < fileBytes.Length; i++)
{
buffer[i + 145] = fileBytes[i];
}
SocketConnection.Send(ip, buffer);
Is there anything inherently wrong with what I'm doing, or do I need to do something different for images?
EDIT: I have changed it to reflect the current code, and also, after doing a dump of the raw bytes on both ends, it looks like for some reason the bytes are getting rearranged when they come over the wire. Is there any way to ensure that the bytes come across in the original order?
In ReadMessage you're writing bytes.Length bytes to the stream, regardless of the number of bytes that were actually read. Try:
private static byte[] ReadMessage(SslStream sslStream)
{
byte[] buffer = new byte[2048];
MemoryStream stream = new MemoryStream();
int bytes = -1;
while (bytes != 0)
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
// Use "bytes" instead of "buffer.Length" here
stream.Write(buffer, 0, bytes);
}
return stream.ToArray();
}
Based on your follow-up, you're also taking the file data from the wrong point in the buffer, and so you're losing the first byte of the file.
Your code should be:
var fileBytes = messageData.Splice(145); // File data starts at 145, not 146
Is this possibly a conflict between endianness? If the bytes from the server are ABCDEF and the client is seeing the image bytes as BADCFE then that's the issue.
I haven't worked with image files, but when I read a short or an int instead of a String from the bytes coming in over the wire, I do something like this:
int intFromStream = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(byteArrayWithLength4, 0));