Я создаю программу на 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
структура?Я не уверен.
Я уже три часа гуглю это, но ничего полезного не извлекаю.Любые предложения или советы будут безумно приветствоваться.