【问题标题】:How to receive a text file from Android to C using TCP/IP Protocol. I am having data loss如何使用 TCP/IP 协议从 Android 接收文本文件到 C。我有数据丢失
【发布时间】:2015-08-09 01:12:47
【问题描述】:

我已经编写了从 Android 接收文件到 C 的代码,但问题是我收到数据丢失。将接收到的文本文件与原始文本文件进行检查时,字节不匹配。如何根除这种情况?我已经给出了代码供参考。`

  #include<stdio.h>
  #include<unistd.h>
  #include<string.h>    
  #include<stdlib.h>
  #include<sys/ioctl.h>
  #include<sys/types.h>
  #include<arpa/inet.h>
  #include<sys/socket.h>

  int receive_text(long int new_socket)
  {
      int buffersize = 0, recv_size = 0, size = 0, read_size,     write_size;
      char verify = '1';
      int errno;
      FILE *text;
      char *pBuf;

      //Find the size of the text
      recv(new_socket, (char *)&size, sizeof(int), 0);
      //Send our verification signal
      //send(new_socket, &verify, sizeof(char), 0);
      text = fopen("/home/sosdt009/Desktop/received.txt", "w");

      if (text == NULL)
      {
        puts("Error has occurred. Text file could not be opened \n");
        return -1;
      }

      //Loop while we have not received the entire file yet
      while (recv_size < size)
      { 
         ioctl(new_socket, FIONREAD, &buffersize);
         //We check to see if there is data to be read from the socket 
         if (buffersize > 0)
         {
            pBuf = malloc(buffersize);
            if (!pBuf)
            {
              fprintf(stderr, "Memory Error. Cannot allocate!\n");
              exit(-1);
            }
            //memset(pBuf,0,buffersize);
            read_size = recv(new_socket, pBuf, buffersize, 0);
            if (read_size < 0)
            {
               printf("%s", strerror(errno));
            }
            //Write the currently read data into our text file
            write_size = fwrite(pBuf, 1, buffersize, text);
            free(pBuf);
            printf("%d \n", write_size);
            //Increment the total number of bytes read
            recv_size += write_size;        
            printf(" %d \n", recv_size);
        }           
     }
     fclose(text);
     return 1;
 }

 int main(int argc , char *argv[]) {
    int socket_desc , new_socket, c, read_size, buffer = 0;
    struct sockaddr_in server , client;
    char *readin;
    //Create socket
    socket_desc = socket(AF_INET,SOCK_STREAM,0);
    if (socket_desc == -1)
    {
      printf("Could not create socket:");
    }
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 6777 );
    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
       puts("bind failed");
       return 1;
    }
    puts("Bind completed");
    //Listen
    listen(socket_desc,3);
    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);
    if((new_socket = accept(socket_desc,(struct sockaddr *)&client,(socklen_t *)&c)) )
    {
      puts("Connection accepted");
    }
    fflush(stdout);
    close(socket_desc);
    if (new_socket<0)
    {
        perror("Accept Failed");
        return 1;
    }
    while(1)
    {       
      receive_text(new_socket);
    }
    close(socket_desc);
    return 0;
 }

【问题讨论】:

  • 您可能希望记录收到的size 的值并验证它是否正确。

标签: c sockets system-calls tcp-ip


【解决方案1】:

这里

read_size = recv(new_socket, pBuf, buffersize, 0);

recv() 告诉您它为当前迭代接收了多少字节,即 read_size 字节。

这里

write_size = fwrite(pBuf, 1, buffersize, text);

你忽略接收到的字节数,但总是写buffersize

通过将实际接收到的数据量写入目标文件来解决此问题:

write_size = fwrite(pBuf, 1, read_size, text);

recv() 的调用接收到的字节数完全错过了任何错误检查。

在传输二进制数据时,您还需要确保不要绊倒

  1. 发送方和接收方整数值的宽度可能不同
  2. 发送方和接收方的字节顺序不同

要解决上述第一个可能的问题,请在位宽方面使用明确定义的数据类型。这里int32_t 而不是int 或者可能是未签名的学究:unint32_t

对于第二个可能的陷阱,按网络字节顺序传输数据。要实现这一点,请不要发送普通的int(或uint32_t),而是通过调用htonl() 将其转换为网络字节顺序(在发送之前)。然后在接收端使用ntohl() 将其转换回主机字节顺序。


发送方在传输过程中关闭套接字的情况被忽略,但应通过测试recv()0的结果来处理,这表明发送方关闭了套接字。


在调用accept() 时将int c 转换为socklen_t 可能会引发未定义的行为。

解决这个问题而不是

int c;

定义

socklen_t c;

另外2代码关闭socket_desc两次,根本不关闭new_socket


还有3在做

ioctl(new_socket, FIONREAD, &buffersize);

测试数据是否可用确实有意义,因为套接字的缓冲区是由内核异步填充给程序的,因此调用 ioctl() 返回的值可能会在眨眼之间过时。

只需删除对ioctl() 的调用并定义一个固定大小的缓冲区来读取。 recv() 将阻塞直到数据可用。

【讨论】:

  • 我已经按照上面的cmets修改了代码,但是还是有数据丢失。
猜你喜欢
  • 2021-09-11
  • 1970-01-01
  • 2015-10-22
  • 2020-01-29
  • 2018-06-25
  • 2015-11-13
  • 1970-01-01
  • 2017-09-18
  • 1970-01-01
相关资源
最近更新 更多