LINUX.ORG.RU

сваливается send (сокет)


0

0

Пишу клиент-сервер. В клиенте есть вызов send. Так вот примерно 1 из 10 запусков програмы, заканчивается тем, что прога вываливается при send. При этом нет никаких ошибок.

Вот часть кода клиента (некоторые переменные определены в классе):

void socket::send_data(char *data_)
{
	sd = socket( PF_INET, SOCK_STREAM, 0 );
	if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
	{
		perror("Connect ");
		exit(errno);
	}else{
		
		char data[2048];
	  	memcpy(data, data_, strlen(data_)+1);
		printf("before\n");
		if(send(sd, (char *)&data, 2048, 0) == -1){
			perror("Send ");
			exit(errno);
		}
		printf("after\n");
		close(sd);
	}
}

А вот что выводится в консоль при ошибке:

src $ ./client
before
...и всё...

Часть кода сервера:

void socket::recv_data()
{
	while(1){
		int client;
		socklen_t size = sizeof(addr);
		printf( "Waiting for connect...\n" );
		client = accept(sd, (struct sockaddr*)&addr, &size );
		printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
 		recv(client, &buffer, sizeof(buffer), 0);
 		printf( "data = %s\n", buffer );
		close(client);
	}

	close(sd);

}

У клиента и сервера данный класс (soсket) явлется потомком класса base_thread.

Вот он:

class base_thread {
	public :
		virtual ~base_thread() {}

		// Must be implemented by real client
		virtual void *init() = 0;

		int start() {
			int n = pthread_create(&pth_, 0, real_run, this);
			pthread_detach(pth_);
			return n;
		}

		pthread_t id() const {
			return pth_;
		}

	private :
		pthread_t pth_;
		static void * real_run(void *arg) {
  			base_thread *t = static_cast<base_thread *>(arg);
 			return t->init();
		}
};

Вот init() socket:

void *socket::init()
{
	addr_len = sizeof(addr);
	addr.sin_family = AF_INET;
	addr.sin_port = htons( port );
	inet_aton( host, &addr.sin_addr );
}

Есть ещё класс base:

...
tsocket = new socket(...);
socket->start();

base *obj = new base(..., tsocket);
obj->start();
...

Класс base, так же является потомком base_thread, вот его init():

void* base::init()
{
	int n = 0, r = 0, fd_log = 0;
	char *buf = new char[0];
	char *line = new char[1024];


	fd_log = open( path, O_RDONLY );
	if (fd_log < 0){
		printf("File %s not found!\n", path);
		return 0;
	}

	r = read(fd_log, &buf[0], 1);
	while(r > 0){
		while(buf[0] != '\n' && r > 0){
			r = read(fd_log, &buf[0], 1);
			line[n] = buf[0];
			n++;
		}
		r = read(fd_log, &buf[0], 1);
		line[n+1] = '\0';
		socket->send_data(line);
		n = 0;
	}
	close(fd_log);
}
★★★★★

Переполнение буфера может быть тут:

char data[2048];
memcpy(data, data_, strlen(data_)+1);

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

