Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lab2 / server / server

.cpp
Скачиваний:
11
Добавлен:
01.02.2019
Размер:
9.91 Кб
Скачать
#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;
}

Соседние файлы в папке server