Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a linked list over a socket

I was trying to implement a very simple form of NFS using tcp sockets. All the functions were working properly except the "ls" command. My plan was to use a linked list structure to pass the list of constituent file and directory names in the current directory. I wrote the following code:

                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
                }

On the Client side I was reading like this:

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

Here, I am getting a segmentation fault. After giving it a thought I understood that the 'next' pointer is pointing to an address in the address space of the server program, so client can's access it. So I used an array of strings for passing the d_name list, and quite obviously, it worked perfectly.

So, my question is:

1. Is there any way of passing a linked list over a socket connection?

2. If not, then what is the best way to pass the list of constituent files and directories over a network? How is it implemented in real NFS?

like image 259
Ricky Avatar asked Feb 25 '26 03:02

Ricky


1 Answers

  1. Is there any way of passing a linked list over a socket connection?

Not directly, no. What you need to do instead is send some bytes over the socket connection, in some well-defined format that the receiving program can use to construct an identical linked list.

As others have pointed out in the comments, it's useless to send a pointer across a socket connection, because the pointer is valid only inside the sending process's memory space -- even if you did send the pointer's value across, it wouldn't be a valid pointer in the receiver's memory space.

Fortunately there is no need to send the pointers; instead just send the payload-data (in your case, the name arrays) and let the receiver create a new linked list containing that payload-data as it receives it.

For example (pseudocode, and note that there are many ways this could be done, this is just one way that seemed reasonably simple to me):

 // 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;
 }

... and then the receiver would run code something like the following (again, pseudocode; real code would do proper error checking, etc):

 // 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)
like image 107
Jeremy Friesner Avatar answered Feb 26 '26 17:02

Jeremy Friesner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!