BG Development


Страници: (2) [1] 2   ( Първото ново мнение ) Reply to this topicStart new topicStart Poll

> Сокета. Слушане на два порта
ivelinqnev
Публикувано на: 27-08-2017, 21:23
Quote Post



Име:
Група: Потребител
Ранг: Старо куче

Мнения: 611
Регистриран на: 02.12.08



Имам следния проблем. Имам прост сокет сървър, който трябва да слуша на два различни порта.

Обаче не мога да създам втора структура за 2-рия порт. Някой да е правил подобно нещо?

CODE
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>

void *messages_handler(void *);
void *healthcheck_handler(void *);



int main(int argc, char *argv[]) {
 struct sockaddr_in server_messages, server_healthcheck;
 int socket_messages, socket_healthcheck;

 pthread_t messages_thread;

 pthread_t healthcheck_thread;

 //Create socket
 socket_messages = socket(AF_INET, SOCK_STREAM, 0);
 if (socket_messages == -1) {
   printf("Could not create socket");
 }
 puts("Socket messages created");

 //Prepare the sockaddr_in structure
 server_messages.sin_family = AF_INET;
 server_messages.sin_addr.s_addr = INADDR_ANY;
 server_messages.sin_port = htons(7990);

 //Bind
 if (bind(socket_messages, (struct sockaddr *) &server_messages, sizeof(server_messages)) < 0) {
   //print the error message
   perror("bind failed 1. Error");
   return 1;
 }
 puts("bind done");

 if (pthread_create(&messages_thread, NULL, messages_handler,
                    (void*) &socket_messages) < 0) {
   perror("could not create thread");
   return 1;
 }

 server_healthcheck.sin_family = AF_INET;
 server_healthcheck.sin_addr.s_addr = INADDR_ANY;
 server_healthcheck.sin_port = htons(7994);
 //Bind
   if (bind(server_healthcheck, (struct sockaddr *) &server_healthcheck, sizeof(server_healthcheck)) < 0) {
     //print the error message
     perror("bind failed 2. Error");
     return 1;
   }
   puts("bind done");

   if (pthread_create(&healthcheck_thread, NULL, healthcheck_handler,
                       (void*) &socket_messages) < 0) {
      perror("could not create thread");
      return 1;
    }

 while(1) {

   }

 return 0;
}

void *healthcheck_handler(void *socket_desc) {
 puts("healthcheck_handler");
   //Get the socket descriptor
   int sock = *(int*)socket_desc, client_sock, c, read_size;
   struct sockaddr_in client;
   char client_message[1024];

   //Listen
   listen(sock, 3);

   c = sizeof(struct sockaddr_in);
   puts("Waiting for incoming connections... healthcheck_handler");
   client_sock = accept(sock, (struct sockaddr *) &client, (socklen_t*) &c);
   if (client_sock < 0) {
     puts("accept failed healthcheck_handler");
    // return 1;
   }
   puts("Connection accepted healthcheck_handler");

   while (1) {
       //Receive a reply from the server
       if (recv(client_sock, client_message, 1024, 0) < 0) {
         puts("recv failed healthcheck_handler");
         break;
       }
         puts(client_message);
         puts("\n healthcheck_handler");

     }
   return 0;
}

void *messages_handler(void *socket_desc) {

 puts("messages_handler");
 //Get the socket descriptor
 int sock = *(int*)socket_desc, client_sock, c, read_size;
 struct sockaddr_in client;
 char client_message[1024];

 //Listen
 listen(sock, 3);

 c = sizeof(struct sockaddr_in);
 puts("Waiting for incoming connections...");
 client_sock = accept(sock, (struct sockaddr *) &client, (socklen_t*) &c);
 if (client_sock < 0) {
   puts("accept failed");
  // return 1;
 }
 puts("Connection accepted");

 while (1) {
     //Receive a reply from the server
     if (recv(client_sock, client_message, 1024, 0) < 0) {
       puts("recv failed");
       break;
     }
       puts(client_message);
       puts("\n");

   }
 return 0;
}


Това мнение е било редактирано от ivelinqnev на 27-08-2017, 21:27
PMEmail Poster
Top
gat3way
Публикувано на: 27-08-2017, 21:53
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 1539
Регистриран на: 22.06.12



Еми нормално батка, на двете нишки подаваш един и същ fd, на същия ли ще слушаш, няма да стане това.

P.S на второ четене.... ти какво си сътворил icon_smile.gif Голяма тарапана, компилатора не те ли понаплюва с warning-и. Изобщо няма да стане така, bind-вай си сокетите в главната нишка, ама сокетите, не някакви структури и подавай файловите дескриптори към нишките да си слухтят и чакат за връзки. Това е станало пълен мъзгоч.

