======Project: Time Server====== A project for Systems Programming by Brad Hammond during the Fall of 2011. =====Objectives===== To get a better understanding of socket programming on a Unix System. =====Prerequisites===== In order to successfully accomplish/perform this project, the listed resources/experiences need to be consulted/achieved: * understand structs * understand pointers * understand sockets =====Background===== The idea here is get a little better understanding of socket programming on a lower level. In Java it's fairly simple and to the point. In C, there's a lot more low level manipulation to be done. One of the things I think the book should spend a little more time on is explaining what the structs here are and what the members are used for. In Joe's HPC Systems and Networking class I had come across a C Unix sockets tutorial that I found my way back to. I think it does a decent job at breaking down what's going on in the code. =====Attributes===== * pointers: pointers are at the heart of dynamic structures. * network programming: program will use sockets * malloc/free: program mallocs memory for strings * command line arguments: accepts hostname and port number as arguments =====Code===== ==== Server ==== #include #include #include #include #include #include #include #include #define PORT 13000 #define HOST_LEN 256 #define error(errMsg) {perror(errMsg); exit(1);} int main(int argc, char** argv) { struct sockaddr_in address; //Stores internet address info struct hostent *hostEntries; //Stores info about the host name, name length char name[HOST_LEN]; //Name of the server int sockID, sockFD, visitorCount = 0; //ID & file descriptor for the socket, current visitor number FILE *sockFP; //Used to write to the socket time_t currTime; //Current time //Get a socket if ((sockID = socket(PF_INET, SOCK_STREAM, 0)) == -1) error("Cannot get socket"); //Zero the address structure bzero((void*) &address, sizeof(address)); //Get host name and fill hostEntries struct gethostname(name, HOST_LEN); hostEntries = gethostbyname(name); //Copy the h_addr member to the sin_addr member bcopy((void*) hostEntries -> h_addr, (void*) &address.sin_addr, hostEntries -> h_length); //Convert port in host byte order to network byte order address.sin_port = htons(PORT); //Set .sin_family to AF_INET, internet address address.sin_family = AF_INET; //Bind to the socket if (bind(sockID, (struct sockaddr*) &address, sizeof(address)) != 0) error("Cannot bind to socket"); //Listen for incomming connections if (listen(sockID, 1) != 0) error("Cannot listen on socket"); //accepts an incomming connection. Set the FP to the socket //so we can write to it. Once the connection is established //we can send messages to the user. What visitor number they //are, the time, etc. Then we close the fp. while (1) { if ((sockFD = accept(sockID, NULL, NULL)) == -1) error("Cannot accept on socket"); if ((sockFP = fdopen(sockFD, "w")) == NULL) error("Cannot open file pointer"); currTime = time(NULL); fprintf(sockFP, "Welcome to %s! ", name); fprintf(sockFP, "The current time is %s", ctime(&currTime)); fprintf(sockFP, "You are visitor #%d\n", ++visitorCount); fclose(sockFP); } return 0; } ==== Client ==== #include #include #include #include #include #include #include #define error(errMsg) {perror(errMsg); exit(1);} #define STDOUT 1 int main(int argc, char **argv) { struct sockaddr_in servAddress; //Address of the server to connect //to struct hostent *hostEntries; //Stores the name of the server and the //server name's length int sockID, sockFD; //socket ID and file descriptor char *message; //Message to get from server int messageLen; //length of the message; //Check arguments. Needs a hostname and port number if (argc != 3) error("no arguments"); //Malloc space for the message and zero the socket address struct message = (char*) malloc(sizeof(char) * BUFSIZ); bzero(&servAddress, sizeof(servAddress)); //Open the socket if ((sockID = socket(AF_INET, SOCK_STREAM, 0)) == -1) error("Cannot open socket."); //Get the hostname and store it in the hostEntries struct if ((hostEntries = gethostbyname(argv[1])) == NULL) error(argv[1]); //Copy h_addr member to sin_addr member, store the port, and store the socket type //IPV4 socket. bcopy(hostEntries->h_addr, (struct sockaddr*)&servAddress.sin_addr, hostEntries->h_length); servAddress.sin_port = htons(atoi(argv[2])); servAddress.sin_family = AF_INET; //Connect to the socket if (connect(sockID, (struct sockaddr*)&servAddress, sizeof(servAddress)) != 0) error("Cannot conect to socket."); //Read the message in from the socket if ((messageLen = read(sockID, message, BUFSIZ)) == -1) error("Cannot read from socket"); //Write to stdout if (write(STDOUT, message, messageLen) != messageLen) error("Cannot write to stdout"); //Close the file descriptor and free memory from message close(sockID); free(message); return 0; } =====Execution===== Again, if there is associated code with the project, and you haven't already indicated how to run it, provide a sample run of your code: brad@Lucid-Lynx:/media/06F6-9DC2/Notepad++/Programs$ ./clientThing `hostname` 13000 Welcome to Lucid-Lynx! The current time is Thu Dec 15 12:16:41 2011 You are visitor #1 brad@Lucid-Lynx:/media/06F6-9DC2/Notepad++/Programs$ ./clientThing `hostname` 13000 Welcome to Lucid-Lynx! The current time is Thu Dec 15 12:16:43 2011 You are visitor #2 brad@Lucid-Lynx:/media/06F6-9DC2/Notepad++/Programs$ ./clientThing `hostname` 13000 Welcome to Lucid-Lynx! The current time is Thu Dec 15 12:16:44 2011 You are visitor #3 brad@Lucid-Lynx:/media/06F6-9DC2/Notepad++/Programs$ =====Reflection===== I feel a little bit better about the structs used in socket programming. It was a bit overwhelming at first having to know all of the members you use and how to use them. I'm still a bit fuzzy on some of it but I definitely have a better understanding than I did before doing this. *struct sockaddr_in contains information about an address *sin_family will always be set to AF_INET IpV4 *sin_port is the port number to connect to *struct hostent stores information about a host computer *h_name is the name of the host *h_length is the length of the address of the host I think I'm pretty good on this stuff now. It's just a case of trying to remember what parameters each function will take. Some of the syntax is a bit crazy with the struct pointers being casted and such. =====References===== In performing this project, the following resources were referenced: * http://en.wikipedia.org/wiki/AF_INET * http://www.linuxhowtos.org/C_C++/socket.htm * Understanding Unix/Linux Programming Generally, state where you got informative and useful information to help you accomplish this project when you originally worked on it (from Google, other wiki documents on the Lab46 wiki, etc.)