-1

I'm running out of idea in my file sharing application where I am receiving data on server from client side using FileStream.copyto().It works well but currently i have set the buffer size of 1024 for var bytesread = fs.Read(buffer, 0, buffer.Length) but I have two issues :

  1. I am unsure about the maximum size it allows before buffer overflow.Should it be a hit and trial method ? or is there a fixed bytes limit to transfer data on WLAN.

  2. When i checked the code on server side using hard-coded filename with extension like in FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read) where i pre-defined path ,it works but how would I enable it to get the file name. I mean,should i use a fix-protocol where i should allocate a pre-data bytes for it and then check & recieve on server side before data copying ?

Any good idea.

1 Answers1

1

Without code and a more precise description, it's hard to know what you actually need here. But, if I understand correctly you have a scenario where a client endpoint is reading a local file and sending the data to the server endpoint, and the server endpoint is using a NetworkStream object for the I/O.

Assuming that's the case, then the client can include the file name with something like this:

void TransmitFileName(Stream stream, string fileName)
{
    byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName),
        fileNameLengthBytes = BitConverter.GetBytes(fileNameBytes.Length);

    stream.Write(fileNameLengthBytes, 0, 4);
    stream.Write(fileNameBytes, 0, fileNameBytes.Length);
}

On the server, assuming you have already read the data into an appropriately-sized byte[] buffer, you can decode the information as follows:

string DecodeFileName(Stream stream)
{
    byte[] fileNameLengthBuffer = new byte[4];

    FillBufferFromStream(stream, fileNameLengthBuffer);
    int fileNameLength = BitConverter.ToInt32(fileNameLengthBuffer, 0);

    byte[] fileNameBuffer = new byte[fileNameLength];

    FillBufferFromStream(stream, fileNameBuffer);
    return Encoding.UTF8.GetString(fileNameBuffer);
}

void FillBufferFromStream(Stream stream, byte[] buffer)
{
    int cbTotal = 0;
    while (cbTotal < buffer.Length)
    {
        int cbRead = stream.Read(buffer, cbTotal, buffer.Length - cbTotal);

        if (cbRead == 0)
        {
            throw new InvalidDataException("premature end-of-stream");
        }

        cbTotal += cbRead;
    }
}

I leave the actual server-side I/O as an exercise for the reader. Do note, however, that using TCP you are not guaranteed any given read operation will block until all the bytes you've asked for have been read. So you will need to read continuously until you've gotten all of the bytes you need for the decoding operation to succeed.

<EDIT> I've added the necessary logic to read the data from the NetworkStream object. Note that I include a helper method that will check the actual number of bytes read, and continue to read bytes, filling the buffer until as many bytes as are needed are actually read. You cannot count on the Read() method to block until you've actually read all of the bytes you were hoping for.</EDIT>

In practice, this probably means doing the decoding in two parts: first part to get the fileNameLength value (which you know requires 4 bytes), and the second part to get the file name (the length of which you will know only after decoding the fileNameLength value).

After the bytes for the file name, you can just transmit the file data itself just as you were before.


EDIT: To use the above in the context of the code you posted…

Client: call the TransmitFileName() method before you send the actual file data. E.g.:

using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    TransmitFileName(netstream, Path.GetFileName(path));
    ...

Server: call the DecodeFileName() method before you receive the actual file data. E.g.:

//open a stream to get data 
NetworkStream netStream = client.GetStream(); 

//Directory to save
string DirName = @"D:\NewFolder\Test\";

//File Name is requirement here to save data at.

string fileloc = Path.Combine(DirName, DecodeFileName(netStream));
MessageBox.Show(fileloc);
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Why `4 bytes` for `fileNameLengthBytes`? – yeung Leone Jan 04 '15 at 07:12
  • Because the length of the array is represented by the `System.Int32` type, i.e. a 32-bit integer, i.e. four bytes. You could get away with smaller -- e.g. 2 bytes (`System.Int16` aka `short`) if you know the length will never be longer than 65535, 1 byte (`System.Byte` aka `byte`) if never longer than 255. But an `int` will make the I/O code more consistent with the underlying in-memory data, and a few extra bytes in your stream aren't going to make a noticeable difference. – Peter Duniho Jan 04 '15 at 07:17
  • Updated Question code ...u may look at my scenarion please now – yeung Leone Jan 04 '15 at 10:30
  • Ur suggestion in my scenarion means a new protocol to be adapted.ok? – yeung Leone Jan 04 '15 at 10:32
  • Yes, if you want to change the information that is transmitted by your protocol, it is required that the protocol itself is changed. If you want to call that a "new protocol", then yes...you need a new protocol. Whereas your previous protocol involved simply transmitting the entire file as the connection stream (and presumably shutting down the connection when that's completed, though you don't show that in your posted code), if you want to send the file name, then you have to change your protocol so that the file name is included in the data sent, and in a way that the receiver can interpret. – Peter Duniho Jan 04 '15 at 17:42
  • Would u plz.modify your answwer for that purpose...I have edited my Question code to get to know the idea. – yeung Leone Jan 05 '15 at 05:58
  • @CrystalHeart: Please see my edit. This should be enough to get your specific question answered. Good luck. – Peter Duniho Jan 05 '15 at 07:26