User Tools

Site Tools


user:bh011695:portfolio:time_server

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

Client

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

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:

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.)

user/bh011695/portfolio/time_server.txt · Last modified: 2011/12/15 12:37 by bh011695