A project for Systems Programming by Brad Hammond during the Fall of 2011.
To get a better understanding of socket programming on a Unix System.
In order to successfully accomplish/perform this project, the listed resources/experiences need to be consulted/achieved:
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.
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <time.h> #include <string.h> #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; }
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #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; }
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$
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.
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.
In performing this project, the following resources were referenced:
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.)