Thread: File transfer- the file sometimes not full transferred

  1. #1
    Registered User
    Join Date
    Dec 2008
    Posts
    9

    File transfer- the file sometimes not full transferred

    Hi,
    Recently i found out one code from a website. I try to run it, sometimes i can get back the transferred file with original size but sometimes cannot. Some bytes of the file is missing when received it from the server.I unable to open the file that lost some bytes and it shows the file is damaged. This condition is not consistent. I have try many method to find out what problem, but seems like no results for it.Is there any solution to solve this problem?

    The code is as below:
    Code:
    //FILE TRANSFER USING C#.NET SOCKET - SERVER
    class FTServerCode
    {
    IPEndPoint ipEnd;
    
    Socket sock;
    public FTServerCode()
    {
    ipEnd = new IPEndPoint(IPAddress.Any, 5656);
    
    //Make IP end point to accept any IP address with port no 5656.
    
    sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    
    //Here creating new socket object with protocol type and transfer data type
    sock.Bind(ipEnd);
    
    //Bind end point with newly created socket.
    }
    public static string receivedPath;
    public static string curMsg = "Stopped";
    public void StartServer()
    {
    try
    {
    curMsg = "Starting...";
    sock.Listen(100);
    /* That socket object can handle maximum 100 client connection at a time & waiting for new client connection /
    curMsg = "Running and waiting to receive file.";
    Socket clientSock = sock.Accept();
    /* When request comes from client that accept it and return new socket object for handle that client. */
    byte[] clientData = new byte[1024 * 5000];
    
    int receivedBytesLen = clientSock.Receive(clientData);
    curMsg = "Receiving data...";
    
    int fileNameLen = BitConverter.ToInt32(clientData, 0);
    
    /* I’ve sent byte array data from client in that format like [file name length in byte][file name] [file data], so need to know first how long the file name is. /
    string fileName = Encoding.ASCII.GetString(clientData, 4, fileNameLen);
    /* Read file name */
    BinaryWriter bWrite = new BinaryWriter(File.Open(receivedPath +"/"+ fileName, FileMode.Append)); ;
    
    /* Make a Binary stream writer to saving the receiving data from client. /
    bWrite.Write(clientData, 4 + fileNameLen, receivedBytesLen - 4 - fileNameLen);
    /* Read remain data (which is file content) and save it by using binary writer. */
    curMsg = "Saving file...";
    
    bWrite.Close();
    clientSock.Close();
    
    /* Close binary writer and client socket */
    curMsg = "Reeived & Saved file; Server Stopped.";
    }
    catch (Exception ex)
    {
    curMsg = "File Receving error.";
    }
    }
    }
    
    </code>
    
    Code for Client Application:
    
    <code>
    
    //FILE TRANSFER USING C#.NET SOCKET - CLIENT
    class FTClientCode
    {
    public static string curMsg = "Idle";
    public static void SendFile(string fileName)
    {
    try
    {
    IPAddress[] ipAddress = Dns.GetHostAddresses("localhost");
    IPEndPoint ipEnd = new IPEndPoint(ipAddress[0], 5656);
    
    /* Make IP end point same as Server. */
    Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    /* Make a client socket to send data to server. */
    
    string filePath = "";
    /* File reading operation. */
    fileName = fileName.Replace("\\", "/");
    while (fileName.IndexOf("/") > -1)
    {
    filePath += fileName.Substring(0, fileName.IndexOf("/") + 1);
    fileName = fileName.Substring(fileName.IndexOf("/") + 1);
    }
    
    
    byte[] fileNameByte = Encoding.ASCII.GetBytes(fileName);
    if (fileNameByte.Length > 850 * 1024)
    {
    curMsg = "File size is more than 850kb, please try with small file.";
    return;
    }
    
    curMsg = "Buffering ...";
    byte[] fileData = File.ReadAllBytes(filePath + fileName);
    
    /* Read & store file byte data in byte array. */
    byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];
    
    /* clientData will store complete bytes which will store file name length, file name & file data. */
    byte[] fileNameLen = BitConverter.GetBytes(fileNameByte.Length);
    /* File name length’s binary data. */
    fileNameLen.CopyTo(clientData, 0);
    fileNameByte.CopyTo(clientData, 4);
    fileData.CopyTo(clientData, 4 + fileNameByte.Length);
    /* copy these bytes to a variable with format line [file name length][file name] [ file content] */
    curMsg = "Connection to server ...";
    clientSock.Connect(ipEnd);
    
    /* Trying to connection with server. /
    
    curMsg = "File sending...";
    clientSock.Send(clientData);
    /* Now connection established, send client data to server. */
    curMsg = "Disconnecting...";
    clientSock.Close();
    
    /* Data send complete now close socket. */
    curMsg = "File transferred.";
    
    }
    catch (Exception ex)
    {
    if(ex.Message=="No connection could be made because the target machine actively refused it")
    curMsg="File Sending fail. Because server not running." ;
    else
    curMsg = "File Sending fail." + ex.Message;
    }
    
    }
    }
    Hope to get help from you all. Thanks.

    Regards,
    sf

  2. #2
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Code:
    int receivedBytesLen = clientSock.Receive(clientData);
    and

    Code:
    clientSock.Send(clientData);
    You can't be sure that the server receieves all of the data in one read, or the server sends it all in one write. You probably will want to include in your protocol the length of the file, say the first 4 bytes can say this. Then your server can read in a loop until it gets all these bytes. For the client you just need to make sure you get all the bytes wrote out to write. So do another loop until send has returned all the expected bytes that you are going to send.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Some decent indentation would be a bonus.
    By "bonus", I mean essential.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by shu_fei86 View Post
    Code:
    if(ex.Message=="No connection could be made because the target machine actively refused it")
    in addition to what has already been said, you really shouldn't rely on the text of an error message. there are other (better) ways of determining which error was generated.

  5. #5
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Quote Originally Posted by Elkvis View Post
    in addition to what has already been said, you really shouldn't rely on the text of an error message. there are other (better) ways of determining which error was generated.
    Like catching the SocketException.

    http://msdn.microsoft.com/en-us/library/fkbhht5w.aspx

  6. #6
    Registered User
    Join Date
    Dec 2008
    Posts
    9

    File transfer- the file sometimes not full transferred

    Hi,
    Thanks for the reply.
    Quote Originally Posted by valaris View Post
    Code:
    int receivedBytesLen = clientSock.Receive(clientData);
    and

    Code:
    clientSock.Send(clientData);
    You can't be sure that the server receieves all of the data in one read, or the server sends it all in one write. You probably will want to include in your protocol the length of the file, say the first 4 bytes can say this. Then your server can read in a loop until it gets all these bytes. For the client you just need to make sure you get all the bytes wrote out to write. So do another loop until send has returned all the expected bytes that you are going to send.
    I not really sure how to make the server receives all of the data in one read or send it all in one write ? And how to include in the protocol the length of the file? Can somebody give me some guidance? Sorry because i not really very expert in C#, but i need to solve this problem as fast as possible because it is quite urgent for me. Here thank you for help from you all and sorry for my disturbing. Thanks a lot!

    Regards,
    sf

  7. #7
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Well, you have to make up your own protocol for this that the client and server agree on. On your first transmission you can set the first 4 bytes for instance to be the length of the file. Then who ever is receiving can read in a loop until it has received that amount of bytes. This way you are guaranteed to receive all of the file. In C# check out the binary writer/reader for crafting your packets.

  8. #8
    Registered User
    Join Date
    Dec 2008
    Posts
    9

    File transfer- the file sometimes not full transferred

    Hi,

    Quote Originally Posted by valaris View Post
    Well, you have to make up your own protocol for this that the client and server agree on. On your first transmission you can set the first 4 bytes for instance to be the length of the file. Then who ever is receiving can read in a loop until it has received that amount of bytes. This way you are guaranteed to receive all of the file. In C# check out the binary writer/reader for crafting your packets.
    If need to set the first 4 bytes to be length of the file, where should i put it? I not really sure for it. Both client server need to set this 4 bytes as well? Any changes do i need to make for binary writer / reader? Sorry for that because i am just a C# beginner. Hope sir can give me some guidance. Thank you very much.

    Regards,
    sf

  9. #9
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Here is a routine you can use to build the packet that the client will send to the server. The first sizeof(int) bytes will contain the length of the file in bytes that you are sending. Immediately after those bytes will begin the actual file data. Now since TCP is a byte stream protocol, and it guarantees that the bytes you send will arrive in order, on the server side we can peek until there are sizeof(int) bytes in the receive buffer. Once we have those bytes we know the length of the file. After that we can just call some other routine to block on a read of the socket until it reads those total number of bytes from the stream. After that simply return your array of bytes and use it for whatever you want on the server.

    Code:
            static byte[] GetFileBuffer(string FileName)
            {
                if (!File.Exists(FileName))
                    throw new FileNotFoundException("Could Not Find " + FileName);
    
                using (MemoryStream ms = new MemoryStream())
                {
                    using (BinaryWriter br = new BinaryWriter(ms))
                    {
                        FileInfo Info = new FileInfo(FileName);
                        br.Write((int)Info.Length);
                        br.Write(File.ReadAllBytes(FileName));
    
                        //The stream expands as you add bytes, make sure the final buffer
                        //is the specified size.
                        ms.Capacity = (int)Info.Length + sizeof(int);
                        return ms.GetBuffer();
                    }
                }
            }
    Note the using blocks are just syntactic sugar for calling the dispose method from the IDispose interfaces that those classes implement. This insures that any resources that the objects used will be disposed of (and in many cases also surpresses the GC from performing a finalize on the object for extra efficiency).
    Last edited by valaris; 02-20-2009 at 12:19 AM.

  10. #10
    Registered User
    Join Date
    Dec 2008
    Posts
    9

    File transfer- the file sometimes not full transferred

    Hi,
    Quote Originally Posted by valaris View Post
    Code:
            static byte[] GetFileBuffer(string FileName)
            {
                if (!File.Exists(FileName))
                    throw new FileNotFoundException("Could Not Find " + FileName);
    
                using (MemoryStream ms = new MemoryStream())
                {
                    using (BinaryWriter br = new BinaryWriter(ms))
                    {
                        FileInfo Info = new FileInfo(FileName);
                        br.Write((int)Info.Length);
                        br.Write(File.ReadAllBytes(FileName));
    
                        //The stream expands as you add bytes, make sure the final buffer
                        //is the specified size.
                        ms.Capacity = (int)Info.Length + sizeof(int);
                        return ms.GetBuffer();
                    }
                }
            }
    I try this code already but i fail to transfer the file. Is it i need to change something at the server there which is the receiver part? I have no idea on what to change at the receiver part. Is there any hints to it?
    Please guide. Thanks!

    Regards,
    sf

  11. #11
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    On the client side use this routine to return to you an array of bytes that you must send. Then in a loop make sure the length of this array gets sent out to the server. Now on the server wait until you can read 4 bytes to get the file length, then in a recv loop grab that amount of bytes and return that byte array to some caller. So yes...you have to now modify the server to deal with the new packet structure.

    So I would start out my checking the sockets Available property for 4 bytes (the length of the file). If there are 4 bytes read them into a byte array. Then you can call BitConverter.ToInt32() on that buffer to get the length of the file. Now write a routine that will sit in a loop, filling a buffer from the socket until it has read that amount of bytes in the initial 4 byte header.
    Last edited by valaris; 02-20-2009 at 09:23 AM.

  12. #12
    Registered User
    Join Date
    Dec 2008
    Posts
    9

    File transfer- the file sometimes not full transferred

    Hi, Valaris

    I had tried the method that you suggested, the 1st 4 bytes are the file size and the following bytes are file and It help to solve my doubt.

    However, I found out that the main reason that cause the file transfer incomplete most of the time is due to the socket close by the client before the server able to received all the file. It cause the remaining byte being clear by the client.

    Thanks for your help. You help me a lot and i learn a lot from here.

    Thank you very much!

    Regards,
    sf

  13. #13
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    No problem and good luck,

    I would definently make sure your method of transfer/receiving is different though to guarantee all the bytes are sent/receieved, or your program will be unreliable at best!

  14. #14
    Registered User
    Join Date
    Mar 2009
    Posts
    1
    Quote Originally Posted by shu_fei86 View Post
    Hi, Valaris

    However, I found out that the main reason that cause the file transfer incomplete most of the time is due to the socket close by the client before the server able to received all the file. It cause the remaining byte being clear by the client.
    Thank you very much for this information. I had the same problem. In client code:

    instead of:

    curMsg = "Disconnecting...";
    clientSock.Close();

    I have used:

    curMsg = "Disconnecting...";
    Thread.Sleep(100);
    clientSock.Close();

    So that, the client cannot close the socket before the transmission is complete. If you are using larger files, you can write 200 instead of 100. This is my 1-line code solution, but of course I cannot guarantee that it works always ...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. To find the memory leaks without using any tools
    By asadullah in forum C Programming
    Replies: 2
    Last Post: 05-12-2008, 07:54 AM
  2. Need Help Fixing My C Program. Deals with File I/O
    By Matus in forum C Programming
    Replies: 7
    Last Post: 04-29-2008, 07:51 PM
  3. Can we have vector of vector?
    By ketu1 in forum C++ Programming
    Replies: 24
    Last Post: 01-03-2008, 05:02 AM
  4. help with text input
    By Alphawaves in forum C Programming
    Replies: 8
    Last Post: 04-08-2007, 04:54 PM
  5. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM