Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // cn-lab5-server.cpp: определяет точку входа для консольного приложения.
- //
- #include "stdafx.h"
- #include <chrono>
- #include <iostream>
- #include <map>
- #include <regex>
- #include <string>
- #include <thread>
- #include <vector>
- #include <winsock2.h>
- #pragma comment(lib, "ws2_32.lib")
- using namespace std;
- using namespace std::chrono;
- typedef long long ll;
- typedef unsigned long long ull;
- typedef time_point<system_clock, milliseconds> timepoint;
- vector<thread> connected_clients_list;
- timepoint str_to_tp (const string _tp) {
- milliseconds tp_m(stoull(_tp));
- timepoint tp(tp_m);
- return tp;
- }
- class Message {
- private:
- timepoint tp;
- string dest_num;
- string text;
- bool deletable;
- public:
- Message(const timepoint &_tp, const string &_dest_num, const string &_text, const bool &_deletable)
- : tp(_tp), dest_num(_dest_num), text(_text), deletable(_deletable) {};
- string get_dest_number() const {
- return dest_num;
- }
- bool is_deletable() const {
- return deletable;
- }
- timepoint get_tp() const {
- return tp;
- }
- };
- class MessageList {
- private:
- vector<Message> messages;
- public:
- void add(const string &_tp, const string &_dest_number, const string &_text, const bool &_deletable = false) {
- timepoint tp = str_to_tp(_tp);
- messages.emplace_back(tp, _dest_number, _text, _deletable);
- return;
- }
- void remove(const string &_timepoint, const string &_dest_number) {
- for (auto i = messages.rbegin(); i != messages.rend(); i++)
- if (i->get_dest_number() == _dest_number) {
- if (i->is_deletable() == true) {
- timepoint tp = str_to_tp(_timepoint);
- milliseconds period(60000);
- if (duration_cast<milliseconds>(tp - i->get_tp()) <= period) {
- messages.erase(next(i).base());
- return;
- }
- throw exception("&del_fail_too_late");
- }
- throw exception("&del_fail_not_deletable");
- }
- throw exception("&del_fail_no_such_addressee");
- }
- };
- map<const string, MessageList> client_message_list;
- class Network {
- private:
- SOCKET main_sock;
- map<string, pair<sockaddr_in, SOCKET>> client_list;
- string receive(const SOCKET sock) const {
- char recv_buff[65536];
- int len = recv(sock, &recv_buff[0], sizeof(recv_buff) - 1, 0);
- if (len == -1)
- throw exception("&wsa_error_recv");
- recv_buff[len] = 0;
- string s = recv_buff;
- return s;
- }
- public:
- Network() {
- WSAData wsadata;
- WSAStartup(0x0202, &wsadata);
- cout << "WinSock2 initialized" << endl;
- }
- ~Network() {
- WSACleanup();
- }
- void start(const int &port) {
- main_sock = socket(AF_INET, SOCK_STREAM, 0);
- cout << "Main socket created successfully" << endl;
- sockaddr_in addr_local;
- addr_local.sin_family = AF_INET;
- addr_local.sin_addr.S_un.S_addr = 0;
- addr_local.sin_port = htons(port);
- ::bind(main_sock, (sockaddr *)&addr_local, sizeof(addr_local));
- cout << "Port " << ntohs(addr_local.sin_port) << " bound successful" << endl;
- listen(main_sock, SOMAXCONN);
- cout << "Listening port 5005" << endl;
- return;
- }
- void stop() {
- for (auto pair : client_list) {
- send(pair.first, "&server_stop");
- closesocket(pair.second.second);
- }
- closesocket(main_sock);
- return;
- }
- void send(const string &num, const string &s) const {
- try {
- ::send(client_list.at(num).second, s.c_str(), s.length(), 0);
- }
- catch (exception e) {
- cout << e.what() << endl;
- }
- return;
- }
- string receive (const string &num) const {
- char recv_buff[65536];
- int len = recv(client_list.at(num).second, &recv_buff[0], sizeof(recv_buff) - 1, 0);
- if (len == -1)
- throw exception("&wsa_error_recv");
- recv_buff[len] = 0;
- string s = recv_buff;
- return s;
- }
- string accept() {
- sockaddr_in client_addr;
- int client_addr_size = sizeof(client_addr);
- SOCKET client_sock = ::accept(main_sock, (sockaddr *)&client_addr, &client_addr_size);
- if (client_sock == INVALID_SOCKET)
- throw exception("&wsa_error_accept");
- string num;
- try {
- num = receive(client_sock);
- }
- catch (exception e) {
- throw e;
- }
- cout << num << " connected" << endl;
- client_list.try_emplace(num, make_pair(client_addr, client_sock));
- return num;
- }
- }network;
- class Commands {
- private:
- map<string, void(Commands::*)(const smatch &, const string &) const> command_list;
- void sms(const smatch &input, const string &num) const {
- if (input.str(3) == "-d") {
- client_message_list.at(num).add(input.str(1), input.str(4), input.str(5), true);
- cout << "Message from " << num << " to " << input.str(4) << " send success" << endl;
- }
- else {
- client_message_list.at(num).add(input.str(1), input.str(3), input.str(4));
- cout << "Message from " << num << " to " << input.str(3) << " send success" << endl;
- return;
- }
- network.send(num, "&sms_success");
- return;
- }
- void del(const smatch &input, const string &num) const {
- try {
- client_message_list.at(num).remove(input.str(1), input.str(3));
- }
- catch (exception e) {
- cout << "Message from " << num << " to " << input.str(3) << " delete failed: " << e.what() << endl;
- network.send(num, e.what());
- return;
- }
- cout << "Message from " << num << " to " << input.str(3) << " delete success" << endl;
- network.send(num, "&del_success");
- return;
- }
- public:
- Commands() {
- command_list.emplace("sms", &Commands::sms);
- command_list.emplace("del", &Commands::del);
- }
- void exec(const smatch &input, const string &num) const {
- (this->*command_list.at(input.str(2)))(input, num);
- return;
- }
- }commands;
- map<string, string> wsa_except_list = { {"&wsa_error_accept", "accept error "},
- {"&wsa_error_recv", "recv error "} };
- void client_process(const string &num) {
- client_message_list.try_emplace(num);
- while (true) {
- string s;
- try {
- s = network.receive(num);
- }
- catch (exception e) {
- cout << wsa_except_list.at(e.what()) << WSAGetLastError() << endl;
- return;
- }
- regex pattern(R"(^(\d+)\s(".+"|[.\S]+)\s*(".*"|[.\S]*)\s*(".*"|[.\S]*)\s*(".*"|[.\S]*)\s*$)");
- smatch match_results;
- regex_match(s, match_results, pattern);
- commands.exec(match_results, num);
- }
- cout << num << " disconnected" << endl;
- return;
- }
- void port_listen() {
- while (true) {
- string num;
- try {
- num = network.accept();
- }
- catch (exception e) {
- cout << wsa_except_list.at(e.what()) << WSAGetLastError() << endl;
- return;
- }
- connected_clients_list.emplace_back(client_process, num);
- }
- return;
- }
- int main()
- {
- cout << "cn-lab5 var10 server was started" << endl;
- network.start(5005);
- thread listen(port_listen);
- string s;
- do {
- cin >> s;
- } while (s != "stop" && s != "exit");
- network.stop();
- if (listen.joinable())
- listen.join();
- for (auto i = 0; i < connected_clients_list.size(); i++)
- if (connected_clients_list.at(i).joinable())
- connected_clients_list.at(i).join();
- cout << "cn-lab5 var10 server was stopped" << endl;
- return 0;
- }
Add Comment
Please, Sign In to add comment