10 Server::Server(
const std::string& address,
size_t port) : _address(address), _port(port) {}
15 _socket = socket(AF_INET, SOCK_STREAM, 0);
17 throw std::runtime_error(
"Cannot create socket");
20 if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(opt)) < 0)
22 perror(
"setsockopt SO_REUSEADDR failed");
26 sockaddr.sin_family = AF_INET;
27 if (!_address.empty())
29 if (inet_pton(AF_INET, _address.c_str(), &sockaddr.sin_addr) <= 0)
32 throw std::runtime_error(
"Invalid address: " + _address);
37 sockaddr.sin_addr.s_addr = INADDR_ANY;
40 sockaddr.sin_port = htons(port != 0 ? port : _port);
42 if (bind(_socket, (
struct sockaddr*)&sockaddr,
sizeof(sockaddr)) < 0)
45 throw std::runtime_error(
"Failed to bind on socket. errno: " + std::to_string(errno));
50 FD_SET(_socket, &_active);
55 throw std::runtime_error(
"Failed to listen on socket. errno: " + std::to_string(errno));
59 void Server::_acceptNewConnection()
61 int connfd = accept(_socket, 0, 0);
67 std::cout <<
"Max connections reached, closing new connection" << std::endl;
75 FD_SET(connfd, &_active);
76 FD_SET(connfd, &_readyRead);
78 _clients[connfd] = _next_id;
79 _clientsToFd[_next_id] = connfd;
83 bool Server::_receiveClientMsg(
const int& fd)
86 if (!FD_ISSET(fd, &_readyRead))
92 while ((bytes = recv(fd, buffRead,
sizeof(buffRead), MSG_DONTWAIT)) > 0)
94 _partialMsgs[fd].appendBytes(
reinterpret_cast<unsigned char*
>(buffRead), bytes);
95 while (_partialMsgs[fd].isComplet())
99 _partialMsgs[fd] >> msgType;
104 _partialMsgs[fd] >> dataSize;
106 newMsg.appendBytes(_partialMsgs[fd].getBuffer()->data().data(), dataSize);
108 _partialMsgs[fd].incr_cursor(dataSize);
110 newMsg.setMessageFd(fd);
112 _msgs.push_back(newMsg);
114 _partialMsgs[fd].getBuffer()->clear();
117 if (bytes == 0 || (bytes == -1 && errno != EAGAIN && errno != EWOULDBLOCK))
127 auto fdIt = _clientsToFd.find(clientID);
128 if (fdIt == _clientsToFd.end())
131 if (!FD_ISSET(fdIt->second, &_active))
138 ssize_t bytes_sent = send(fdIt->second, data.data(), data.size(), 0);
139 if (bytes_sent == -1)
141 _clearClient(fdIt->second);
142 std::cout <<
"Failed to send message to client " << clientID << std::endl;
148 for (
auto&
id : clientIDs)
157 for (
auto& [fd, clientId] : _clients)
159 sendTo(message, clientId);
165 const std::function<
void(
long long& clientID,
const Message& msg)>& action)
167 _tasks[messageType] = action;
175 _readyRead = _active;
176 timeval timeout = {0, 10000};
177 int select_result = select(_max_fd + 1, &_readyRead, NULL, NULL, &timeout);
179 if (select_result <= 0)
181 if (errno == EBADF || errno == EINTR)
183 std::cout <<
"Select interrupted, stopping server..." << std::endl;
190 for (
int fd = 0; fd <= _max_fd; fd++)
192 if (!FD_ISSET(fd, &_readyRead))
197 _acceptNewConnection();
200 if (!_receiveClientMsg(fd))
202 auto clientIt = _clients.find(fd);
203 if (clientIt != _clients.end())
207 _partialMsgs.erase(fd);
212 for (
size_t i = 0; i < _msgs.size(); i++)
214 auto it = _tasks.find(_msgs[i].type());
216 if (it == _tasks.end())
219 auto it2 = _clients.find(_msgs[i].getFd());
220 if (it2 == _clients.end())
223 long long clientId = it2->second;
225 it->second(clientId, _msgs[i]);
230 void Server::_clearAll()
233 _clientsToFd.clear();
234 _partialMsgs.clear();
239 void Server::_clearClient(
int& fd)
241 auto clientIt = _clients.find(fd);
242 if (clientIt == _clients.end())
247 long long clientId = clientIt->second;
251 FD_CLR(fd, &_active);
255 _clientsToFd.erase(clientId);
256 _partialMsgs.erase(fd);
264 std::cout <<
"Closing server socket." << std::endl;
269 for (
auto& [fd, clientId] : _clients)
277 FD_CLR(fd, &_active);
Class representing a structured message for network communication.
std::vector< unsigned char > getSerializedData() const
void sendTo(const Message &message, long long clientID)
void sendToArray(const Message &message, std::vector< long long > clientIDs)
void defineAction(const Message::Type &messageType, const std::function< void(long long &clientID, const Message &msg)> &action)
void sendToAll(const Message &message)
void start(const size_t &port=0)