C :: Threads непоследовательно открывает отправляющий сокет - PullRequest
0 голосов
/ 18 сентября 2019

Я создаю программу на C и борюсь со странной - и непоследовательной - ошибкой потока и сокета с gethostbyname(), которую я никогда раньше не видел.

Сначала кое-что из среды: я 'Я работаю над коробкой Ubuntu, и мой код скомпилирован с GCC:

root@ubuntu:/home/me/socketProject# gcc -v
...
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
root@ubuntu:/home/me/socketProject#

Цель здесь: я разработал еще одну программу на C, которая когда-нибудь станет сетевым сервисом, я надеюсь.Сервер работает нормально, но мне нужно провести стресс-тестирование.Итак, я создал клиентскую программу для бомбардировки имитируемыми сетевыми запросами.Когда сервер подключен и прослушивает TCP 12345, клиентской программе нужно всего лишь сделать следующее:

  • Для N раз разверните отдельный рабочий поток
    • Каждый поток должен открытьсяотправляющий сокет, затем отправьте некоторые данные на 127.0.0.1 через TCP 12345
    • После отправки поток должен немедленно прекратить

Это должно быть детской игрой,Я хочу использовать большое число N, чтобы увидеть, что происходит, когда мой сервер взломан.

Позвольте мне пройтись по моему коду и описать проблему.Программа относительно проста.Есть несколько структур, а затем main().По сути, main() зацикливается на N = numThreads, каждый раз создавая отдельный рабочий поток.Каждому потоку дается заполненная структура package, с информацией, которую он будет использовать позже:

typedef struct{
   int sock;
   struct sockaddr address;
   int addr_len;
} connection_t;

typedef struct{
   char* IP;
   int port, myNum;
} package;


void process(void* pack);                  // code for the thread, see below...


int main( int argc, char ** argv ){
   pthread_t  thread;
   int        numThreads = 10;             // or 100 or 1000 or whatever
   char       svrIP[20] = "127.0.0.1";
   int        portNumber = 12345;

   int i=0;
   for( ; i<numThreads; i++){

      package* pack   = (package*) malloc( sizeof(package) );
      pack->IP        = (char*) malloc( sizeof(char) * 20 );
      strcpy( pack->IP, svrIP );
      pack->port      = portNumber;
      pack->myNum     = i;

      pthread_create(&thread, NULL, process, (void*) pack);
      pthread_detach(thread);

      free( pack->IP );
      free( pack );
   }

   sleep(1);

   printf("END OF PROGRAM\n");
   return 0;
}

Все выше работает отлично, независимо от того, что я установил для numThreads.Теперь для кода потока.После рождения поток пытается открыть сокет, а затем отправить текстовую строку.Тогда поток заканчивается.Обратите внимание на все, что fprintf() код около gethostbyname() - я буду ссылаться на него позже:

void process(void* pack){
   int                  len, sock = -1;
   struct sockaddr_in   address;
   struct hostent *     host;

   char* msg = "Some text string here for the server...";

   printf("THREAD %d STARTED:  %s  --  %d\n", ((package*)pack)->myNum, ((package*)pack)->IP, ((package*)pack)->port );

   // create the socket
   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (sock <= 0){
      fprintf( stderr, "Thread %d: error: cannot create socket\n", ((package*)pack)->myNum );
      pthread_exit(0);
   }

   // connect to server
   address.sin_family = AF_INET;
   address.sin_port = htons( ((package*)pack)->port );
   host = gethostbyname( ((package*)pack)->IP );
   if (!host){
      fprintf( stderr, "Thread %d: error: unknown host %s  --  Error is:  (%d) \”%s\”\n",
            ((package*)pack)->myNum,
            ((package*)pack)->IP,
            errno, strerror(errno));
      pthread_exit(0);
   }

   memcpy(&address.sin_addr, host->h_addr_list[0], host->h_length);
   if (connect(sock, (struct sockaddr *)&address, sizeof(address))){
      fprintf( stderr, "Thread %d: error: cannot connect to host %s\n", ((package*)pack)->myNum, ((package*)pack)->IP );
      pthread_exit(0);
   }

   printf("Thread %d: Sending message \”%s\”\n", ((package*)pack)->myNum, msg);

   len = strlen(msg);
   write(sock, &len, sizeof(int));
   write(sock, msg, len);

   printf("Thread %d: message sent, exiting...\n", ((package*)pack)->myNum );

   close(sock);

   pthread_exit(0);
}

