LINUX.ORG.RU

Клиент-сервер TCP и несколько потоков.

 ,


0

1

Есть TCP клиент, к коду которого не имею доступ, и есть TCP сервер, мною написанный. Клиент отлично подключается к серверу, теперь серверу надо отослать(send()) клиенту некую информацию. Вопрос таков: допустим я открываю на сервере слушающий TCP сокет в одном потоке, и устанавливаю связь(accept()) в этом же потоке, а отсылать информацию буду в другом. Может такое сработать или другой поток будет иметь другой набор дескрипторов и ничего не получится? И если ответ на первый вопрос отрицательный, то почему всё же при отправке(send()) из другого потока функция send не вернёт ошибку?

Я уже такое провернул, и клиент ничего не получил, а если посылаю из того же потока, то клиент получает. Самое интересное то, что в обоих случаях я отлавливаю пакет с помощью tcpdump, и они оба содержат правильный адрес получателя. Ещё один вопрос: почему всё же не доходит, даже с правильным адресом?

От потока не зависит.

Вопрос, а как этот второй поток (send()) синхронизирован с первым, который accept()? Если send() вызывается сразу после accept(), то в одном потоке это и будет так, а если send() в другом потоке, то он точно вызывается после accept()? Блокировка по мьютексу?

gag ★★★★★ ()

Вопрос таков: допустим я открываю на сервере слушающий TCP сокет в одном потоке, и устанавливаю связь(accept()) в этом же потоке, а отсылать информацию буду в другом. Может такое сработать или другой поток будет иметь другой набор дескрипторов и ничего не получится?

У потоков все общее: и память, и дескрипторы. accept и send/recv в разных потоках — обычная практика.

Я уже такое провернул, и клиент ничего не получил, а если посылаю из того же потока, то клиент получает.

Ты что-то делаешь неправильно. Последовательность accept -> pthread_create -> send в свежесозданном потоке будет абсолютно корректно работать.

red_eyed_peguin ()
Ответ на: комментарий от Dennis7
__attribute__((noreturn)) void *terminal_receive_thread(void *arg)
{
	for(;;) {
		sd = accept(listen_sd, 0, 0);
		if (sd == -1) {
			warn("accept error");
			thread_exit((const int) arg);
		}

		pthread_mutex_unlock(&send_mutex);
/*
		ret = send(sd,
			   "odin dva",
			   strlen("odin dva"),
			   0
		      );
		if (ret == -1) {
			warn("send error");
			goto out;
		}
*/

		sleep(100);

		ret = recv(sd,
			   buffers.terminal_recv,
			   MAX_RECV_LEN,
			   0
			  );
		if (ret == -1) {
			warn("recv error");
			goto out;
		}
	
		pthread_mutex_lock(&send_mutex);

		ret = shutdown(sd, SHUT_RDWR);
		if (ret == -1) {
			warn("shutdown error");
			goto out;
		}
		close(sd);
	}
			
out:
	close(sd);
	thread_exit((const int) arg);
}

__attribute__((noreturn)) void *terminal_send_thread(void *arg)
{
	for(;;) {
		pthread_mutex_lock(&send_mutex);
		
		ret = send(sd,
			   "odin dva",
			   strlen("odin dva"),
			   0
			  );
		if (ret == -1) {
			warn("send error");
			goto out;
		}

		pthread_mutex_unlock(&send_mutex);

/*
...
*/
	}
out:
	thread_exit((const int) arg);
}

вот код двух потоков. если использовать только terminal_receive_thread и в нём раскоментировать функцию send(), то всё работает

elbondyto ()
Ответ на: комментарий от red_eyed_peguin

Так оно и работает, я tcpdump-ом отлавливаю пакеты с правильным адресом, но они не доходят. Может есть у клиента какая-нибудь проверка на идентификатор процесса отправителя?

elbondyto ()
Ответ на: комментарий от gag

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

elbondyto ()
Ответ на: комментарий от elbondyto

Странная работа с мьютексами.
Может быть я код посмотрел слишком бегло, но кто блокирует mutex до входа в поток terminal_send_thread?

trex6 ★★★★★ ()
Ответ на: комментарий от elbondyto

Могу порекомендовать выставить слипы и принтэфы до и после accept и send, чтобы убедиться, что они отрабатывают в правильном порядке.

trex6 ★★★★★ ()
Ответ на: комментарий от elbondyto

Заголовки IP пакета и TCP сегмента не содержат pid

anonymous ()
Ответ на: комментарий от elbondyto

если сам руками и telnet`ом подключаешься - всё правильно отрабатывает ?

MKuznetsov ★★★★★ ()

tcp-стек в ядре, а не в программе/библиотеке. Если tcpdump показывет пакет с правильными ip-адресами/портами, значит он из нужного tcp-соединения с правильными полями заголовка и он будет принят клиентом.

Клиента ведь можно попробовать ведь запустить в режиме трассировки и посмотреть, доходят ли до него данные. Возможно, что send() из другого потока срабатывает через больший промежуток времени и клиент уже отваливается по тайм-ауту.

mky ★★★★★ ()

Здесь http://isl.storozhilov.com/ можно качнуть С++ библиотеку (ISL - Internet Server Library), которая позволит реализовать требуемое сильно не погружаясь в детали межпоточной синхронизации. Сделай своего наследника класса isl::AbstractSyncTcpService, в котором переопредели фабричный метод isl::AbstractSyncTcpService::createTask(), возвращающий указатель на экземпляр разработанного тобой же наследника класса isl::AbstractSyncTcpService::AbstractTask с переопределенным методом isl::AbstractSyncTcpService::AbstractTask::execute(), собственно и производящим отправку данных клиенту по сокету.

illy ()
Ответ на: комментарий от illy

спасибо) я уже разобрался, сам налажал с синхронизацией(( только шухер на форуме поднял

elbondyto ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.