套接字编程使用C

时间:2015-09-15 00:48:53

标签: c sockets network-programming

我刚开始学习套接字编程,我尝试使用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 个答案:

答案 0 :(得分:2)

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

其他一些事情:

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

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

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

这里的想法是服务器将目录条目写入由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
          }
       }
    }

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