Передача связанного списка через сокет - PullRequest
2 голосов
/ 19 марта 2019

Я пытался реализовать очень простую форму NFS с использованием сокетов tcp.Все функции работали правильно, кроме команды "ls".Мой план состоял в том, чтобы использовать структуру связанного списка для передачи списка составляющих файлов и имен каталогов в текущем каталоге.Я написал следующий код:

                struct lnode
                {
                   char name[256];
                   struct lnode* next;
                };
                DIR* drptr = opendir("."); //as of now, only current directory is considered
                if(drptr==NULL)
                {
                    perror("Could not open");
                }
                else
                {
                    struct dirent* drnt;
                    struct lnode* head = NULL,*tail = NULL;
                    drnt = readdir(drptr);
                    while(drnt!=NULL)
                    {

                        if(strcmp(drnt->d_name,".")!=0&&strcmp(drnt->d_name,"..")!=0)
                        {
                             if(head==NULL)
                             {
                                head = (struct lnode*)malloc(sizeof(struct lnode));
                                strcpy(head->name,drnt->d_name);
                                head->next = NULL;
                                teail = head;
                             }
                             else
                             {
                                tail->next = (struct lnode*)malloc(sizeof(struct lnode));
                                strcpy(tail->next->name,drnt->d_name);
                                tail->next->next = NULL;
                                tail = tail->next;
                             }
                        }
                        else
                        {
                            break;
                        }
                        drnt = readdir(drptr);
                    }
                    write(1,head,sizeof(lnode)); // the socket is duped to 1, so 1 is used for socket communication
                }

На стороне клиента я читал так:

struct lnode* l,*q;
recv(sfd,l,sizeof(struct lnode),0);
q = l;
while(q!=NULL)
{
   printf("%s\n",q->name);
   q = q->next;
}

Здесь я получаю ошибку сегментации.После размышления я понял, что указатель «следующий» указывает на адрес в адресном пространстве серверной программы, поэтому клиент может получить к нему доступ.Поэтому я использовал массив строк для передачи списка d_name, и вполне очевидно, что он работал отлично.

Итак, мой вопрос:

1.Есть ли способ передачи связанного списка через сокетное соединение?

2.Если нет, то как лучше всего передать список составляющих файлов и каталогов по сети?Как это реализовано в реальном NFS?

1 Ответ

2 голосов
/ 19 марта 2019
  1. Есть ли способ передачи связанного списка через сокетное соединение?

Не напрямую, нет. Вместо этого вам нужно отправить несколько байтов через соединение с сокетом в определенном формате, который получающая программа может использовать для создания идентичного связанного списка.

Как отмечали другие в комментариях, бесполезно отправлять указатель через соединение с сокетом, потому что указатель действителен только внутри пространства памяти отправляющего процесса - даже если вы отправили значение указателя через него, это не быть действительным указателем в области памяти получателя.

К счастью, нет необходимости отправлять указатели; вместо этого просто отправьте данные полезной нагрузки (в вашем случае, массивы name) и позвольте получателю создать новый связанный список, содержащий эти данные полезной нагрузки, когда он их получит.

Например (псевдокод, и обратите внимание, что есть много способов сделать это, это только один способ, который мне показался достаточно простым):

 // compute the length of the linked list we want to send
 int numNodesInLinkedList = 0;
 struct lnode * n = headNode;
 while(n)
 {
    numNodesInLinkedList++;
    n = n->next;
 }

 // sender:  First, send a string telling the receiver how many nodes to expect
 char headerBuffer[256];
 sprintf(headerBuffer, "%i", numNodesInLinkedList);
 send(sfd, headerBuffer, sizeof(headerBuffer), 0);

 // Then send that many node's worth of name-data
 struct lnode * n = headNode;
 while(n)
 {
    send(sfd, n->name, sizeof(n->name), 0);
    n = n->next;
 }

... и тогда получатель будет запускать код, подобный следующему (опять же, псевдокод; реальный код будет выполнять правильную проверку ошибок и т. Д.):

 // receiver:  First, receive the string containing the number-of-nodes-to-receive
 char headerBuffer[256];
 recv(sfd, headerBuffer, sizeof(headerBuffer), MSG_WAITALL);

 const int numNodesInLinkedList = atoi(headerBuffer);
 struct lnode * headNode = NULL;
 struct lnode * tailNode = NULL;

 // Then receive that many names, and place them into our new linked-list
 for (int i=0; i<numNodesInLinkedList; i++)
 {
    struct lnode * newNode = malloc(sizeof(struct lnode));
    newNode->next = NULL;

    recv(sfd, newNode->name, sizeof(newNode->name), MSG_WAITALL);
    if (tailNode)
    {
       tailNode->next = newNode;
       tailNode = newNode;
    }
    else tailNode = headNode = newNode;
 }

 // at this point, headNode points to the start of the received linked-list
 // and tailNode points to the last received node in the list
 // (or both headNode and tailNode are NULL if the list was empty)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...