Advertisement
Guest User

client

a guest
Jul 5th, 2017
275
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.41 KB | None | 0 0
  1. #include <sys/mman.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <netinet/tcp.h>
  6. #include <unistd.h>
  7. #include <sched.h>
  8. #include <exception>
  9. #include <string.h>
  10. #include <sys/epoll.h>
  11. #include <iostream>
  12. #include <array>
  13. #include <vector>
  14.  
  15.  
  16. int safe_call(int ret, const char * ctx) {
  17. //   fprintf(stderr, "%s == %d, errno(%d) == %s\n", ctx, ret, errno, strerror(errno));
  18.   if((ret == -1) && (errno != EINPROGRESS)) throw std::runtime_error(std::string(ctx) +  " == " + std::to_string(ret) + ", errno(" + std::to_string(errno) + ')'  + " == " + strerror(errno));
  19.   return ret;
  20. }
  21. #define safe_call(call) safe_call(call, #call)
  22.  
  23. int connect_to(in_addr_t addr, uint16_t port) {
  24.   sockaddr_in saddr{};
  25.   saddr.sin_family = AF_INET;
  26.   saddr.sin_port = htons(port);
  27.   saddr.sin_addr.s_addr = htonl(addr);
  28.   int fd = safe_call(socket(AF_INET, SOCK_NONBLOCK | SOCK_STREAM, 0));
  29.   safe_call(connect(fd, (__CONST_SOCKADDR_ARG)&saddr, sizeof(saddr)));
  30.   return fd;
  31. }
  32.  
  33.  
  34.  
  35.  
  36. class alignas(64) client {
  37. public:
  38.  
  39.  
  40.   void connect(in_addr_t addr, uint16_t port) {
  41. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  42.     this->addr = addr;
  43.     this->port = port;
  44.     fd = connect_to(addr, port);
  45.     add_to_epoll();
  46.     ++active_connections;
  47.   }
  48.  
  49.  
  50.  
  51.   void close() {
  52. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  53.     remove_from_epoll();
  54.     safe_call(::close(fd));
  55.     --active_connections;
  56.   }
  57.  
  58.   size_t get_rq() {
  59.     return count;
  60.   }
  61.  
  62.   client() = default;
  63.   client(client && o) = delete;
  64.   client(client & o) = delete;
  65.   client & operator=(const client & o) = delete;  
  66.   client & operator=(client && o) = delete;
  67.   ~client() = default;
  68.  
  69.  
  70.   void run() {
  71. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  72.     size_t data = fd;
  73.     safe_call(write(fd, &data, sizeof(data)));
  74.     update_events(EPOLLIN | EPOLLRDHUP | EPOLLET);
  75.   }
  76.  
  77.  
  78. protected:
  79.  
  80.   void add_to_epoll() {
  81.     epoll_event eevent;
  82.     eevent.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET;
  83.     eevent.data.ptr = (void *)this;
  84.     safe_call(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &eevent));
  85.   }
  86.  
  87.   void update_events(uint32_t ev) {
  88.     epoll_event eevent;
  89.     eevent.events = ev;
  90.     eevent.data.ptr = (void *)this;
  91.     safe_call(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &eevent));
  92.   }
  93.  
  94.   void remove_from_epoll() {
  95.     safe_call(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr));
  96.   }
  97.  
  98.   void update_next() {
  99. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  100.     uint64_t * it = (uint64_t *)buff, * end = it + (sizeof(buff) / sizeof(uint64_t));
  101.     do {
  102.       if(*it != size_t(fd)) throw std::runtime_error{"bad data"};
  103.     } while(++it < end);
  104.     buff_cur = 0; memset(buff, 0, sizeof(buff)); ++count;
  105.   }
  106.  
  107.   void update_buff() {
  108. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  109.     while(ssize_t r = read(fd, buff, (sizeof(buff) - buff_cur))) {
  110.       if(r == -1) return;
  111.       buff_cur += r;
  112.       if(buff_cur == sizeof(buff)) update_next();
  113.     }
  114.   }
  115.  
  116. protected:
  117.   in_addr_t addr;
  118.   uint16_t port;
  119.   int fd;
  120.   size_t buff_cur = 0, count = 0;
  121.   uint8_t buff[1024];
  122.  
  123. protected:
  124.   static constexpr size_t epoll_size = 1024, epoll_event_size = 1024;
  125.   static inline int epoll_fd = safe_call(epoll_create(epoll_size));
  126.   static inline std::array<epoll_event, epoll_event_size> edata;
  127.   static inline size_t active_connections = 0;
  128.  
  129. public:
  130.  
  131.   static void run(size_t timeout) {
  132.    
  133.     while(1) {
  134.       size_t n = safe_call(epoll_wait(epoll_fd, std::begin(edata), edata.size(), timeout));
  135.      
  136.       if(!active_connections) return;
  137.      
  138.       for(auto it = std::begin(edata), end = it + n; it < end; ++it) {
  139.         ((client *)(it->data.ptr))->wait_handler(it->events);
  140.       }
  141.     }
  142.   }
  143. protected:
  144.  
  145.   void wait_handler(uint32_t events) try {
  146. //     fprintf(stderr, "%s, events == %x\n", __PRETTY_FUNCTION__, events);
  147.      
  148.     if(events & EPOLLOUT) run();
  149.     if(events & EPOLLIN) update_buff();  
  150.     if(events & EPOLLRDHUP) close();
  151.   } catch(const std::exception & e) { std::cerr << e.what() << std::endl; std::terminate();}
  152. };
  153.  
  154.  
  155. int main() {
  156.   in_addr_t addr = INADDR_LOOPBACK; uint16_t port = 8888;
  157.   std::vector<client> v(10000);
  158.   for(auto & x : v) x.connect(addr, port);
  159.  
  160.  
  161.   client::run(50);
  162.  
  163.   size_t rq = 0;
  164.  
  165.   for(auto & x : v) rq += x.get_rq();
  166.  
  167.   fprintf(stderr, "rq = %lu\n", rq);
  168. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement