Advertisement
skuf1973

Untitled

Apr 6th, 2020
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.37 KB | None | 0 0
  1. /* Пример использования функции listen()
  2.  * (c) Лёха @ 2020
  3.  */
  4. #include <stdio.h>
  5. #include <Windows.h>
  6. #include <WinSock2.h>
  7.  
  8. /* Начнём с того, что это адрес и порт, на которых мы будем слушать
  9.  * входящие соединения.
  10.  */
  11. const char listenOnAddr[] = "127.0.0.1";
  12. const unsigned short listenOnPort = 80;
  13. const unsigned int listenTimeout = 3; // В секундах
  14.  
  15. /* Описание клиента на той стороне сокета. Добавить поля по вкусу
  16.  */
  17. typedef struct _client {
  18.     int fd;
  19.  
  20. } client_t;
  21.  
  22.  
  23. static client_t *_clients;
  24. static int numberOfClients, clientsArraySize;
  25.  
  26.  
  27. /* Получение структуры для нового клиента.
  28.  */
  29. client_t *allocClient()
  30. {
  31.     client_t *temp;
  32.  
  33.     /* Стратегия выделения памяти такая. При нехватке места в массиве клиентов увеличиваем
  34.      * его в два раза. Константа 16 взята из головы, не парься
  35.      */
  36.     if(numberOfClients == clientsArraySize) {
  37.         temp = (client_t *)realloc(_clients, sizeof(client_t)*(clientsArraySize? clientsArraySize: 16));
  38.         if(NULL == temp)
  39.             return NULL;
  40.     }
  41.  
  42.     temp = _clients + numberOfClients;
  43.     ++numberOfClients;
  44.  
  45.     return temp;    
  46. }
  47.  
  48.  
  49. /* Поиск описателя клиента по его дескриптору сокета
  50.  */
  51. client_t *findClientByFd(int fdToFind)
  52. {
  53.     for(int i=0; i<numberOfClients; ++i) {
  54.         if(_clients[i].fd == fdToFind)
  55.             return &_clients[i];
  56.     }
  57.     return NULL;
  58. }
  59.  
  60.  
  61. int main(int argc, char *argv[])
  62. {
  63.     struct hostent *host;
  64.     SOCKET listenSock;
  65.     struct timeval tmo;
  66.  
  67.     _clients = NULL;
  68.     numberOfClients = 0;
  69.     clientsArraySize = 0;
  70.  
  71. /* Резольвим имя нашего хоста, на котором будем слушать коннекты от клиентов
  72.  */
  73.     host = gethostbyname(listenOnAddr);
  74.     if(NULL == host) {
  75.         printf("Неизвестное имя хоста %s\n", listenOnAddr);
  76.         return EXIT_FAILURE;
  77.     }
  78.  
  79. /* Создаём сокет, на котором будем слушать
  80.  */
  81.     listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Или SOCK_DGRAM и IPPROTO_UDP, по вкусу
  82.     if(INVALID_SOCKET == listenSock) {
  83.         printf("Не удалось создать сокет\n");
  84.         return EXIT_FAILURE;
  85.     }
  86.  
  87. /* Привязываемся
  88.  */
  89.     if(SOCKET_ERROR == bind(listenSock, host->h_addr_list[0], sizeof(host->h_addr_list[0]))) {
  90.         printf("Не удалось привязаться к данному адресу: %s\n", listenOnAddr);
  91.         return EXIT_FAILURE;
  92.     }
  93.  
  94. /* Слушаем входящие соединения
  95.  */
  96.     SOCKET s = listen(listenSock, 0);
  97.  
  98.  /* Вот тут начинается немного магии
  99.   */
  100.     fd_set rdfds;
  101.  
  102.     for(;;) {
  103.         /* заполняем структуру fd_set для чтения номерами дескрипторов, которые надо
  104.          * слушать. Можно, конечно, заполнить структуры, которые отвечают
  105.          * за запись и ошибки сокетов, но на практике этого никогда не
  106.          * приходилось использовать. Обычно сокеты доступны на запись всегда,
  107.          * а ошибки ловятся другими способами.
  108.          */
  109.         FD_SET(listenSock, &rdfds); // Дескриптор который принимает соединения
  110.         for(int i=0; i<numberOfClients; ++i) {
  111.             FD_SET(_clients[i].fd, &rfds); // И все другие клиенты
  112.         }
  113.  
  114.         tmo.tv_sec = listenTimeout;
  115.         tmo.tv_usec = 0;
  116.  
  117.         /* Вызов select() закончится либо по событию, либо по таймауту.
  118.          * +1, потому что к клиентам прибавлен 1 сокет, на котором
  119.          * слушаем новые соединения.
  120.          */
  121.         int nfds = select(numberOfClients+1, &rdfds, NULL, NULL, &tmo);
  122.         if(SOCKET_ERROR == nfds) {
  123.             if(WSAEINTR == WSAGetLastError())
  124.                 continue;
  125.             printf("Ошибка сетевой подсистемы %u\n", WSAGetLastError());
  126.             break; // Лениво писать обрабтчик ошибок, прости :)
  127.         }
  128.  
  129.         /* После вызова select(), fd_set rfds содержит номера дескрипторов,
  130.          * у которых либо а) в случае listenSock произошло новое соединение,
  131.          * либо у других есть данные, которые можно прочитать
  132.          */
  133.         if(FD_ISSET(s, &rdfds)) {
  134.             struct sockaddr_in addr;
  135.             int addrLen = sizeof(addr);
  136.             SOCKET newClient = accept(s, (struct sockaddr *)&addr, addrLen);
  137.            
  138.             client_t *newClient = allocClient();
  139.             if(NULL == newClient) {
  140.                 printf("Мало памяти\n");
  141.                 exit(EXIT_FAILURE);
  142.             }
  143.  
  144.             /* Тут можно заполнить структуру, описывающую клиента. Инициализация
  145.              * и всё такое
  146.              */
  147.  
  148.             // -----
  149.  
  150.             /* Если вызов read() вернёт 0, то значит клиент закрыл соединение
  151.              * После этого надо вызвать shutdown(SD_BOTH) и closesocket()
  152.              */
  153.         }
  154.  
  155.         for(int i=0; i<numberOfClients; ++i) {
  156.             if(FD_ISSET(_clients[i].fd, &rdfds)) {
  157.                 /* Тут читаем из соответствующего сокета данные и обрабатываем их,
  158.                  * как надо
  159.                  */
  160.             }
  161.         }
  162.  
  163.         /* Если nfds равно нулю, значит случился таймаут. Тут можно
  164.          * слать хартбит. Ну или что там
  165.          */
  166.     }
  167.  
  168.     return EXIT_SUCCESS;
  169. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement