在tcp套接字传输中丢失字符串的第一个字符 - C

时间:2015-08-02 21:59:46

标签: c sockets debugging tcp

我在C中使用linux套接字设置了服务器和客户端。由于某种原因,我尝试发送的缓冲区的第一个字符丢失了(我给出的示例中的括号)。我认为这将是一个非常简单的调试周末,但到目前为止,我已经无处可去了。我认为发送前缓冲区是正确的,但发送后错误。我对套接字没有经验,这是我第一次尝试这种类型的东西,我真的很感激任何指针。该程序(可能更新)将用于接收我实习的公司的GPS跟踪坐标,这是我明天的最后一天,我真的很想让他们留下一些无用的东西。如果我没有提供足够的信息,那么请问!我试图在一个简单的c脚本中模拟我希望从客户端收到的输入。我相信这个问题可能是send()和recv()函数的第三个参数,但我真的不知道。在此先感谢,这是我的代码:

server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define MYPORT 3490
#define BACKLOG 10
#define ONETRANSFER 1056
#define IDLENGTH 5

void sigchld_handler(int s) {
    while(wait(NULL) > 0);
}

char* receiveFileName(int fd) {
  char *fileName = malloc((IDLENGTH + 4) * sizeof(char));
  int numBytes;
  fileName[0] = 't';
  fileName[1] = 'a';
  fileName[2] = 'g';
  if((numBytes = recv(fd, &fileName[3], IDLENGTH, 0)) == -1) {
    /* Print to a log file here? Don't know the identity of the tag yet */
    printf("Error in receiveFileName");
    exit(1);
  } 
  fileName[IDLENGTH + 3] = '\0';
  return fileName;
}

char* receiveData(int fd, char* fileName, int dataSize) {
  int dataReceived;
  FILE *fp = fopen(fileName, "ab");//If this doesn't work try w, I think append is correct though
  int i; 
  for(i = 0; i < dataSize; i++) {
    char dataBuf[ONETRANSFER]; 
    int remainingData = ONETRANSFER;
      while(((dataReceived = recv(fd, &dataBuf, ONETRANSFER, 0)) >= 0) && (remainingData > 0)) {  
    if(dataReceived == 0){ 
      printf("no data received\n");
      break;
    }

    fwrite(dataBuf, sizeof(char), strlen(dataBuf), fp);
    remainingData -= dataReceived;
    //  printf("Received %d bytes. We hope to receive %d more", dataReceived, remainingData); //For debug
    printf("i = %d\n", i);
      }
      printf("exited\n");
  }
  fclose(fp);
  //close(fd);
} 



/* Sets up socket */
int setUpSocket() {
  int sockfd;
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Error setting up socket()");
        exit(1);
  }
  return sockfd;
}


/* Bind the socket */
void serverBind(int sockfd, struct sockaddr_in my_addr) {
  if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1){
    perror("Error in bind()");
    exit(1);
  } else {
    printf("Server-bind() is OK...\n");
  }
}

int receiveDataSize(int fd) {
  int dataSize, numBytes;
  char buf[4];
  if(numBytes = recv(fd, buf, 4, 0) == -1) {
    /* Connection error, undecided as to how to respond atm */
  }
  buf[2] = '\0';
  dataSize = strtol(buf, NULL, 10); /* 10 makes it decimal */
  printf("The size is %d\n", dataSize);
  return dataSize;
}

/* Listen and wait for the client */
void serverListen(int sockfd) {
  if(listen(sockfd, BACKLOG) == -1) {
    perror("Server-listen() error");
    exit(1);
  } else {
    printf("Server-listen() is OK...Listening...\n");
  }
}

int main(int argc, char* argv[]) {
  int sockfd, newfd;        /* listen on sock, new connection on new_fd */
  struct sockaddr_in my_addr;   /* my address info */
  struct sockaddr_in their_addr; /* their adress info */
  int sin_size;
  struct sigaction sa;
  int yes = 1;          /* Need this as a pointer later */

  sockfd = setUpSocket();

  /* Set sock options */

  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
        perror("Error in setsockopt()");
        exit(1);
    }

  /* host byte order */
  my_addr.sin_family = AF_INET;
  /* short, network byte order */
  my_addr.sin_port = htons(MYPORT);
  /* automatically fill with my IP */
  my_addr.sin_addr.s_addr = INADDR_ANY;

  /* zero the rest of the struct */
  memset(&(my_addr.sin_zero), '\0', 8);

  serverBind(sockfd, my_addr);
  /* Set the server to listen for tags */
  serverListen(sockfd);

  /* clean all the dead processes */
  sa.sa_handler = sigchld_handler;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_RESTART;

  if(sigaction(SIGCHLD, &sa, NULL) == -1){
        perror("Sigaction() error");
        exit(1);
  }

  /* accept loop */
  while(1) {
    sin_size = sizeof(struct sockaddr_in);
    if((newfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
    perror("Error in accept()");
    continue;
    } 
    /* If weird things start to happen include a case for fork unsuccessful */
    /* This is the child process */
    if(!fork()){
      /* Maybe encorporate these two into one function? */
      char* fileName = receiveFileName(newfd);
      printf("The fileName is: %s", fileName);
      int dataSize = receiveDataSize(newfd); /* return the value as a factor of 1056 e.g forg 2112 return 2*/
      printf("The dataSize is: %d", dataSize);
      receiveData(newfd, fileName, dataSize);
      close(newfd);
      exit(0);
    } else {
      /* This is the parent process, looks silly but needed to fork */
    }
    close(newfd);
  }
  return 0;
}

emulate.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 3490
#define SINGLETRANSFER 1056
#define IDLENGTH 5
#define ID 12345

int setUpSocket(void) {
  int sockfd;
  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("Error setting up socket");
    exit(1);
  }
  return sockfd;
}

void sendSize(char* buf, int fd) {
  int bufLength = strlen(buf) + 1;
  int dataSize = ((bufLength - 1) / SINGLETRANSFER) + 1; /* Number of "sections" sent */
  printf("DataSize is %d", dataSize);
  char sizeString[3]; //Here I am assuming that it wont be greater than 99 * 1056
  sprintf(sizeString, "%d", dataSize);
  if(send(fd, sizeString, 3, 0) == -1) {
    perror("Error in sendLength");
    exit(1);
  }
}

void sendId(int fd, const char* id) {
  int checkByte;
  if((checkByte = send(fd, id, IDLENGTH, 0) == -1)) {
      perror("Error in sending ID");
    }
}

void sendData(char* data, int fd) {
  int dataLength = strlen(data) + 1;
  int totalBytesWritten = 0;
  int numBytes;
  printf("data[0] is: %c", data[0]);
  while(totalBytesWritten != SINGLETRANSFER) {
    //assert(totalBytesWritten < 1056);
    if(numBytes = send(fd, data, dataLength - totalBytesWritten, 0) == -1) {
      //printf("data left: %d\n", dataLength - totalBytesWritten);
      perror("Error in sending in sendData()");
      exit(1);
       } else if (numBytes == 0) {
      //printf("%d", totalBytesWritten);
       break;
    } else {
      //printf("data left: %d\n", dataLength - totalBytesWritten);
      //printf("numbytes: %d", numBytes);
      totalBytesWritten += numBytes;
    }  
  }
}

int main(int argc, char *argv[]) {
  const char* id = "44444";  
  int sockfd, numbytes;
  char* ip = "127.0.0.1";

  /* I have no idea why but the first byte is being lost at some point, I have added a "NULL" byte at the beginning*/
    char* data = "(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,01end"; /* 1056 bytes, it's a test file, doesn't need to be pretty :) */
  struct hostent *he;
  /* The address information of the connector */
  struct sockaddr_in their_addr;

  /* Get host info */
  if((he = gethostbyname(ip)) == NULL) {
    perror("getHostbyName");
    exit(1);
  }
  /* set up the socket */
  sockfd = setUpSocket();

  /* Host byte order */
  their_addr.sin_family = AF_INET;
  their_addr.sin_port = htons(PORT);
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);

  /* Set rest of struct to zero */
  memset(&(their_addr.sin_zero), '\0', 8);

  if(connect(sockfd, (struct sockaddr *) &their_addr, sizeof(struct sockaddr)) == -1) {
    perror("Error in connect()");
    exit(1);
  }  else {
    printf("Connected ok\n");
  }
  /* Send the tag's ID */
  sendId(sockfd, id);

  printf("size of data is: %zu\n", strlen(data));
  printf("The size of (int) data is: %d\n",(int) strlen(data));
  /* Send the size of buffer (number of iterations of 1056) */
  sendSize(data, sockfd);

  /* Send the data */
  sendData(data, sockfd);

  return 0;
}

客户端一次发送1056个字节的数据,直到数据用完为止(我无法控制)

2 个答案:

答案 0 :(得分:0)

交换数据大小时,发送三个字节的大小,但要求接收四个字节。假设这些调用实际上发送了三个字节,并且接收了四个字节,(这是无法保证的,你应该检查返回的值),然后是“receiveDataSize()&#39;将占用后面数据的第一个字节:(

答案 1 :(得分:0)

您提供的代码中存在大量错误,例如这也有问题:

while(((dataReceived = recv(fd, &dataBuf, ONETRANSFER, 0)) >= 0) && (remainingData > 0)) {  
if(dataReceived == 0){ 
  printf("no data received\n");
  break;
}

fwrite(dataBuf, sizeof(char), strlen(dataBuf), fp);
remainingData -= dataReceived;
//  printf("Received %d bytes. We hope to receive %d more", dataReceived, remainingData); //For debug
printf("i = %d\n", i);
  }

应该是:

 fwrite(dataBuf, sizeof(char), dataReceived , fp);