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));
Related
I'm currently working on a project that involves me taking a picture with my laptop camera on a given command. I'm using my webcam as a security camera right now due to the fact that I have not gotten the time to buy a real one yet so my laptop will have to do.
The project is structured like this:
I have my Server (this runs on my laptop) and I have my Client (which runs on my PC which will later be on my phone - but thats not relevant). I send a command to the server using my client (in this case it's "Webcam") and the server receives it, takes a picture using the webcam, gets the bytes and then sends the bytes over a network stream to the client.
However when I download the stream with my client, it downloads 0 bytes. To clarify, it does save the image in my folder but I can't open it because it's 0 bytes.
Server
while (true)
{
if (nwStream.DataAvailable)
{
//Create a byte array (a buffer). This will hold the byte size that we recieve from the client in memory.
byte[] buffer = new byte[client.ReceiveBufferSize];
//Now we need to read the bytes and store the bytes we read in a int, we do this by using our nwStream.Read function and pass it the correct parameters.
//1. [Buffer] - an array of type byte, and we declared that above [buffer] <- This is what we are reading from.
//2. [Offset] - Now we need to set the offset, where we want to start reading in the buffer. so since its an array we start at 0.
//3. [Size] - The number of bytes we want to read from the NetworkStream.
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
//Now we need to decode the message we recieved by using the Encoding.ASCII.GetString to get the string and passing the correct parameters.
//1. [Bytes] - What we want to decode, this is where we give it a byte array
//2. [Index] - We need to give it the first index of the array that we want to decode so it knows where to start, we do this bya dding 0 since its an array.
//3. [Count] - The number of bytes we want to decode and we created an int to hold that number above so let's pass it as a parameter.
string dataRecieved = Encoding.Default.GetString(buffer, 0, bytesRead);
if (dataRecieved == "webcam")
{
Console.WriteLine("Starting the webcam feature..");
CameraFeature();
}
}
}
}
private static void CameraFeature()
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo Device in VideoCaptureDevices)
{
Devices.Add(Device.Name);
Console.WriteLine("Device: " + Device.Name);
}
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[0].MonikerString);
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.Start();
}
private static void exitcamera()
{
FinalVideo.SignalToStop();
// FinalVideo.WaitForStop(); << marking out that one solved it
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame); // as sugested
FinalVideo = null;
}
static void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap video = (Bitmap)eventArgs.Frame.Clone();
//video.Save($"image{imgCount}.png");
Console.WriteLine("Picture taken!");
Connection(video);
exitcamera();
imgCount++;
}
public static void Connection(Bitmap tImage)
{
Console.WriteLine("Starting the transfer..");
byte[] bStream = ImageToByte(tImage);
try
{
nwStream.Write(bStream, 0, bStream.Length);
Console.WriteLine("Done..");
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
static byte[] ImageToByte(Bitmap iImage)
{
MemoryStream mMemoryStream = new MemoryStream();
iImage.Save(mMemoryStream, System.Drawing.Imaging.ImageFormat.Png);
return mMemoryStream.ToArray();
}
}
Client
private static void SendCommand()
{
while (true)
{
Console.WriteLine("Please enter a command: ");
string userInput = Console.ReadLine();
//Convert out string message to a byteArray because we will send it as a buffer later.
byte[] bytesToSend = Encoding.Default.GetBytes(userInput);
//Write out to the console what we are sending.
Console.WriteLine("Sending: " + userInput);
//Use the networkstream to send the byteArray we just declared above, start at the offset of zero, and the size of the packet we are sending is the size of the messages length.
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//RecieveBuffer();
//Recieve the bytes that are coming from the other end (server) through the client and store them in an array.
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
//byte[] bitmap = GetYourImage();
//read the bytes, starting from the offset 0, and the size is what ever the client has recieved.
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
//Decode the bytes we just recieved using the Encoding.ASCII.GetString function and give it the correct parameters
//1. What it should decode
//2. Starting to decode from what offset
//3. How much do we want to decode?
Bitmap bmp;
using (var ms = new MemoryStream(bytesToRead))
{
bmp = new Bitmap(ms);
bmp.Save("Image.png");
}
//Console.WriteLine("Recieved: " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
}
Try MemoryStream.Seek(0, SeekOrigin.Begin) before sending stream to client. You may download 0 bytes, because stream at its end when you receive it.
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 am trying to receive data at my server of any length through tcp connection. First my client sends length of data to server through stream.write then it send the actual data.
At Client I receive the length and loop until whole the data is received successfully.
The problem is: "I receive 0 size on the server no matters what the length of data is". I tried to figure out the issue but could not get where the problem is. Any kind of help/hint would be appreciated.
Server Side Code:
byte[] lengthOfData = new byte[2048];
byte[] buffer;
try
{
stream = client.GetStream();
eventLog1.WriteEntry("Size of 1st = "+stream.Read(lengthOfData,0,lengthOfData.Length));
int numBytesToRead = ByteArraySerializer.BytesArrayToInt(lengthOfData);
eventLog1.WriteEntry("number of bytes to read= "+numBytesToRead);
buffer = new byte[numBytesToRead+10];
int numBytesRead = 0;
do
{
int n = stream.Read(buffer, numBytesRead, 10);
numBytesRead += n;
numBytesToRead -= n;
eventLog1.WriteEntry("number of bytes read= " + numBytesRead);
} while (numBytesToRead > 0);
}
catch (Exception e) // Called automatically when Client Diposes or disconnects unexpectedly
{
eventLog1.WriteEntry("Connection Closes: "+e.ToString());
lock (connectedClients)
{
connectedClients.Remove(client);
}
client.Close();
break;
}
Client Side Code
byte[] command = ByteArraySerializer.Serialize<Command>(cmd);
byte[] sizeOfData = ByteArraySerializer.IntToBytesArray(command.Length);
stream.Write(sizeOfData, 0, sizeOfData.Length);
Console.WriteLine("Size of Data = "+command.Length);
stream.Write(command, 0, command.Length);
Change the following line at server
byte[] lengthOfData = new byte[2048];
to
byte[] lengthOfData = new byte[sizeof(int)];
The issue was that the read at server was supposed to read only 4 bytes integer whereas it was reading other data as well which was getting written after writing the length of data. We are supposed to read only 4 bytes if we want to get the length of data(integer).
I have the following code:
private string Connect()
{
string responseData;
try
{
TcpClient client = new TcpClient(ServerIp, Port);
client.ReceiveBufferSize = Int32.MaxValue;
Byte[] data = Encoding.GetEncoding(1251).GetBytes(ReadyQuery);
NetworkStream stream = client.GetStream();
// send data
stream.Write(data, 0, data.Length);
// buffer
data = new Byte[65536];
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = Encoding.GetEncoding(1251).GetString(data, 0, bytes);
// close all
stream.Close();
client.Close();
return responseData;
}
I have problem with a big message. The receive message size is 22K chars. I get only part of message.
How can I receive big messages?
PS. In the debugger bytes equal 4096.
You call stream.Read in a loop until you read the entire message. If you know the message size in advance it's relatively easy:
int messageSize = 22000;
int readSoFar = 0;
byte [] msg = new byte[messageSize];
while(readSoFar < messageSize)
{
var read = stream.Read(msg, readSoFar, msg.Length - readSoFar);
readSoFar += read;
if(read==0)
break; // connection was broken
}
If the message size is part of the message (say, encoded in the first 4 bytes), you should read those first and then do as I suggested.
I am using network stream to send a file name (example :"text.txt") and then send the file. the server is supposed to read the name and create a write stream to write the data in. the problem that the server gets the name + data from the file in the read command to get the name only. i think this is unclear.
the question i get the file name + some data from the file.
code that sends file name then file data:
ASCIIEncoding asci = new ASCIIEncoding();
TcpClient clientSocket = new TcpClient(textBox2.Text, 8880);
NetworkStream networkStream = clientSocket.GetStream();
byte[] b = asci.GetBytes(s);//s is the name of the file
networkStream.Write(b, 0, b.Length);
networkStream.Flush();
while(true)
{
file = fileStream.Read(fileBuffer,0,fileBuffer.Length);
networkStream.Write(fileBuffer,0,file);
if(file == 0) break;
}
the code that the server rec. the name and data with
byte [] buffer2 = new byte[1];
String filename = "";
ASCIIEncoding asci = new ASCIIEncoding();
while (true)
{
int k = networkStream.Read(buffer2, 0, buffer2.Length);
filename = filename+asci.GetString(buffer2, 0, k);
if (k == 0) break;
}
using (Stream fileStream = File.OpenWrite("C:/Users/Laptop/Documents/" + filename))
{
while (true)
{
thisRead = networkStream.Read(dataByte, 0, blockSize);
fileStream.Write(dataByte, 0, thisRead);
if (thisRead == 0) break;
}
thanks. i think i dont know how to say or illustrate the problem.
You have to send something that indicates the end of the filename. The server receives the filename as long as this or these stop characters are not received and it receives the payload afterwards.
For example, HTTP uses \r\n\r\n to mark the end of the HTTP header.