Advertisement
Endil

cn-lab5-server

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