#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#define CLIENT_FIFO "./client_%d"
struct Word
{
int Amount;
char* Text;
};
int wordComp(const void* e1, const void* e2)
{
int a1 = ((struct Word*)e1)->Amount;
int a2 = ((struct Word*)e2)->Amount;
if(a1 < a2) return 1;
if(a1 > a2) return -1;
return 0;
}
void SendData(int fd, char* filename)
{
// prepare the file processing with the all words list
int in = open(filename, O_RDONLY);
char word[4096];
char c = 0;
int i = 0;
int wordsSize = 0, wordsCount = 10;
struct Word* words = (struct Word*)malloc(wordsCount * sizeof(struct Word));
// read char by char the input file
int len = 0;
while((len = read(in, &c, sizeof(char))) >= 1)
{
// if it's not a valid char it's interpreted as end of word
if(c == '\n' || c == ',' || c == '.' || c == '\t' || c == '\r' || c == ' ')
{
// if the current word is empty skip the char
if(i <= 0)
continue;
word[i] = '\0';
// compare the current word with all the stored ones
int founded = 0;
for(int j = 0; j < wordsSize; ++j)
{
// if a word matches simply increase the counter
if(strcmp(words[j].Text, word) == 0)
{
founded = 1;
words[j].Amount++;
break;
}
}
// if the word is new it will be inserted in the list
if(founded == 0)
{
// if the words list capability is not enough, increase the size
if(wordsSize == wordsCount - 1)
{
struct Word* prevData = words;
words = (struct Word*)malloc(wordsCount * 2 * sizeof(struct Word));
memcpy(words, prevData, wordsCount * sizeof(struct Word));
wordsCount *= 2;
}
// build a new string to be stored
int len = strlen(word);
char* newStr = (char*)malloc(len + 1);
memcpy(newStr, word, len);
newStr[len] = '\0';
// store the new string with amount 1
words[wordsSize].Text = newStr;
words[wordsSize++].Amount = 1;
}
i = 0;
}
else
{
// if the character is valid it will be added to the current word
word[i++] = c;
}
}
// sort all the words by the amount
qsort(words, wordsSize, sizeof(struct Word), wordComp);
// send the words:
// 1. send the total amount size
// 2. for each word:
// -- write the amount
// -- write the text size
// -- write the text chars
write(fd, &wordsSize, sizeof(int));
for(i = 0; i < wordsSize; ++i)
{
struct Word* w = &words[i];
write(fd, &w->Amount, sizeof(int));
int len = strlen(w->Text);
write(fd, &len, sizeof(int));
write(fd, w->Text, len);
}
close(in);
}
void HandleClient(char* clientFifoName, char* filename)
{
printf("Client Handling!\n");
// open the channel with the client
int clientFifo = -1;
if((clientFifo = open(clientFifoName, O_WRONLY)) == -1)
{
printf("Client handle error!\n");
printf("Errno: %d\n", errno);
return;
}
// handle the input file
SendData(clientFifo, filename);
close(clientFifo);
}
void Server(char* publicFifo)
{
printf("Init Server!\n");
// make public fifo
if(mkfifo(publicFifo, 0666) == -1)
{
printf("Server error [MKFIFO]!\n");
printf("Errno: %d\n", errno);
return;
}
// open it in read only mode
int fifo = -1;
if((fifo = open(publicFifo, O_RDONLY)) == -1)
{
printf("Server error [OPEN FIFO]!\n");
printf("Errno: %d\n", errno);
return;
}
printf("Server is running and waiting for clients...\n");
char clientInfo[4096];
char clientFifo[4096];
char filename[4096];
// begin to listen
while (1)
{
// if someone writes something
if (read(fifo, clientInfo, 4096) > 0)
{
// split the information in client fifo name and input filename
int len = strlen(clientInfo);
memcpy(clientFifo, clientInfo, len + 1);
len = strlen(clientInfo + len + 1);
memcpy(filename, clientInfo + len + 1, len);
// begin to fork to handle the client
pid_t pid = fork();
if (pid == 0)
{
HandleClient(clientFifo, filename);
exit(0);
}
else if (pid < 0)
{
printf("Failed to fork process\n");
printf("Errno: %d\n", errno);
}
}
}
close(fifo);
unlink(publicFifo);
}
void Client(char* publicFifo, char* filename)
{
printf("Init Client!\n");
// build the client fifo name based on the client pid
char clientFifo[4096];
snprintf(clientFifo, 4096, CLIENT_FIFO, getpid());
// make the client fifo
if(mkfifo(clientFifo, 0666) == -1)
{
printf("Client error [MKFIFO]!\n");
printf("Errno: %d\n", errno);
return;
}
// open the public fifo
int fifo = -1;
if((fifo = open(publicFifo, O_WRONLY)) == -1)
{
printf("Client error [OPEN FIFO]!\n");
printf("Errno: %d\n", errno);
return;
}
// build the data for the server:
// 1. clientFifo name
// 2. input filename
int clientLen = strlen(clientFifo), fileLen = strlen(filename);
char* data = (char*)malloc(clientLen + 1 + fileLen + 1);
memcpy(data, clientFifo, clientLen);
data[clientLen] = '\0';
memcpy(data + clientLen + 1, filename, fileLen);
data[clientLen + fileLen + 1] = '\0';
// send the data
write(fifo, data, clientLen + 1 + fileLen + 1);
close(fifo);
printf("Client connected!\n");
// open the client fifo
int cFifo = -1;
if ((cFifo = open(clientFifo, O_RDONLY)) == -1)
{
printf("Client error [OPEN CLIENT FIFO]!\n");
printf("Errno: %d\n", errno);
return;
}
// begin to read the server's data
// raed the total amount size of words
int size = 0;
read(cFifo, &size, sizeof(int));
// foreach word read the amount and the string
for(int i = 0; i < size; ++i)
{
int amount = 0, len = 0;
read(cFifo, &amount, sizeof(int));
read(cFifo, &len, sizeof(int));
char* text = (char*)malloc(len + 1);
read(cFifo, text, len);
text[len] = '\0';
// print the result
printf("%d: %s\n", amount, text);
}
close(cFifo);
unlink(clientFifo);
}
int main(int argc, char* argv[])
{
int p = fork();
if(p == 0)
Server("/tmp/publicFifo2");
else
Client("/tmp/publicFifo2", "input.txt");
return 0;
}