Commit 3b45c310 authored by Nilesh Jagdish's avatar Nilesh Jagdish

Added previously done code

parents
all:
$(CC) -o server server.c -lpthread
$(CC) -o client client.c
server:
$(CC) -o server server.c -lpthread
client:
$(CC) -o client client.c
clean:
$(RM) client
$(RM) server
\ No newline at end of file
# Client code
## Compilation
make client
## Running
./client server ip server port number
# Server side
## Compilation
make server
## Running
./server
## config.txt
This file contains information for initialization of the server.
### Format:
server IP
server port number
number of threads to be created
# Compiling client and server together
make all
# Deleting the executables
make clean
\ No newline at end of file
#include <iostream>
#include <list>
#include <cstring>
#include <iterator>
#include <unordered_map>
#include "cache.h"
using namespace std;
/*
* The idea behind cache implementation :
* To implement LRU, Write-back, fully associative cache
* MAX Cache size - 32 key-value pairs
* Each cache node will consist of 1. key 2. value 3. dirty bit
* Algo :
* 1. Search in cache :
* Use unordered_map to see if a key is present in the cache and if it is present, this operation
* should return 1
* 2. Insert in cache :
* If cache is full, call LRU
* If cache has is not full, replace the frame with key-value pair to be inserted
* 3. LRU cache :
* Keep a pointer on a frame after the frame last replaced
* Move the pointer circularly, if a node has referenceBit = '0', then select this key-value for
* replacement
* Use bitmap to identify the file in which key is present
* (Use locality to evict more than one key-value pair?)
* And read the key-value pair in array element
*
* Data Structures : 1. List of cacheNode - 32 keys
* 2. Unordered map - <key, array index>
*
*/
#define MAX_CACHE_SIZE 32
list<cacheNode> cache;
unordered_map<char *, list <cacheNode> :: iterator> hashTable;
int search(char* key) {
unordered_map<char *, list <cacheNode> :: iterator> :: iterator it = hashTable.find(key);
if(it == hashTable.end()) {
return 0;
}
else {
list <cacheNode> :: iterator cnode_it = it->second;
cache.push_front(*cnode_it);
cache.erase(cnode_it);
return 1;
}
}
void lru(char* key, char *value) {
}
/*
* Assumption here is that before calling insert, key-value pair does not already exist in cache
*/
void insert(char* key, char* value) {
cacheNode cnode;
if(cache.size() == MAX_CACHE_SIZE) {
lru(key, value);
}
else {
cnode.key = (char *)malloc(strlen(key) + 1);
strcpy(cnode.key, key);
cnode.value = (char *)malloc(strlen(value) + 1);
strcpy(cnode.value, value);
cnode.dirtyBit = '0';
cache.push_front(cnode);
hashTable[key] = cache.begin();
}
}
/*
* Testing code
*/
int main() {
char key1[] = "A";
char key2[] = "B";
char key3[] = "C";
char key4[] = "D";
char value[] = "1";
insert(key1, value);
insert(key2, value);
insert(key3, value);
printf("%d\n", search(key1));
printf("%d\n", search(key2));
printf("%d\n", search(key3));
printf("%d\n", search(key4));
}
/*
*
* Cache node structure :
* dirtyBit = '1' if value is modified, '0' if not modified
* referenceBit - To implement approximate LRU
* An iterator will iterate through the list to find first page which has referenceBit = '0'
* It replaces that key-value along with 3 following key-value pairs with the new key and its following
* 3 key-value pairs in persistent storage
* If referenceBit = '1', set it to '0' and move forward(in circular fashion)
* To implement perfect LRU(which might be costly in terms of performance) - need a global counter for time
*/
typedef struct cacheNode {
char* key;
char* value;
char dirtyBit;
} cacheNode;
#include <stdio.h>
#include "client.h"
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int connectToServer(char *addr, char *portNo) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// getaddrinfo return getaddr objects by searching using the provided hints, name, service
int s = getaddrinfo(addr, portNo, &hints, &result);
if(s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return -1;
}
connect(sockfd, result->ai_addr, result->ai_addrlen);
sendToServer(sockfd);
return 0;
}
void sendToServer(int sockfd) {
printf("Enter the index no to choose an option...\n");
printf("------OPTIONS------\n1. GET\n2. PUT\n3. DELETE\n4. EXIT\n");
int choice;
char *buffer = (char *)malloc(513*sizeof(char));
char key[100], value[100];
while(1) {
printf("Enter choice: :");
scanf("%d", &choice);
switch(choice) {
case 1:
printf("Key: ");
scanf("%s", key);
GET(key, buffer);
break;
case 2:
printf("Key: ");
scanf("%s", key);
printf("Value: ");
scanf("%s", value);
PUT(key, value, buffer);
break;
case 3:
printf("Key: ");
scanf("%s", key);
DELETE(key, buffer);
break;
case 4:
break;
}
write(sockfd, buffer, strlen(buffer));
char recvBuffer[1000];
int len = read(sockfd, recvBuffer, 999);
recvBuffer[len] = '\0';
printf("%s\n", recvBuffer);
}
// char buffer[100];
// while(fgets(buffer, 100, stdin) != NULL) {
// write(sockfd, buffer, strlen(buffer));
// char recvBuffer[1000];
// int len = read(sockfd, recvBuffer, 999);
// recvBuffer[len] = '\0';
// printf("%s\n", recvBuffer);
// }
}
int GET(char* key, char *request) {
printf("GET called!\n");
// char request[513];
memset(request, '0', 513);
request[0] = '1';
// memcpy(request+1, key, strlen(key));
memcpy(request+257-strlen(key), key, strlen(key));
// printf("%s\n", request);
}
int PUT(char* key, char* value, char *request) {
printf("PUT called!\n");
// char request[513];
memset(request, '0', 513);
request[0] = '2';
// memcpy(request+1, key, strlen(key));
memcpy(request+257-strlen(key), key, strlen(key));
memcpy(request+513-strlen(value), value, strlen(value));
printf("key at index: %ld\n", 257-strlen(key));
printf("value at index: %ld\n", 513-strlen(value));
}
int DELETE(char* key, char *request) {
// char request[513];
printf("DELETE called!\n");
memset(request, '0', 513);
request[0] = '3';
// memcpy(request+1, key, strlen(key));
memcpy(request+257-strlen(key), key, strlen(key));
// printf("%s\n", request);
}
int main(int argc, char **argv) {
printf("IP = %s, Port = %s\n", argv[1], argv[2]);
// PUT("100", "200");
connectToServer(argv[1], argv[2]);
return 0;
}
// 1. connection to server
// 2. KV communication functions
int connectToServer(char *addr, char *portNo);
void sendToServer(int sockfd);
int GET(char* key, char *request);
int PUT(char* key, char* value, char *request);
int DELETE(char* key, char *request);
void terminateConnection();
127.1.1.2
20000
10
\ No newline at end of file
#include <stdio.h>
#include "server.h"
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
void initVals(char *ip, char *portNo, int *nThreads) {
FILE *ptr = fopen("config.txt", "r");
fscanf(ptr, "%s\n%s\n%d\n", ip, portNo, nThreads);
fclose(ptr);
}
void *respondToClient(void *args) {
int clientFd = *((int *)args);
while(1) {
// printf("reading for client %d\n", clientFd);
char buffer[513];
int len = read(clientFd, buffer, 513);
// buffer[len] = '\0';
char key[100], value[100];
char todo = buffer[0];
// key: first non-zero till byte 257
int i;
for(i=1; buffer[i]=='0'; i++);
// printf("I: %d %c\n", i, buffer[i]);
printf("key length: %d\n", 257-i);
memcpy(key, buffer+i, 257-i);
// value: first non-zero till byte 513
for(i=257; buffer[i]=='0'; i++);
printf("value length: %d\n", 513-i);
memcpy(value, buffer+i, 513-i);
switch(todo) {
case '1':
printf("GET recvd\n");
printf("Key: %s\n", key);
break;
case '2':
printf("PUT recvd\n");
printf("Key: %s\n", key);
printf("Value: %s\n", value);
break;
case '3':
printf("DELETE recvd\n");
printf("Key: %s\n", key);
break;
}
// printf("%s\n", buffer);
write(clientFd, "Client response\0", 16);
}
}
int acceptConnections(char *addr, char *portNo, int nThreads) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
pthread_t clientThreads[nThreads];
int clientNo = 0;
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int s = getaddrinfo(addr, portNo, &hints, &result);
if(s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return -1;
}
int b = bind(sockfd, result->ai_addr, result->ai_addrlen);
if(b != 0) {
printf("Binding error\n");
return -1;
}
int l = listen(sockfd, nThreads);
if(l != 0) {
printf("Error while listening...\n");
return -1;
}
printf("Waiting for connection...\n");
while(1) {
int clientFd = accept(sockfd, NULL, NULL);
printf("Connected to client with fd: %d\n", clientFd);
clientNo++; // shared variables hence we need conditional variable
int fid = fork();
if(fid==0) {
// create thread
int *cfd = &clientFd;
pthread_create(&clientThreads[clientNo], NULL, respondToClient, (void *)cfd);
} else {
// manage threads
}
}
return 0;
}
int main(int argc, char **argv) {
printf("Server is running...\n");
char ip[20], portNo[10];
int nThreads;
initVals(ip, portNo, &nThreads);
printf("Ip address: %s\n", ip);
printf("portno: %s\n", portNo);
printf("no of threads: %d\n", nThreads);
acceptConnections(ip, portNo, nThreads);
return 0;
}
// 1. connection to client
// 2. KV communication functions
// 3. memory management
// each will run on an independant thread
void initVals(char *ip, char *portNo, int *nThreads);
int acceptConnections(char *addr, char *portNo, int nThreads);
void recvGet();
void recvPut();
void recvDelete();
void terminateConnections();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment