Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用C语言编写带循环的套接字程序发送和接收消息_C_Sockets_Network Programming - Fatal编程技术网

用C语言编写带循环的套接字程序发送和接收消息

用C语言编写带循环的套接字程序发送和接收消息,c,sockets,network-programming,C,Sockets,Network Programming,我刚刚开始学习socket编程,我正在尝试使用TCP在客户端和服务器之间发送和接收数据。首先,我从服务器向客户机发送当前目录的大小,而客户机接收到的结果非常好。然后我想从服务器直接发送当前文件中的每个文件名,因此我创建了一个循环来执行此操作。在客户机中,我还有一个循环,用于接收所有文件名,这些文件名执行的次数与文件的次数(目录大小)相同。问题是,当我打印出在循环中接收到的内容时,缓冲区是空白的。我意识到第一个循环接收的字节是55,其余的是0,但缓冲区总是空的。以下是我的代码片段: 服务器: if

我刚刚开始学习socket编程,我正在尝试使用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{//显示服务器目录中的文件
//获取目录的大小
无符号长大小=htonl(directorySize());
n=发送(newsockfd,&size,sizeof(size),0);
如果(n<0)syserr(“无法发送到服务器”);
DIR*d=opendir(“.”);
结构方向*dir;
如果(d)
{
而((dir=readdir(d))!=NULL)
{memset(&buffer[0],0,sizeof(buffer));//清除缓冲区
strcat(缓冲区,目录->数据单元名称);
n=发送(newsockfd,buffer,strlen(buffer),0);
如果(n<0)syserr(“无法发送到服务器”);
}
closedir(d);
}
否则{
syserr(“错误…无法从目录获取文件。”);
}
}
客户:

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--;
     }
 }       
if(strcmp(buffer,“ls remote”)==0{//显示服务器目录中的文件
无符号长尺寸;
n=recv(sockfd,&size,sizeof(uint32_t),0);//接收目录的大小
如果(n<0)syserr(“无法从服务器接收”);
尺寸=ntohl(尺寸);
而(大小>0){
memset(&buffer[0],0,sizeof(buffer));//清除缓冲区
n=recv(sockfd,buffer,255,0);//从服务器接收目录
如果(n<0)syserr(“无法发送到服务器”);
缓冲区[strlen(buffer)-1]='\0';
printf(“接收:%s\n”,缓冲区);//打印目录
大小--;
}
}       

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

还有几件事:

  • 缓冲区[strlen(buffer)-1]='\0';在客户端代码将被切掉 最后一个字符。应该是buffer[strlen(buffer)]='\0'; 相反
  • 类型使用与sizeof()运算符的一致性很重要。 例如,在我的Mac上,sizeof(long)是8,而sizeof(uint32_t)是4。 这导致了缺乏
    客户端和服务器之间的同步
这里的“同步”问题是由于这样一种可能性,即当客户端开始从套接字读取时,服务器已经写入了多个目录项,因此客户端将全部作为一个字符串读取。如果假定缓冲区大小不同,则将目录大小写入套接字并从套接字读取,事情会变得更加混乱;见上文

经过一些额外的实验后,我找到了一些似乎有效的代码。我确信可以进行一些改进,还有其他的方法,还有一些代码无法解释的场景,例如,如果程序运行时目录发生了变化,该怎么办。这只是一段概念验证代码,有望帮助您朝着正确的方向前进

这里的想法是让服务器将目录条目写入套接字,并用空字符分隔。然后在客户端将它们用作分隔符来区分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
          }
       }
    }
//假定最大条目长度为255
//缓冲区长度为256字节,以容纳空终止符。
//终止符作为direntry分隔符对客户端很重要。
字符缓冲区[256];
//获取目录的大小
无符号长大小=htonl(dirSize());
int n=send(client_sock,&size,sizeof(size),0);
如果(n<0)放入(“无法将大小发送到服务器”);
DIR*d=opendir(“.”);
结构方向*dir;
如果(d)
{
而((dir=readdir(d))!=NULL)
{
memset(&buffer[0],0,sizeof(buffer));//清除缓冲区
strcat(缓冲区,目录->数据单元名称);
//最多可写入255个字符的direntry+空终止符。
n=发送(客户端存储,缓冲区,strlen(缓冲区)+1,0);
如果(n<0)放入(“无法向服务器发送条目”);
}
closedir(d);
}
否则{
puts(“错误…无法从目录获取文件。”);
}
从套接字读取的客户端代码:

// 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
          }
       }
    }
char缓冲区[256];
/*
*如果目录项的开头在一个缓冲区中,但是
*结局在下一个。
*/
char buf_1[256];
无符号长尺寸;
buf_1[0]=0;//确保strlen(buf_1)为0。
int n=recv(sockfd,&size,sizeof(long),0);//接收目录的大小
如果(n<0)放入(“无法从服务器接收大小”);
尺寸=ntohl(尺寸);
而(大小>0){
memset(&buffer[0],0,sizeof(buffer));//清除缓冲区
n=recv(sockfd,buffer,255,0);//将buffer的最后一个元素保留为0
如果(n<0)puts(“无法从服务器接收条目”);
int _start=0;
if(strlen(buf_1))//以前读取的缓冲区中剩余的内容
{
//buf_1包含条目的开头,buffer-结尾
strcat(buf_1,buffer);//假设缓冲区中某处有一个0-终止符
printf(“接收:%s\n,buf_1);//buf_1现在有了条目,打印它buf_1[0]=0;//将buf_1标记为