CSS 432
FAQ on Final Project: Network Application
Q1: How many lines should the ftp client expect to read as a server
reply?
I have a question about the replies the server sends back. For
replies, what can the client assume as far as the message size or line
count? I am running into a problem where if I don't know how many
lines to read for each reply, I am not getting all of the data. If I
just keep looping, I will read all of the data, but as soon as no data
is left, I go into a read call that blocks and waits for incoming
data. So basically my question is, what can we assume about the server
replies, and if we can assume nothing, how can we make sure we read
the entire reply without going into a read call that blocks?
I read the RFC about server replies and how the first line and the
last line should contain a common sequence to tell the client that
more data exists on additional lines and that no more data is left
after the last line. Should we use this implantation for our client?
A: Use poll( &ufds, 1, 1000 ) to check if you have more
data to read
While RFC mentions the first and the last line format returned from
the server, all you need is just use the poll system call.
#include <sys/poll.h>
struct pollfd ufds;
ufds.fd = sd; // a socket descriptor to exmaine for read
ufds.events = POLLIN; // check if this sd is ready to read
ufds.revents = 0; // simply zero-initialized
int val = poll( &ufds, 1, 1000 ); // poll this socket for 1000msec (=1sec)
if ( val > 0 ) { // the socket is ready to read
char buf[BUFLEN];
int nread = read( sd, buf, BUFLEN ); // guaranteed to return from read
// even if nread < BUFLEN
Q2: How do we read from cin without knowing the # of reads in advance?
Since we have to have the program handle input in a variety of ways,
how do we read from the console (cin) without know the # of reads in
advance?
A: Use cin.getline( )
Here is a code example. After receiving a cin intput in command[], you
have to lexically analyze its contents.
#define 10000 // allocate a big character array
char command[CMD_MAX]; // receive a cin input
cin.getline( command, CMD_MAX );
Q3: Which messages need to have the crlf delimiter and how do we
add it to them?
A: All commands must have the crlf "\r\n" delimiter at their
tail. Also, all server responses must have this delimiter, too.
Q4: Do we need to fork the client application in case when
receiving data over the passive ftp connection?
For our project you talked about forking the client application in
class when receiving data over the passive ftp connection.
For example in order:
Send PASV
Passively Connect()
Fork() a child
Send LIST
What I cannot figure out is why the client needs to fork for getting
the data? Currently my client is complete and, get, put and ls work
just like the actual FTP program without using a fork. Is there some
specific reason we need to fork that I am not realizing?
A: It is always safe to let a child process or a thread read data
from the server.
If your client sends a "LIST" command and thereafter tries to read
data from the server, the server might have already sent data and
closed the passive connection before your client actually reads the
data, in which case you will receive a "broken pipe" error. To prevent
this error, you would like to spawn a child process or a thread and
make them read to read data, (i.e., call read( )) before you actually
send a "LIST" command. Although the spawned process or a thread may be
blocked for a read first, once the server receives "LIST" and returns
data, it can immediately read data. That's the reason why you may need
to spawn another instance to read data. In summary, my recommended
sequence will be:
send a PASV command to the server
receive a server response
establish a "data" connection
fork a child process/thread and let it be blocked on read( )
send a RETR command to the server
the child reads all data from the server and terminates itself.
Q5: For the client do we have to get the system username who is logged and
display it in the prompt like the real FTP client?
A: Yes. Use getlogin.
A code example is:
#include <unistd.h>
#include <stdio.h>
char *serverIp; // let it point to one of argv[] that includes serverIp.
string userString( getlogin( ) );
cout << "Name (" << serverIp << ":" << userString << "): ";
Q6: What file modes does the client have to specify when writing to
its local disk a file received from the server?
A: Use S_IRUSR, S_IWUSR, S_IRGRP, and S_IROTH.
For the get command, the client should set these file modes before
writing a fie received from the server:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int file = open( filename, O_WRONLY | OCREAT, mode );
Q7: I received a multiple defintion error when compiling my program.
When i tried to put the socket into one class and compile the ftp and
ftpd programs, i am getting a multiple definition error for all of the
functions. any idea why?
A: Use #ifndef, #define, and #endif
If you code many classes that may refer to each other, the compiler
may read the same header file repeatedly, which causes this multiple
definition error. Use #ifndef, #defin, and #endif in your header
file. Assuming your header file name is Socket.h, your file should be:
#ifndef _SOCKET_H_
#define _SOCKET_H_
your class definition
#endif
This way prevents the compiler from scanning the same class definition.
Q8: Although I converted all C++ string into C chars, write( ) still does not work.
Here is my code:
char sendCmd[100];
cin >> cmd;
strcpy (sendCmd, "PASS ");
strcat (sendCmd, cmd);
strcat (sendCmd, "\r\n");
int nwrite = write(clientSd, sendCmd, sizeof(sendCmd) );
What's wrong?
A: Make sure the exact number of bytes you will send
In the above example, you'll always send 100 bytes. Assuming that cmd
includes "abc", sendCmd includes "PASS abc\r\n" which is 10-byte
long. Note that sendof( sendCmd ) always return 100 in the above case.
Q9: I have so much trouble with getline( )
A: Use cin >>.