-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathServerSocket.cpp
More file actions
165 lines (143 loc) · 5.74 KB
/
ServerSocket.cpp
File metadata and controls
165 lines (143 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "ServerSocket.hpp"
ServerSocket::ServerSocket() : serverSocket(INVALID_SOCKET) {}
// destructor w/ cleanup
ServerSocket::~ServerSocket() {
if (serverSocket != INVALID_SOCKET) {
closesocket(serverSocket);
}
WSACleanup();
}
// initialize winsock, return true if successful
bool ServerSocket::initWinsock() {
WSADATA wsaData;
return WSAStartup(MAKEWORD(2, 2), &wsaData) == 0;
}
// start server on port
bool ServerSocket::start(int port) {
if (!initWinsock()) {
cerr << "WSAStartup failed." << endl;
return false;
}
// socket creation
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
cerr << "Socket creation failed." << endl;
return false;
}
// socket binding
sockaddr_in serverAddr = {};
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port);
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
cerr << "Bind failed." << endl;
closesocket(serverSocket);
return false;
}
// socket listening
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
cerr << "Listen failed." << endl;
closesocket(serverSocket);
return false;
}
return true;
}
// accept and handle client communication
void ServerSocket::run(RedisServer& server) {
bool serverRunning = true;
while (serverRunning) {
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket == INVALID_SOCKET) {
cerr << "Accept failed." << endl;
continue;
}
thread clientThread(&ServerSocket::handleClient, this, clientSocket, std::ref(server));
clientThread.detach(); // detach the thread so it runs independently
}
}
//handle client communication
bool ServerSocket::handleClient(SOCKET clientSocket, RedisServer& server) {
char buffer[1024];
string userInput = "";
while (true) {
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived > 0) {
buffer[bytesReceived] = '\0'; // null-terminate
userInput.append(buffer); // add the received data to userInput string
// check if newline is present e.g. command complete
size_t pos = userInput.find('\n');
if (pos != string::npos) {
userInput.erase(userInput.find_last_not_of("\r\n") + 1); // remove trailing whitespace
cout << "Received command: " << userInput << endl;
// Process the command
if (userInput.substr(0, 3) == "SET") {
size_t spacePos = userInput.find(' ', 4);
if (spacePos == string::npos || spacePos + 1 >= userInput.size()) {
send(clientSocket, "ERROR: Missing key or value\r\n", 28, 0);
}
else {
string key = userInput.substr(4, spacePos - 4);
string value = userInput.substr(spacePos + 1);
server.set(key, value);
server.saveToFile(key, value);
send(clientSocket, "OK", 2, 0);
}
}
else if (userInput.substr(0, 3) == "GET") {
if (userInput.size() <= 4 || userInput.substr(4).find_first_not_of(' ') == string::npos) {
send(clientSocket, "ERROR: Missing key\r\n", 20, 0);
}
else {
string key = userInput.substr(4);
string value = server.get(key);
if (value.empty()) {
send(clientSocket, "ERROR: No key found\r\n", 19, 0);
}
else {
string response = value + "\n";
send(clientSocket, response.c_str(), response.size(), 0);
}
}
}
else if (userInput.substr(0, 3) == "DEL") {
if (userInput.size() <= 4 || userInput.substr(4).find_first_not_of(' ') == string::npos) {
send(clientSocket, "ERROR: Missing key\r\n", 20, 0);
}
else {
string key = userInput.substr(4);
bool successful = server.del(key);
if (successful) {
send(clientSocket, "OK\n", 2, 0);
}
else {
send(clientSocket, "ERROR: No key found\r\n", 19, 0);
}
}
}
else if (userInput == "QUIT") {
send(clientSocket, "Closing connection. Goodbye!\r\n", 29, 0);
cout << "Client requested to quit. Closing connection." << endl;
break;
}
else {
send(clientSocket, "ERROR: Unknown command\r\n", 22, 0);
}
userInput.clear(); // clear the userInput buffer for the next command
}
}
else if (bytesReceived == 0) {
// connection closed gracefully by the client
cout << "Client disconnected.\r\n" << endl;
break;
}
else {
// error receiving data
cerr << "Error receiving data from client.\r\n" << endl;
break;
}
}
closesocket(clientSocket);
return false;
}