Хорошо, это код.Итак, вот проблема:

Независимо от того, какое значение я установил для numThreads, некоторые рабочие потоки успешно открывают сокет, а некоторые нет.Те, кто терпит неудачу, терпят неудачу в этом вызове gethostbyname().Проверьте ниже;Я установил numThreads в 10, что означает, что я должен видеть запуск потоков с 0 по 9:

me@ubuntu:/home/me/socketProject# ./runTest
THREAD 2 STARTED:  127.0.0.1  --  24601
THREAD 5 STARTED:  127.0.0.1  --  24601
THREAD 3 STARTED:  127.0.0.1  --  24601
THREAD 3 STARTED:  127.0.0.1  --  24601
THREAD 4 STARTED:  127.0.0.1  --  24601
THREAD 7 STARTED:  127.0.0.1  --  24601
Thread 7: Sending message "Some text string here for the server..."
Thread 7: message sent, exiting...
THREAD 7 STARTED:  127.0.0.1  --  24601
Thread 7: Sending message "Some text string here for the server..."
Thread 7: message sent, exiting...
THREAD 8 STARTED:  127.0.0.1  --  24601
Thread 8: Sending message "Some text string here for the server..."
Thread 8: message sent, exiting...
THREAD 9 STARTED:    --  24601
THREAD 9 STARTED:    --  24601
Thread 9: Sending message "Some text string here for the server..."
Thread 9: message sent, exiting...
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
END OF PROGRAM
me@ubuntu:/home/me/socketProject#

Сервер получил четыре тестовых сообщения, как показано в приведенном выше выводе.

Оооооооооо ... здесь происходит много странностей.Должна быть какая-то ошибка с этими сообщениями « THREAD X STARTED », потому что похоже, что потоки 0, 1 и 6 никогда не запускаются, а потоки 3, 7 и 9 почему-то запускаются дважды.Но numThreads == 10 и десять потоков запущены, поэтому я пока проигнорирую эту проблему.

Больше беспокойства вызывает то, что шесть потоков не смогли вызвать gethostbyname().Я признаю: для этого куска кода я скопировал пример из учебника, и я не могу вспомнить, где я его получил.Но мне интересно, имеет ли смысл это заявление if(!host).Когда я провел бета-тестирование в не поточной версии, проблем не было, но теперь…

Еще более странно то, что код Errno - «Успех».Если он успешен ... почему не удается позвонить?Я чувствую, что упускаю что-то действительно очень очевидное.

Меня также беспокоит, что эта проблема противоречива.Иногда, когда я проверяю это, 7/10 потоков успешно отправляют.Иногда 1/10 делаю.Мой средний показатель успеха составляет около 3/10.Если я что-то узнал о C, то, что противоречивые проблемы обычно указывают на то, что переменные были успешно созданы, но не инициализированы.Что может потребоваться инициализировать здесь?host структура?Я не уверен.

Я уже три часа гуглю это, но ничего полезного не извлекаю.Любые предложения или советы будут безумно приветствоваться.

1 Ответ

1 голос
/ 19 сентября 2019

Проблема здесь:

  pthread_create(&thread, NULL, process, (void*) pack);
  pthread_detach(thread);

  free( pack->IP );
  free( pack );

... вы создаете ресурс, специфичный для нового потока (pack), а затем немедленно удаляете его, прежде чем поток завершит свою работу!Эти бесплатные звонки должны быть выполнены в конце process

...