Това мнение е било редактирано от gat3way на 27-08-2017, 22:07
PMEmail Poster
Top
kierenski
Публикувано на: 28-08-2017, 08:15
Quote Post



Име:
Група: Потребител
Ранг: Посетител

Мнения: 92
Регистриран на: 10.01.16



Ползвай epool_wait и ще можеш да си го реализираш само с един сокет проверката дали е жив сървъра.
https://banu.com/blog/2/how-to-use-epoll-a-...e-example-in-c/

Идеята е че слушаш на всички fd и когато се появи нова информация се вика съответната предварително конфигурирана функция по групи.

Проверката дали е жив можеш да направиш с допълнителна команда на същия порт. т.е. като изпратиш PING да ти върне PONG и това значи че е жив и не е зает, а това лесно се прави с epool.
PMEmail Poster
Top
bvbfan
Публикувано на: 28-08-2017, 09:28
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 2393
Регистриран на: 08.12.13



Няма нужда от нишки. Направи си сокетите не блокиращи.


--------------------
QUOTE (Bender @ 23-04-2015, 19:11)
Xamarin: ЛАПАЙ!
Ти: Добре...
PMEmail Poster
Top
ivelinqnev
Публикувано на: 28-08-2017, 15:20
Quote Post



Име:
Група: Потребител
Ранг: Старо куче

Мнения: 611
Регистриран на: 02.12.08



QUOTE (gat3way @ 27-08-2017, 21:53)
Еми нормално батка, на двете нишки подаваш един и същ fd, на същия ли ще слушаш, няма да стане това.

P.S на второ четене.... ти какво си сътворил icon_smile.gif Голяма тарапана, компилатора не те ли понаплюва с warning-и. Изобщо няма да стане така, bind-вай си сокетите в главната нишка, ама сокетите, не някакви структури и подавай файловите дескриптори към нишките да си слухтят и чакат за връзки. Това е станало пълен мъзгоч.

Че е тарпана си е така. Направих във всяка нишка да си bind-ва сама.

Това за структурите не го разбрах, bind метода иска структура?
PMEmail Poster
Top
gat3way
Публикувано на: 28-08-2017, 16:13
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 1539
Регистриран на: 22.06.12



По принцип всичко това работи със сокети, които са си обикновени файлови дескриптори, които имат малко екстри, понеже са ммм мрежови файлови дескриптори. Точно така както отваряш и четеш от файлове, така и отваряш и четеш от сокети, верно функциите може да са различни, ама концептуално няма разлика. Структурите които попълваш са помощна информация така както името на файла който ще отваряш и режима на достъп са помощна информация.

Сега за архитектурата - варианти бол - с блокиращи или неблокиращи сокети, всичко в една нишка, със select/poll/epoll и прочие или в отделни нишки. Няма универсално решение това, epoll например е нещо което много лесно се оплесква и е тотален overkill ако ще посрещаш рядко и малко връзки. Дори в обратния случай става проблем сам за себе си защото в един момент процесорното време ще ти стане bottleneck-а, а хардуера е многоядрен и е срамота да не му утилизираш ядрата.

Специално в конкретния случай (без да знам какъв ти е специално use-case-а) аз бих го реализирал с отделна нишка за watchdog-а и бих ползвал неблокиращи сокети и някакъв прост polling (select примерно) за worker-ите като начало. Дори съвсем като начало бих го правил с блокиращи сокети щото е далеч по-лесно, после ще го мъча с неблокиращи защото там драмите винаги се случват и никога не се случва от първия път и си пада дебъгване. Но watchdog-а в отделна нишка при всички положения, иначе ще трябва да се вкарва някаква логика да се третира специално watchdog сокета най-малкото, което е досадно.

Това мнение е било редактирано от gat3way на 28-08-2017, 16:39
PMEmail Poster
Top
ivelinqnev
Публикувано на: 28-08-2017, 16:54
Quote Post



Име:
Група: Потребител
Ранг: Старо куче

Мнения: 611
Регистриран на: 02.12.08



Цялото това нещо ми трябва, за да тествам. use-case-а ми е един socket server, който да слуша постоянно на два порта. Аз го направих и работи, като си пускам две нишки, в които всяка една отваря порт и слуша за входящи съобщения. Кода сигурно е грозен, но работи. Ако имате някакви идеи, как да го подобря ще съм благодарен icon_smile.gif
CODE
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>

void *messages_handler();
void *healthcheck_handler();



int main(int argc, char *argv[]) {

 pthread_t messages_thread, healthcheck_thread;

 if (pthread_create(&messages_thread, NULL, messages_handler, NULL) < 0) {
   perror("could not create thread");
   return 1;
 }

 if (pthread_create(&healthcheck_thread, NULL, healthcheck_handler, NULL)
     < 0) {
   perror("could not create thread");
   return 1;
 }

 while (1) {

 }

 return 0;
}

