Endil

cn-lab5-server

Dec 18th, 2015
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.90 KB | None | 0 0
  1. // cn-lab5-server.cpp: определяет точку входа для консольного приложения.
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include <chrono>
  6. #include <iostream>
  7. #include <map>
  8. #include <regex>
  9. #include <string>
  10. #include <thread>
  11. #include <vector>
  12. #include <winsock2.h>
  13.  
  14. #pragma comment(lib, "ws2_32.lib")
  15.  
  16. using namespace std;
  17. using namespace std::chrono;
  18.  
  19. typedef long long ll;
  20. typedef unsigned long long ull;
  21. typedef time_point<system_clock, milliseconds> timepoint;
  22.  
  23. vector<thread> connected_clients_list;
  24.  
  25. timepoint str_to_tp (const string _tp) {
  26.     milliseconds tp_m(stoull(_tp));
  27.     timepoint tp(tp_m);
  28.     return tp;
  29. }
  30.  
  31. class Message {
  32. private:
  33.      timepoint tp;
  34.      string dest_num;
  35.      string text;
  36.      bool deletable;
  37. public:
  38.     Message(const timepoint &_tp, const string &_dest_num, const string &_text, const bool &_deletable)
  39.         : tp(_tp), dest_num(_dest_num), text(_text), deletable(_deletable) {};
  40.     string get_dest_number() const {
  41.         return dest_num;
  42.     }
  43.     bool is_deletable() const {
  44.         return deletable;
  45.     }
  46.     timepoint get_tp() const {
  47.         return tp;
  48.     }
  49. };
  50.  
  51. class MessageList {
  52. private:
  53.     vector<Message> messages;
  54. public:
  55.     void add(const string &_tp, const string &_dest_number, const string &_text, const bool &_deletable = false) {
  56.         timepoint tp = str_to_tp(_tp);
  57.         messages.emplace_back(tp, _dest_number, _text, _deletable);
  58.         return;
  59.     }
  60.     void remove(const string &_timepoint, const string &_dest_number) {
  61.         for (auto i = messages.rbegin(); i != messages.rend(); i++)
  62.             if (i->get_dest_number() == _dest_number) {
  63.                 if (i->is_deletable() == true) {
  64.                     timepoint tp = str_to_tp(_timepoint);
  65.                     milliseconds period(60000);
  66.                     if (duration_cast<milliseconds>(tp - i->get_tp()) <= period) {
  67.                         messages.erase(next(i).base());
  68.                         return;
  69.                     }
  70.                     throw exception("&del_fail_too_late");
  71.                 }
  72.                 throw exception("&del_fail_not_deletable");
  73.             }
  74.         throw exception("&del_fail_no_such_addressee");
  75.     }
  76. };
  77.  
  78. map<const string, MessageList> client_message_list;
  79.  
  80. class Network {
  81. private:
  82.     SOCKET main_sock;
  83.     map<string, pair<sockaddr_in, SOCKET>> client_list;
  84.     string receive(const SOCKET sock) const {
  85.         char recv_buff[65536];
  86.         int len = recv(sock, &recv_buff[0], sizeof(recv_buff) - 1, 0);
  87.         if (len == -1)
  88.             throw exception("&wsa_error_recv");
  89.         recv_buff[len] = 0;
  90.         string s = recv_buff;
  91.         return s;
  92.     }
  93. public:
  94.     Network() {
  95.         WSAData wsadata;
  96.         WSAStartup(0x0202, &wsadata);
  97.         cout << "WinSock2 initialized" << endl;
  98.     }
  99.     ~Network() {
  100.         WSACleanup();
  101.     }
  102.     void start(const int &port) {
  103.         main_sock = socket(AF_INET, SOCK_STREAM, 0);
  104.         cout << "Main socket created successfully" << endl;
  105.         sockaddr_in addr_local;
  106.         addr_local.sin_family = AF_INET;
  107.         addr_local.sin_addr.S_un.S_addr = 0;
  108.         addr_local.sin_port = htons(port);
  109.         ::bind(main_sock, (sockaddr *)&addr_local, sizeof(addr_local));
  110.         cout << "Port " << ntohs(addr_local.sin_port) << " bound successful" << endl;
  111.         listen(main_sock, SOMAXCONN);
  112.         cout << "Listening port 5005" << endl;
  113.         return;
  114.     }
  115.     void stop() {
  116.         for (auto pair : client_list) {
  117.             send(pair.first, "&server_stop");
  118.             closesocket(pair.second.second);
  119.         }
  120.         closesocket(main_sock);
  121.         return;
  122.     }
  123.     void send(const string &num, const string &s) const {
  124.         try {
  125.             ::send(client_list.at(num).second, s.c_str(), s.length(), 0);
  126.         }
  127.         catch (exception e) {
  128.             cout << e.what() << endl;
  129.         }
  130.         return;
  131.     }
  132.     string receive (const string &num) const {
  133.         char recv_buff[65536];
  134.         int len = recv(client_list.at(num).second, &recv_buff[0], sizeof(recv_buff) - 1, 0);
  135.         if (len == -1)
  136.             throw exception("&wsa_error_recv");
  137.         recv_buff[len] = 0;
  138.         string s = recv_buff;
  139.         return s;
  140.     }
  141.     string accept() {
  142.         sockaddr_in client_addr;
  143.         int client_addr_size = sizeof(client_addr);
  144.         SOCKET client_sock = ::accept(main_sock, (sockaddr *)&client_addr, &client_addr_size);
  145.         if (client_sock == INVALID_SOCKET)
  146.             throw exception("&wsa_error_accept");
  147.         string num;
  148.         try {
  149.             num = receive(client_sock);
  150.         }
  151.         catch (exception e) {
  152.                 throw e;
  153.         }
  154.         cout << num << " connected" << endl;
  155.         client_list.try_emplace(num, make_pair(client_addr, client_sock));
  156.         return num;
  157.     }
  158. }network;
  159.  
  160. class Commands {
  161. private:
  162.     map<string, void(Commands::*)(const smatch &, const string &) const> command_list;
  163.     void sms(const smatch &input, const string &num) const {
  164.         if (input.str(3) == "-d") {
  165.             client_message_list.at(num).add(input.str(1), input.str(4), input.str(5), true);
  166.             cout << "Message from " << num << " to " << input.str(4) << " send success" << endl;
  167.         }
  168.         else {
  169.             client_message_list.at(num).add(input.str(1), input.str(3), input.str(4));
  170.             cout << "Message from " << num << " to " << input.str(3) << " send success" << endl;
  171.             return;
  172.         }
  173.         network.send(num, "&sms_success");
  174.         return;
  175.     }
  176.     void del(const smatch &input, const string &num) const {
  177.         try {
  178.             client_message_list.at(num).remove(input.str(1), input.str(3));
  179.         }
  180.         catch (exception e) {
  181.             cout << "Message from " << num << " to " << input.str(3) << " delete failed: " << e.what() << endl;
  182.             network.send(num, e.what());
  183.             return;
  184.         }
  185.         cout << "Message from " << num << " to " << input.str(3) << " delete success" << endl;
  186.         network.send(num, "&del_success");
  187.         return;
  188.     }
  189. public:
  190.     Commands() {
  191.         command_list.emplace("sms", &Commands::sms);
  192.         command_list.emplace("del", &Commands::del);
  193.     }
  194.     void exec(const smatch &input, const string &num) const {
  195.         (this->*command_list.at(input.str(2)))(input, num);
  196.         return;
  197.     }
  198. }commands;
  199.  
  200. map<string, string> wsa_except_list = { {"&wsa_error_accept", "accept error "},
  201.                                         {"&wsa_error_recv", "recv error "} };
  202.  
  203. void client_process(const string &num) {
  204.     client_message_list.try_emplace(num);
  205.     while (true) {
  206.         string s;
  207.         try {
  208.             s = network.receive(num);
  209.         }
  210.         catch (exception e) {
  211.             cout << wsa_except_list.at(e.what()) << WSAGetLastError() << endl;
  212.             return;
  213.         }
  214.         regex pattern(R"(^(\d+)\s(".+"|[.\S]+)\s*(".*"|[.\S]*)\s*(".*"|[.\S]*)\s*(".*"|[.\S]*)\s*$)");
  215.         smatch match_results;
  216.         regex_match(s, match_results, pattern);
  217.         commands.exec(match_results, num);
  218.     }
  219.     cout << num << " disconnected" << endl;
  220.     return;
  221. }
  222.  
  223. void port_listen() {
  224.     while (true) {
  225.         string num;
  226.         try {
  227.             num = network.accept();
  228.         }
  229.         catch (exception e) {
  230.             cout << wsa_except_list.at(e.what()) << WSAGetLastError() << endl;
  231.             return;
  232.         }
  233.         connected_clients_list.emplace_back(client_process, num);
  234.     }
  235.     return;
  236. }
  237.  
  238. int main()
  239. {
  240.     cout << "cn-lab5 var10 server was started" << endl;
  241.     network.start(5005);
  242.     thread listen(port_listen);
  243.     string s;
  244.     do {
  245.         cin >> s;
  246.     } while (s != "stop" && s != "exit");
  247.  
  248.     network.stop();
  249.     if (listen.joinable())
  250.         listen.join();
  251.     for (auto i = 0; i < connected_clients_list.size(); i++)
  252.         if (connected_clients_list.at(i).joinable())
  253.             connected_clients_list.at(i).join();
  254.     cout << "cn-lab5 var10 server was stopped" << endl;
  255.     return 0;
  256. }
Add Comment
Please, Sign In to add comment