> c (char *)&data[0] и (char *)data теже яйца :(

valgrind --tool=memcheck --leak-check=full ./client ?

gdb?

stpg
()

Попробуй пойти методом последовательного приближения. То есть, сперва сделай всё на Си и без потоков, сделай на C++ без потоков, потом добавь потоки. Работы на 15 - 20 минут, но поможет лучше понять где проблема.

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

Попробовал убрать поток из класса socket, проблема отпала. 

Но возникает вопрос, почему socket не работает в потоке? 

Проблема, при использовании потока в сокете, как я понял в переменной 
data_ в функции send_data(char *data_). Если я проверяю в base::init()
длину strlen(line) то всё пучком, но если следом проверяю длину 
strlen(data_) в socket::send_data, то как раз на этом месте всё и 
сваливается.

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

Я с потоками не очень.. а как там форк делается? Может дело в том, что разные потори не имеют общей памяти или ещё что-то в этом роде? то что strlen валится говорит, скорее всего, о том, что ему передан указатель на неинициализированный кусок памяти. Если посмотреть на это вкупе с тем, что ты говорил, то получаем, что в init память ещё доступна, а вот в send_data уже нет.

lv ★★
()

cyclon, ну ты в своём репертуаре.

для начала, на надо брать адрес у массива, если хочешь передать его содержимое как указатель. То есть если есть "char buf []", то передаёшь его в send как "send (buf)", а не send (&buf). У тебя там не в одном месте так, особенно вопиющее - с recv(&buffer), то есть recv в явном виде перезапишет данные в твоей проге (ук-ль buffer и всё что после него). Полный венигрет. И при этом ты только кусочек кода показал. Если представить, что там ещё прячется от наших глаз, то неудивительно, что ничё не работает.

Чтобы ты не смущался, могу заверить, что всё, что ты пытаешься сделать, должно работать без проблем. Проблема (наверное, много проблем) в реализации.

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

> для начала, на надо брать адрес у массива, если хочешь передать его содержимое как указатель. То есть если есть "char buf []", то передаёшь его в send как "send (buf)", а не send (&buf). У тебя там не в одном месте так, особенно вопиющее - с recv(&buffer), то есть recv в явном виде перезапишет данные в твоей проге (ук-ль buffer и всё что после него). Полный венигрет. И при этом ты только кусочек кода показал. Если представить, что там ещё прячется от наших глаз, то неудивительно, что ничё не работает.

Аффигеть :) Я даже в код и не присматривался - а оно вон как :)

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

Да-да согласен...сто лет не писал, тут решил таким орбазом убить 
время... :))))) С этим вроде как разобрался.

Не сочтите за наглость но вопрос, ещё есть )) У меня делается connect
и close сокета в цикле. Но по выводу я наблюдаю что то ли сокеты не
закрываются, то ли ещё что:

Connected: 127.0.0.1:36515
...данные...
Waiting for connect...
Connected: 127.0.0.1:36516
...данные...
Waiting for connect...
Connected: 127.0.0.1:36517
...данные...
Waiting for connect...
Connected: 127.0.0.1:36518
...данные...
Waiting for connect...
Connected: 127.0.0.1:36519
...данные...

т.е. номера портов растут и под конец начинаются подтормаживания
вплоть до полной остановки, как будто заканчиваются свободные сокеты
и идёт ожидание их освобождения.

Можно ли как то делать send не закрывая сокет?

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

> Можно ли как то делать send не закрывая сокет?

Эмм.. сокет открывает сервер. Клиент _коннектится_ к сокету, а потом закрывает _файловый дескриптор_, использовавшийся для коннекта. Кажется как-то так..

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

> Можно ли как то делать send не закрывая сокет?

ну делай, что мешает?

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

> т.е. номера портов растут и под конец начинаются подтормаживания вплоть до полной остановки, как будто заканчиваются свободные сокеты и идёт ожидание их освобождения.

0. С портами будет всё нормально.

1. Используй netstat

2. google "socket TIME_WAIT"

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

lv, сокет - это такой тип файлового дескриптора, тот, который возвращает вызов socket(). Думаю, понятно, что в свете этого определения клиент не может "подключиться к сокету". Дальше разбирайся сам.

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

> 0. С портами будет всё нормально.
> 1. Используй netstat

> 2. google "socket TIME_WAIT"


Ппц не в тему. Товарищи, вы чего человека путаете? Он натурально открывает/закрывает соединение для _каждого_ вызова send(). То есть не понимает сути API сокетов вообще. В код-то посмотрите хотя бы.

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

Да и не хочу его закрывать, он сам отваливается, после передачи первой строки, и повторно его не получается использовать, только предварительно закрыв и открыв новый.

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

> lv, сокет - это такой тип файлового дескриптора, тот, который возвращает вызов socket(). Думаю, понятно, что в свете этого определения клиент не может "подключиться к сокету". Дальше разбирайся сам.

Хмм... я имел в виду, что socket() вызывает как клиент, так и сервер. И закрытие клиентом своего дескриптора серверу по барабану. На сколько я понял, топикстартер хочет каждый раз закрывать сокет сервера после приёма/передачи.. или как там у него всё сделано.. Про "подключиться к сокету" согласен - фигня. Имел в виду "установить канал связи".

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

> Да и не хочу его закрывать, он сам отваливается

cyclon, ладно, я больше на твои посты не буду отвечать. Помню ещё как ты модуль ядра пытался писать, спустя годы ничего не изменилось.

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

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

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