Skip to content

Instantly share code, notes, and snippets.

@jgautsch
Created October 30, 2013 19:59
Show Gist options
  • Save jgautsch/7239206 to your computer and use it in GitHub Desktop.
Save jgautsch/7239206 to your computer and use it in GitHub Desktop.
Thermal sensor threaded server
/***** 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