首页 文章

套接字编程在C中用循环发送和接收消息

提问于
浏览
0

我刚开始学习套接字编程,我正在尝试使用TCP在客户端和服务器之间发送和接收 . 首先,我从服务器向客户端发送当前目录的大小,客户端正好接收它 . 然后我想直接从服务器发送当前的每个文件名,所以我创建了一个循环来这样做 . 在客户端中,我还有一个循环来接收所有文件名,这些文件名的执行次数与文件(目录大小)一样多 . 问题是,当我打印出循环中收到的内容时,缓冲区为空白 . 我意识到第一个循环接收的字节数为55,其余为0,但缓冲区始终为空 . 这是我的代码片段:

服务器:

if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory

   // get the size of the directory 
    unsigned long size = htonl(directorySize());
    n = send(newsockfd, &size, sizeof(size), 0);
    if(n < 0) syserr("can't send to server"); 

    DIR *d = opendir(".");
    struct dirent *dir;
    if (d)
      {
        while((dir = readdir(d))!= NULL)
        { memset(&buffer[0], 0, sizeof(buffer)); // clear buffer
          strcat(buffer,  dir->d_name);
          n = send(newsockfd, buffer, strlen(buffer), 0);
          if(n < 0) syserr("can't send to server"); 
        }
      closedir(d);
    }
    else{
       syserr("Error...could not get files from directory.");
    }
}

客户:

if(strcmp(buffer, "ls-remote") == 0){ //display files from server directory
     unsigned long size;

      n = recv(sockfd, &size, sizeof(uint32_t), 0);// recieve the size of the directory

      if(n < 0) syserr("can't receive from server");
      size = ntohl(size);

     while(size > 0){
       memset(&buffer[0], 0, sizeof(buffer)); // clear buffer
       n = recv(sockfd, buffer, 255, 0); // recieve directory from server 
       if(n < 0) syserr("can't send to server");
       buffer[strlen(buffer) - 1] = '\0';
       printf("recieving: %s\n", buffer); // print directory
       size--;
     }
 }

1 回答

  • 2

    这里的一个问题是发送目录大小的服务器与目录条目和接收它们的客户端之间没有同步 . 换句话说,如果目录包含entry.1,entry.2和entry.3,则客户端可以接收例如entry.1和entry.2entry.3,或entry.1entry.2和entry.3 . 即使这里没有像unicode那样作为罪魁祸首也是如此,正如JVene所建议的那样 .

    其他一些事情:

    • buffer [strlen(buffer) - 1] = '\0';在客户端代码中将切掉最后一个字符 . 它应该是缓冲区[strlen(buffer)] = '\0';代替 .
      与sizeof()运算符类型使用的
    • 一致性非常重要 . 例如,在我的Mac sizeof(长)是8,而sizeof(uint32_t)是4.这导致更缺乏有趣的副作用
      客户端和服务器之间的同步 .

    这里的“同步”问题是由于当客户端开始从套接字读取时,服务器已经编写了几个目录条目,因此客户端将它们全部读作一个字符串 . 如果将目录大小写入套接字并从套接字读取,假设缓冲区大小不同,事情就会变得更加混乱;往上看 .

    经过一些额外的实验,我提出了似乎有用的代码 . 我确信可以进行改进,还有其他方法,并且代码中没有考虑的情况,例如:如果程序正在运行时目录正在改变该怎么办这只是一段代码的证明,有望帮助您朝着正确的方向前进 .

    这里的想法是服务器将目录条目写入由NULL字符分隔的套接字 . 然后将它们用作客户端的分隔符,以区分dir条目 . 请参阅代码中的注释 .

    将dir条目写入套接字的服务器代码:

    // Assume maximum entry length is 255
    // The buffer is 256 bytes long to accommodate the NULL-terminator.
    // The terminator is important for the client as direntry delimiter.
    char buffer[256];
     // get the size of the directory
    unsigned long size = htonl(dirSize());
    int n = send(client_sock, &size, sizeof(size), 0);
    if(n < 0) puts("can't send size to server");
    
    DIR *d = opendir(".");
    struct dirent *dir;
    if (d)
      {
        while((dir = readdir(d))!= NULL)
        {
          memset(&buffer[0], 0, sizeof(buffer)); // clear buffer
          strcat(buffer,  dir->d_name);
          // Write up to 255 chars of direntry + the NULL-terminator.
          n = send(client_sock, buffer, strlen(buffer) + 1, 0);
          if(n < 0) puts("can't send entry to server");
        }
      closedir(d);
    }
    else{
       puts("Error...could not get files from directory.");
    }
    

    从套接字读取的客户端代码:

    char buffer[256];
    
       /*
        * We need this in case the beginning of a directory entry is in one buffer, but
        * the end is in the next.
        */
       char buf_1[256];
       unsigned long size;
    
       buf_1[0] = 0; // make sure strlen(buf_1) is 0.
    
       int n = recv(sockfd, &size, sizeof(long), 0);// recieve the size of the directory
    
       if(n < 0) puts("can't receive size from server");
       size = ntohl(size);
    
       while(size > 0){
           memset(&buffer[0], 0, sizeof(buffer)); // clear buffer
           n = recv(sockfd, buffer, 255, 0);  // keep last element of buffer as 0
           if(n < 0) puts("can't receive entry from server");
    
           int _start = 0;
           if (strlen(buf_1)) // something left over from previously read buffer
           {
              // buf_1 contains beginning of an entry, buffer - the end
              strcat(buf_1, buffer); // Assume there is a 0-terminator somewhere in buffer
              printf("receiving: %s\n", buf_1);  // buf_1 now has the entry, print it          buf_1[0] = 0;  // flag buf_1 as empty
              size--;  // we are one direntry down
              _start += strlen(buffer) + 1;  // move _start to char following 0-terminator
           }
           // Loop while _start is 0 - 254, the char at offset _start is not NULL,
           // and there are still entries to retrieve.
           while (_start < 255 && *(buffer + _start) && size > 0)
           {
              if (strlen( buffer + _start ) + _start >= 255) // no null terminator, need buf_1
              {
                 strcpy(buf_1, buffer + _start);  // copy unfinished entry to buf_1
                 // don't decrement size, we haven't extracted a full direntry.
                 break;  // out of the inner while to read more from the socket.
              }
              else // we have a full direntry
              {
                 printf("receiving: %s\n", buffer + _start); // print it
                 _start += strlen(buffer + _start) + 1;  // move offset to next possible entry
                 size--; // one entry down
              }
           }
        }
    

    希望这有帮助,祝你好运!如果您还有其他问题,请与我们联系 .

相关问题