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?
- 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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With