开发者

sending binary files through TCP sockets c

I made a client & server that establishes a TCP connection through sockets, I'm trying to send binary data over the socket but I could only send txt or pdf files, I had no luck with exe files, I use fread and fseek to read the file and split it into a buffer. When I read the whole exe file it gets sent successfully but when I split it, it gets sent corrupted!

I read some books about sockets but I still don't know much and I have some questions.

is it okay to send the whole file in one send()?? or I should continue with sending it in small chunks?

Also, why exe files get corrupted when I send them in chunks?

Thank you!

Client Code (in c):

int bufSize = 10000;
int sentBytes = 0;


  FILE * pFile;
  long remainingBytes;
  char * buffer;
  size_t result;

  pFile = fopen ( "D:\\file.exe" , "rb" );
  fseek (pFile , 0 , SEEK_END);
  remainingBytes = ftell (pFile);
  rewind (pFile);

int bufferSize = remainingBytes > bufSize ? bufSize : remainingBytes;
buffer = (char*) malloc (sizeof(char)*bufferSize);
send(Socket, (char*)&remainingBytes, 4, 0);

while(remainingBytes > 0)
{
    fseek (pFile , sentBytes , SEEK_SET);
    result = fread(buffer,1,bufferSize,pFile);
    if(bufferSize < remainingBytes)
    {
        send(Socket, buffer, bufferSize, 0);
    }
    else
    {
        send(Socket, buffer, remainingBytes, 0);
        bufferSize = remainingBytes;
    }
    remainingBytes -= bufferSize;
    sentBytes += bufferSize;
}

Server code (in c#)

        try
        {
            int bufferSize = 200;
            int len = 0;
            int receivedBytes = 0;
            int remainingBytes = len;
            byte[] length = new byte[4];
            //byte[] imgBuf = new byte[bufferSize];

            int current = 0;
            List<byte[]> coming = new List<byte[]>();

            sockets[number].Receive(length,4,0);

            len = BitConverter.ToInt32(length, 0);
            remainingBytes = len;

            bufferSize = len < bufferSize ? len : bufferSize;

            while(receivedBytes < len)
            {
                if (remainingBytes > bufferSize)
                {
                    coming.Add(new byte[bufferSize]);
                    //imgBuf = new byte[bufferSize];
                    sockets[number].Receive(coming[current], bufferSize, 0);
                }
                else
                {
                    coming.Add(new byte[remainingBytes]);
                    //imgBuf = new byte[remainingBytes];
                    sockets[number].Receive(coming[current], remainingBytes, 0);
                    bufferSize = remainingBytes;
                }
                remainingBytes -= bufferSize;
                receivedBytes += bufferSize;
                current++;
                //Array.Clear(imgBuf, 0, imgBuf.Length);
            }

            using (var stream = new FileStream(@"C:\receivedFile.exe",FileMode.Create))
            {
                using (var binaryWriter = new BinaryWriter(stream))
                {
                    foreach (byte[] buffer in coming)
                    {
                        binaryWriter.Write(buffer);
                    }
                }

            }
        }
        catch (Exception ex)
        { this.setText(ex.Message, textBox2); }

Edit: Thanks for the help, I got it working :)

        try
        {
            int bufferSize = 1024 * 100;
            int len = 0;
            int receivedBytes = 0;
            int remainingBytes = len;
            int reached = 0;

            byte[] length = new byte[4];
            byte[] imgBuf = new byte[bufferSize];

            int current = 0;
            sockets[number].Receive(length,4,0);

            len = BitConverter.ToInt32(length, 0);
            remainingBytes = len;

           开发者_开发知识库 bufferSize = len < bufferSize ? len : bufferSize;
            imgBuf = new byte[len];

            while (reached < len)
            {
                reached += sockets[number].Receive(imgBuf, receivedBytes, remainingBytes, 0);
                remainingBytes = len - reached;
                receivedBytes = reached;
                current++;
                //Array.Clear(imgBuf, 0, imgBuf.Length);
            }

            using (var stream = new FileStream(@"C:\putty.exe",FileMode.Create))
            {
                using (var binaryWriter = new BinaryWriter(stream))
                {
                        binaryWriter.Write(imgBuf);
                }
            }
            Array.Clear(imgBuf, 0, imgBuf.Length);
        }
        catch (Exception ex)
        { this.setText(ex.Message, textBox2); }


You don't check how many bytes you actually received in sockets[number].Receive(coming[current], bufferSize, 0); . It doesn't have to be equal to the buffer size you have declared. Additionaly, as said in comments, keeping whole file in memory is not a good idea.


In addition to checking the number of bytes received, you need to check the number of bytes sent by each send call -- if your TCP transmit window fills up, a send call might send less data than you requested, in which case the you'll need to resend the unsent data.

In general, you ALWAYS need to check the return value of your system calls to check for the all the various odd corner cases that can occur. Read the man pages for send(2) and recv(2) for a full list of everything that can happen.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