void *healthcheck_handler() {
 struct sockaddr_in server_healthcheck;
 int sock;

 //Create socket
 sock = socket(AF_INET, SOCK_STREAM, 0);
     if (sock == -1) {
       printf("Could not create socket");
     }
     puts("Socket messages created");

 server_healthcheck.sin_family = AF_INET;
 server_healthcheck.sin_addr.s_addr = INADDR_ANY;
 server_healthcheck.sin_port = htons(7300);
 //Bind
   if (bind(sock, (struct sockaddr *) &server_healthcheck, sizeof(server_healthcheck)) < 0) {
     //print the error message
     perror("bind failed 2. Error");
    // return 1;
   }
   puts("bind done");


 puts("healthcheck_handler");
   //Get the socket descriptor
   int client_sock, c, read_size;
   struct sockaddr_in client;
   char client_message[1024];

   //Listen
   listen(sock, 3);

   c = sizeof(struct sockaddr_in);
   while (1) {
     puts("Waiting for incoming connections... healthcheck_handler");
        client_sock = accept(sock, (struct sockaddr *) &client, (socklen_t*) &c);
        if (client_sock < 0) {
          puts("accept failed healthcheck_handler");
         // return 1;
        }
       //Receive a reply from the server
       if (recv(client_sock, client_message, 1024, 0) < 0) {
         puts("recv failed healthcheck_handler");
         break;
       }
       puts("\n healthcheck_handler: ");
         puts(client_message);
         puts("\n healthcheck_handler");

     }
   return 0;
}

void *messages_handler() {
 struct sockaddr_in server_messages;
 struct sockaddr_in client;
 int socket_messages;

 //Create socket
 socket_messages = socket(AF_INET, SOCK_STREAM, 0);
 if (socket_messages == -1) {
   printf("Could not create socket");
 }
 puts("Socket messages created");

 //Prepare the sockaddr_in structure
 server_messages.sin_family = AF_INET;
 server_messages.sin_addr.s_addr = INADDR_ANY;
 server_messages.sin_port = htons(7301);

 //Bind
 if (bind(socket_messages, (struct sockaddr *) &server_messages,
          sizeof(server_messages)) < 0) {
   //print the error message
   perror("bind failed 1. Error");
   //  return 1;
 }
 puts("bind done");
 //Get the socket descriptor
 int client_sock, c, read_size;
 char client_message[1024];

 //Listen
 listen(socket_messages, 3);

 c = sizeof(struct sockaddr_in);

 //Receive a message from client
 while(1) {

   puts("Waiting for incoming connections...");
     client_sock = accept(socket_messages, (struct sockaddr *) &client,
                          (socklen_t*) &c);
     if (client_sock < 0) {
       puts("accept failed");
       // return 1;
     }
     puts("Connection accepted");

   if(recv(client_sock , client_message , 2000 , 0) <0) {
       puts("recv failed");
                  break;
     }
     puts("Server reply :");
           puts(client_message);
           close(client_sock);
    }


 return 0;
}
PMEmail Poster
Top
gat3way
Публикувано на: 28-08-2017, 16:59
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 1539
Регистриран на: 22.06.12



Значи в момента пия гадна гръцка бира в хотела и ужасно ме мързи да гледам код. Направо кажи какъв точно проблем има и какво те притеснява, може да помогна icon_smile.gif
PMEmail Poster
Top
ivelinqnev
Публикувано на: 28-08-2017, 17:06
Quote Post



Име:
Група: Потребител
Ранг: Старо куче

Мнения: 611
Регистриран на: 02.12.08



QUOTE (gat3way @ 28-08-2017, 16:59)
Значи в момента пия гадна гръцка бира в хотела и ужасно ме мързи да гледам код. Направо кажи какъв точно проблем има и какво те притеснява, може да помогна icon_smile.gif

Притесняваме това, че варианта с две нишки за всеки порт е прекалено много код. Но този варианта е по- лесен. И дали е по ОК да имам някакъв timeout във всяка нишка- отколкото while(1) {....}
PMEmail Poster
Top
gat3way
Публикувано на: 28-08-2017, 17:12
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 1539
Регистриран на: 22.06.12



Една нишка за порт би трябвало да е напълно достатъчна. На порта на който се върши работа може да мултиплексираш нещата с некакъв polling механизъм, а watchdog-а може дърварската с неблокиращ сокет така серийно да си accept-ваш и обработваш връзките, за там няма нужда от сложните работи.
PMEmail Poster
Top
1 потребители преглеждат тази тема в момента (1 гости, 0 анонимни потребители)
Потребители, преглеждащи темата в момента:

Topic Options Страници: (2) [1] 2  Reply to this topicStart new topicStart Poll

 


Copyright © 2003-2015 | BG Development | All Rights Reserved
RSS 2.0