Created
October 30, 2013 19:59
-
-
Save jgautsch/7239206 to your computer and use it in GitHub Desktop.
Thermal sensor threaded server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***** Jon Gautsch and Rob Wirthman | |
***** thermd.c | |
***** CSE 30264 - Project 2 | |
***** | |
***** USAGE: ./tcpserver | |
***** | |
***** See comments and README.txt for details | |
*****/ | |
#include <stdio.h> /* for printf() and fprintf() */ | |
#include <sys/socket.h> /* for socket(), bind(), and connect() */ | |
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */ | |
#include <stdlib.h> /* for atoi() and exit() */ | |
#include <string.h> /* for memset() */ | |
#include <unistd.h> /* for close() */ | |
#include <errno.h> /* for errno */ | |
#include <sys/stat.h> /* for stat() */ | |
#include <pthread.h> /* for pthread and mutexes */ | |
#include "./packet.h" | |
#define MAXPENDING 5 /* Maximum outstanding connection requests */ | |
#define PORTNO 9770 /* The port number the server will run on */ | |
pthread_mutex_t lock; /* The mutex lock that will be used to coordinate | |
threads accessing a resource */ | |
void *HandleTCPClient(int clntSocket); /* TCP client handling function */ | |
void DieWithError(char *errorMessage); /* Error handling function */ | |
void receive_packet(int clntSocket, Packet *packet); /* The function that | |
will receive all the data and | |
return a Packet struct. This | |
is so that structs aren't sent | |
through the sockets */ | |
int main(int argc, char *argv[]) | |
{ | |
int servSock; /* Socket descriptor for server */ | |
int clntSock; /* Socket descriptor for client */ | |
struct sockaddr_in echoServAddr; /* Local address */ | |
struct sockaddr_in echoClntAddr; /* Client address */ | |
unsigned short server_port; /* Server port */ | |
unsigned int clntLen; /* Length of client address data structure */ | |
if (argc != 1) /* Test for correct number of arguments */ | |
{ | |
fprintf(stderr, "Usage: %s \n", argv[0]); | |
exit(1); | |
} | |
server_port = PORTNO; /* First arg: local port */ | |
/* Create socket for incoming connections */ | |
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
DieWithError("socket() failed"); | |
/* Construct local address structure */ | |
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ | |
echoServAddr.sin_family = AF_INET; /* Internet address family */ | |
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ | |
echoServAddr.sin_port = htons(server_port); /* Local port */ | |
int val = 1; | |
if (setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) | |
DieWithError("setsockopt() failed"); | |
/* Bind to the local address */ | |
if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) | |
DieWithError("bind() failed"); | |
/* Mark the socket so it will listen for incoming connections */ | |
if (listen(servSock, MAXPENDING) < 0) | |
DieWithError("listen() failed"); | |
for (;;) /* Run forever */ | |
{ | |
/* Set the size of the in-out parameter */ | |
clntLen = sizeof(echoClntAddr); | |
/* Wait for a client to connect */ | |
if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, | |
&clntLen)) < 0) | |
DieWithError("accept() failed"); | |
/* clntSock is connected to a client! */ | |
printf("New client accepted!\n"); | |
printf("\tNew client address: %s\n", inet_ntoa(echoClntAddr.sin_addr)); | |
// printf("\tClient port: %s\n", inet_ntoa(echoClntAddr.sin_port)); | |
// HandleTCPClient(clntSock); | |
pthread_t thread; | |
pthread_create(&thread, NULL, &HandleTCPClient, clntSock); /* start thread */ | |
// pthread_detach(thread); /* don't track it */ | |
pthread_join(thread, NULL); | |
} | |
/* NOT REACHED */ | |
} | |
/************************************************** | |
* Handle TCP Client function: void HandleTCPClient() | |
* Runs in a spun off thread. Handles client | |
* by receiving packet(s) and writing info to | |
* log file. | |
**************************************************/ | |
void *HandleTCPClient(int clntSocket) | |
{ | |
Packet packet; /* The packet to be received for sensor 0 */ | |
Packet packet2; /* The packet to be received for sensor 1, | |
might or might not be received at all. */ | |
char date_text[100]; /* The string that contains the date info for logging */ | |
char log_file_name[100]; /* The file name of the log we will write to */ | |
char log_string[100]; /* The string that will be written to the log file */ | |
FILE *file; | |
/* Receive the first packet being sent by the client */ | |
receive_packet(clntSocket, &packet); | |
/* If the number of sensors being read from on this particular client | |
is 2, and not just 1 (as specified in the first packet received) | |
then receive the 2nd packet from the client */ | |
if (packet.numSensors == 2) | |
receive_packet(clntSocket, &packet2); | |
/* Initialize some time structures, to be used with strftime() */ | |
time_t now = time(NULL); | |
struct tm *t = localtime(&now); | |
/* Get the necessary time strings for logging, and log file name */ | |
strftime(date_text, sizeof(date_text)-1, "%Y %m %d %H %M", t); | |
strftime(log_file_name, sizeof(log_file_name)-1, "./g09_%Y_%m_", t); | |
/* Add the host name to the log file name, ex: "g09_2013_10_" + "student00" */ | |
strcat(log_file_name, packet.name); | |
/* If just 1 sensor is being read, write that to the log file. Else if it's | |
2 sensors being read, write the values from both packets to the log file */ | |
if (packet.numSensors == 1) | |
{ | |
sprintf(log_string, "%s %f\n", date_text, packet.value); | |
} | |
else if (packet.numSensors == 2) | |
{ | |
sprintf(log_string, "%s %f %f\n", date_text, packet.value, packet2.value); | |
} | |
/* * * * * * * * * * * * * * * * * | |
/* Mutex and file writing part | |
/* * * * * * * * * * * * * * * * * | |
/* Lock threads from this step with mutex */ | |
pthread_mutex_lock(&lock); | |
/* Open appropriate file in append mode */ | |
file = fopen(log_file_name, "a"); | |
/* Print log_string into log file */ | |
fprintf(file, "%s", log_string); | |
/* Close file because we're done with it */ | |
fclose(file); | |
/* We're done with resource, so we don't need to protect it anymore */ | |
/* Unlock the mutex */ | |
pthread_mutex_unlock(&lock); | |
pthread_exit(0); | |
return; | |
} | |
/************************************************** | |
* Receive Packet function: void receive_packet() | |
* Used to receive a Packet struct from the | |
* client. Receives data members one at a time | |
* instead of receiving the Packet struct. | |
**************************************************/ | |
void receive_packet(int clntSocket, Packet *packet) | |
{ | |
uint16_t temp16; | |
uint32_t temp32; | |
double tempDBL; | |
if (recv(clntSocket, &(packet -> name), 32, 0) < 0) | |
DieWithError("recv() host name failed"); | |
if (recv(clntSocket, &temp16, sizeof(uint16_t), 0) < 0) | |
DieWithError("recv() numSensors"); | |
packet -> numSensors = ntohs(temp16); | |
if (recv(clntSocket, &temp16, sizeof(uint16_t), 0) < 0) | |
DieWithError("recv() number"); | |
packet -> number = ntohs(temp16); | |
if (recv(clntSocket, &tempDBL, sizeof(tempDBL), 0) < 0) | |
DieWithError("recv() value"); | |
packet -> value = tempDBL; | |
if (recv(clntSocket, &tempDBL, sizeof(tempDBL), 0) < 0) | |
DieWithError("recv() min"); | |
packet -> min = tempDBL; | |
if (recv(clntSocket, &tempDBL, sizeof(tempDBL), 0) < 0) | |
DieWithError("recv() min"); | |
packet -> max = tempDBL; | |
if (recv(clntSocket, &(packet -> time), 32, 0) < 0) | |
DieWithError("recv() host name failed"); | |
if (recv(clntSocket, &temp16, sizeof(uint16_t), 0) < 0) | |
DieWithError("recv() number"); | |
packet -> action = ntohs(temp16); | |
// #ifdef DEBUG | |
printf("Host Name: %s\n",packet -> name); | |
printf("Number of Thermometers: %d\n",packet -> numSensors); | |
printf("Sensor Number: %d\n",packet -> number); | |
printf("Sensor Data: %3.2lf\n",packet -> value); | |
printf("Sensor Min Value: %3.2lf\n",packet -> min); | |
printf("Sensor Max Value: %3.2lf\n",packet -> max); | |
printf("Timestamp: %s",packet -> time); | |
printf("Action: %d\n",packet -> action); | |
// #endif | |
return; | |
} | |
/************************************************** | |
* Error Handling function: void DieWithError() | |
* Called whenever a recv() doesn't work | |
* properly. Will print the error and exit | |
**************************************************/ | |
void DieWithError(char *errorMessage) | |
{ | |
perror(errorMessage); | |
exit(1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment