Добавил:
farel
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:
#include "server.h"
#pragma warning (disable: 4996)
server::server(unsigned short __port) {
port = __port;
}
server::~server() {
delete firstClient;
if (lastClient) delete lastClient;
for (auto &thr : threadClient) thr.join();
}
int server::start() {
WSADATA ws;
WORD wVersion = MAKEWORD(2, 2);
if (WSAStartup(wVersion, &ws)) {
std::cout << "Failed to WSAStartup." << std::endl;
std::cout << "Error code: " << WSAGetLastError() << std::endl;
WSACleanup();
return SOCKET_ERROR;
}
Socket = socket(AF_INET, SOCK_STREAM, NULL);
if (Socket == INVALID_SOCKET) {
std::cout << "Failed to create server socket." << std::endl;
std::cout << "Error code: " << WSAGetLastError() << std::endl;
WSACleanup();
return SOCKET_ERROR;
}
Info.sin_family = AF_INET;
Info.sin_port = htons(port);
Info.sin_addr.s_addr = INADDR_ANY;
sizeInfo = sizeof(Info);
if (bind(Socket, (const sockaddr *)&Info, sizeInfo)) {
std::cout << "Failed to bind server socket" << std::endl;
std::cout << "Error: " << WSAGetLastError() << std::endl;
WSACleanup();
return SOCKET_ERROR;
}
if (listen(Socket, MAX_NUM_CLIENTS)) {
std::cout << "Failed to listen" << std::endl;
std::cout << "Error: " << WSAGetLastError() << std::endl;
WSACleanup();
return SOCKET_ERROR;
}
std::cout << "Сервер запущен." << std::endl;
waitingClients();
return 1;
}
void server::close() {
closesocket(Socket);
WSACleanup();
}
void server::waitingClients() {
while (1) {
if (acceptClient())
threadClient.push_back(std::thread(&server::handleClient, this, lastClient));
}
}
void server::handleClient(client *__client) {
char buff[BUFFER_SIZE];
message welcomeMess;
welcomeMess.type = INF;
welcomeMess.text = "Добро пожаловать " + __client->name + ". Список команд help";
SendClientMessage(__client, welcomeMess);
int recvBytes, res;
while (true) {
recvBytes = recv(__client->Socket, buff, BUFFER_SIZE, 0);
if (recvBytes != SOCKET_ERROR) {
buff[recvBytes] = '\0';
res = onClientCommandText(__client, handleMessage(std::string(buff)));
if (res == -1) break;
}
else break;
}
rejectClient(__client);
}
message server::handleMessage(std::string __message) {
int dividerLength;
message newMessage;
size_t first;
size_t last;
dividerLength = strlen(divider);
// Type message
first = 0;
last = __message.find(divider);
newMessage.type = std::stoi(__message.substr(0, last));
// Name
first = last + dividerLength;
last = __message.find(divider, first);
newMessage.name = __message.substr(first, last - first);
// Info
first = last + dividerLength;
last = __message.find(divider, first);
newMessage.info = __message.substr(first, last - first);
// Text
first = last + dividerLength;
last = __message.find(divider, first);
newMessage.text = __message.substr(first, last - first);
return newMessage;
}
bool server::acceptClient() {
client * newClient = new client;
newClient->sizeInfo = sizeof(newClient->Info);
newClient->Socket = accept(this->Socket, (sockaddr *)&newClient->Info, &newClient->sizeInfo);
newClient->name = "User" + std::to_string(threadClient.size());
if (newClient->Socket == INVALID_SOCKET) {
std::cout << "Клиент " << newClient->Socket << "error (" << WSAGetLastError() << ")" << std::endl;
return 0;
}
if (numClients == MAX_NUM_CLIENTS) {
message infMess;
infMess.type = INF;
infMess.text = "нет места";
SendClientMessage(newClient, infMess);
closesocket(newClient->Socket);
return 0;
}
if (firstClient == NO_CLIENT)
firstClient = lastClient = newClient;
else {
newClient->prev = lastClient;
lastClient->next = newClient;
lastClient = newClient;
}
numClients++;
std::cout << "Клиент " << newClient->Socket << " подключен." << std::endl;
return 1;
}
int server::SendClientMessage(client *__client, message __mess) {
std::string s;
s = std::to_string(__mess.type) + this->divider + __mess.name + this->divider +
__mess.info + this->divider + __mess.text + this->divider;
int sendBytes;
if ((sendBytes = send(__client->Socket, s.c_str(), s.size(), NULL)) == SOCKET_ERROR) {
//std::cout << "Ошибка при отправке сообщения клиенту " << __client->Socket << " (" << WSAGetLastError() << ")" << std::endl;
return SOCKET_ERROR;
}
return sendBytes;
}
void server::rejectClient(client *__client) {
if (firstClient == lastClient && firstClient == __client)
firstClient = lastClient = NO_CLIENT;
else if (lastClient == __client)
lastClient = lastClient->prev;
else if (firstClient == __client)
firstClient = firstClient->next;
else {
__client->prev->next = __client->next;
__client->next->prev = __client->prev;
}
std::cout << "Клиент " << __client->Socket << " отлючен." << std::endl;
numClients--;
closesocket(__client->Socket);
delete __client;
}
int server::onClientCommandText(client *__client, message __mess) {
message infoMess;
size_t t, commandLength;
infoMess.type = INF;
commandLength = infoMess.info.size();
if (!validCommand(__mess.info)) {
infoMess.text = "Неверная команда. Список команд help";
SendClientMessage(__client, infoMess);
return 0;
}
if (__mess.info == "help") {
infoMess.text = "\
\rВыход - exit\n\
\rСменить имя - login [новое имя]\n\
\rСписок пользователей - logAll\n\
\rОтправить сообщение всем пользователям - messAll [сообщение]\n\
\rОтправить сообщение пользователю - messPr [имя пользователя] [сообщение]\n\
\rОтправить файл - file [имя пользователя] [путь к файлу]";
SendClientMessage(__client, infoMess);
return 1;
}
else if (__mess.info == "login") {
if (__mess.name.empty()) {
infoMess.text = "Используйте: login [новое имя]";
SendClientMessage(__client, infoMess);
return 0;
}
for (auto &ch : __mess.name) {
if (!isalpha(ch) && !isdigit(ch)) {
infoMess.text = "Неверное имя (используйте только буквы и цифры)";
SendClientMessage(__client, infoMess);
return 0;
}
}
for (client *currentClient = firstClient; currentClient; currentClient = currentClient->next) {
if (currentClient->name == __mess.name) {
infoMess.text = "Данное имя занято.";
SendClientMessage(__client, infoMess);
return 0;
}
}
infoMess.text = "Ваше имя " + __client->name + " было успешно заменено на " + __mess.name;
SendClientMessage(__client, infoMess);
__client->name = __mess.name;
return 1;
}
else if ((t = __mess.info.find("logAll")) != std::string::npos) {
infoMess.text = "Список пользователей";
for (client *currentClient = firstClient; currentClient; currentClient = currentClient->next) {
infoMess.text = infoMess.text + "#ln" + currentClient->name;
}
SendClientMessage(__client, infoMess);
return 1;
}
else if ((t = __mess.info.find("messPr")) != std::string::npos) {
if (__mess.name.empty()) {
infoMess.text = "Используйте: messPr [имя пользователя] [сообщение]";
SendClientMessage(__client, infoMess);
return 0;
}
bool userIsNotFound = true;
client *receiver = new client;
for (client *currentClient = firstClient; currentClient; currentClient = currentClient->next) {
if (currentClient->name == __mess.name) {
userIsNotFound = false;
receiver = currentClient;
}
}
if (userIsNotFound) {
infoMess.text = "Пользователь с таким именем не найден.";
SendClientMessage(__client, infoMess);
return 0;
}
__mess.name = __client->name;
SendClientMessage(receiver, __mess);
return 1;
}
else if ((t = __mess.info.find("messAll")) != std::string::npos) {
__mess.name = __client->name;
for (client *currentClient = firstClient; currentClient; currentClient = currentClient->next)
if(currentClient != __client) SendClientMessage(currentClient, __mess);
return 1;
}
else if ((t = __mess.info.find("exit")) != std::string::npos) {
if (SendClientMessage(__client, __mess) == SOCKET_ERROR) return -1;
return -1;
}
else if ((t = __mess.info.find("file")) != std::string::npos) {
if (__mess.name.empty()) {
infoMess.text = "Используйте: file [имя пользователя] [путь к файлу]";
SendClientMessage(__client, infoMess);
return 0;
}
bool userIsNotFound = true;
client *receiver = new client;
for (client *currentClient = firstClient; currentClient; currentClient = currentClient->next) {
if (currentClient->name == __mess.name) {
userIsNotFound = false;
receiver = currentClient;
}
}
if (userIsNotFound) {
infoMess.text = "Пользователь с таким именем не найден.";
SendClientMessage(__client, infoMess);
return 0;
}
t = __mess.text.rfind("\\");
if (t == std::string::npos) {
t = -1;
}
__mess.text = __mess.text.substr(t+1);
__mess.name = __client->name;
int sendBytes;
sendBytes = SendClientMessage(receiver, __mess);
int recvBytes;
char buffer[BUFFER_SIZE];
recvBytes = recv(__client->Socket, buffer, BUFFER_SIZE, 0);
buffer[recvBytes] = '\0';
std::string text;
if (recvBytes == SOCKET_ERROR)
return 0;
for (int i = 0; i < recvBytes; i++) {
text.push_back(buffer[i]);
}
__mess = handleMessage(text);
sendBytes = SendClientMessage(receiver, __mess);
return 1;
}
else {
infoMess.text = "Неверная команда. Список команд help";
SendClientMessage(__client, infoMess);
return 0;
}
}
bool server::validCommand(std::string __command) {
size_t commandLength = __command.length();
const char commands[][8] = { "help", "login", "logAll", "messAll", "messPr", "exit", "file" };
for (int i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
if ((__command.find(commands[i]) != std::string::npos) && (__command.length() != strlen(commands[i])))
return 0;
}
return 1;
}