LINUX.ORG.RU

Почему программа выключается?

 


0

2

теперь программа работает.

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>

int socket_goodgame;
struct sockaddr_in parameter_of_server;
struct hostent *info_of_server;
char request [ 255 ];
char *status;
char *viewers;
char *users_in_chat;
char *games;

void configure_parameters_of_server ( )
{
	parameter_of_server.sin_family = PF_INET;
	memcpy ( &parameter_of_server.sin_addr, info_of_server->h_addr_list[0], 4 );
//	parameter_of_server.sin_addr.s_addr = *((unsigned long*) info_of_server->h_addr_list[0]);
	parameter_of_server.sin_port = htons ( 80 );
}
void connect_to_goodgame ( )
{
	info_of_server = gethostbyname ( "goodgame.ru" );

	configure_parameters_of_server ( );

	socket_goodgame = socket ( PF_INET, SOCK_STREAM, 0 );

	int ret;
	ret = connect ( 
			socket_goodgame, 
			( struct sockaddr *) &parameter_of_server, 
			sizeof ( struct sockaddr )
			);
	if ( ret == -1 ) {
		perror ( "connect" );
	}
}

void end_connection ( )
{
	close ( socket_goodgame );
}

void build_subscribes ( )
{
	memset ( request, 0, 255 );
	sprintf ( request,
			"GET http://goodgame.ru/api/getchannelstatus?id=xener HTTP/1.0\n"
			"User-Agent: gd/0.1 (naidv88@gmail.com)\n"
			"Accept: */*\n\n" );
}

char *find_argument ( char *value, char *buffer )
{

	char *position_in_buffer = buffer;
	for ( ; position_in_buffer != NULL; position_in_buffer++ ) {
		if ( !strncmp ( value, position_in_buffer, strlen ( value ) ) ) {
			position_in_buffer += strlen ( value ) + 1;

			char *length_argument = position_in_buffer;
			for ( int i = 0; ; i++ ) {
				if ( *length_argument == '<' ) {
					char *argument = calloc ( i + 1, 1 );
					char *position_in_argument = argument;
					for ( ; i > 0; i-- ) {
						*position_in_argument = *position_in_buffer;
						position_in_argument++;
						position_in_buffer++;
					}

					return argument;
				}
				length_argument++;
			}
		}
	}

	return NULL;
}

int any_argument_is_null ( )
{
	if ( games == NULL || status == NULL || viewers == NULL || users_in_chat == NULL ) {
		if ( games ) free ( games );
		if ( status ) free ( status );
		if ( viewers ) free ( viewers );
		if ( users_in_chat ) free ( users_in_chat );
		return 1;
	} 
	return 0;
}

void print_arguments ( )
{
	clear ( );
	mvprintw ( 0, 1, "gd v. 0.1" );
	mvhline ( 1, 0, '_', 80 );
	mvprintw ( 2, 1, "game: %s", games );
	mvprintw ( 3, 1, "status: %s", status );
	mvprintw ( 4, 1, "viewers: %s", viewers );
	mvprintw ( 5, 1, "users: %s", users_in_chat );
	mvaddch ( 6, 0, ' ' );
	refresh ( );

	free ( games );
	free ( status );
	free ( viewers );
	free ( users_in_chat );
}

void get_arguments ( char *buffer )
{
	status = find_argument ( "status", buffer );
	viewers = find_argument ( "viewers", buffer );
	users_in_chat = find_argument ( "usersinchat", buffer );
	games = find_argument ( "games", buffer );
}
void parse_answer_from_server ( char *buffer )
{
	get_arguments ( buffer );

	if ( any_argument_is_null ( ) ) {
		return;
	}

	print_arguments ( );


}

void get_information ( )
{

	if ( send ( socket_goodgame, request, strlen ( request ), MSG_NOSIGNAL ) == -1 ) {
		perror ( "send" );
	}

	char buf[4096];

	int ret;
	ret = read ( socket_goodgame, buf, 4096 );
	if ( ret == 0 ) return;
	parse_answer_from_server ( &buf[0] );

}

void curses_init ( )
{
	initscr ( );
	cbreak ( );
	noecho ( );
	keypad ( stdscr, FALSE );

}
void end_program ( int sig )
{
	endwin ( );
	exit ( EXIT_SUCCESS );
}
void signals_init ( )
{
	signal ( SIGINT, end_program );
}

int main ( int argc, char *argv[] )
{
	signals_init ( );
	curses_init ( );
	build_subscribes ( );

	while ( 1 ) {
		connect_to_goodgame ( );
		get_information ( );
		end_connection ( );
		sleep ( 1 );
	}

}


Угадал нейросеть не открывая тред.

a1batross ★★★★★ ()

Что вылетает из программы?

anonymous ()

Пробки проверь.

mos ★★☆☆☆ ()

завершиться

Ну ладно в Сишку не смог, но русский-то кто за тебя выучит?

anonymous ()

Магические константы, арифметика указателей, отсутствие проверки валидности входных данных. Мой говнокодомер упёрся в ограничитель. Мне влом проверять find_argument, для ошибок там просто непаханая поляна, просто намекну, что она может вернуть NULL и sprintf'у это не понравится.

redgremlin ★★★★★ ()

скраперы (а уж парсеры и подавно) лучше на чем-то более высокоуровневом, динамическом писать, для писюнчика например есть и тулкиты готовые scraPy или удобные обертки (https://bitbucket.org/lorien/grab/src/8bc44ba39bf7?at=default)

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

твоя программа на 99/100 будет состоять из костыляния управления ресурсами и хоф-примитивов которые в нормальных языках в ядре заложены

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

я делал проверку на ошибки, только в этом примере нет. Все также.

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

Тогда gdb в зубы и вперёд. Разбираться в твоём говнокоде нет ни малейшего желания. Вот найдёшь в gdb точное место ошибки, возвращайся.

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

Разбираться в твоём говнокоде нет ни малейшего желания

Раз так, то твои сообщения как пустой разговор. Я тебя блокирую.

u0atgKIRznY5 ()

Возвращает

Program received signal SIGPIPE, Broken pipe.
0x00007ffff7b1758d in send () from /usr/lib/libc.so.6

u0atgKIRznY5 ()

В общем видимо send генерирует сигнал sigpipe, как написано в man. Это может быть от того, что сокет был закрыт. Значит сервер закрыл соединение наверное. Буду заного сокет открывать и все.

u0atgKIRznY5 ()

Легче уже самому разобраться чем ждать от кого то помощи. Ненравиться помогать, так не пиши.

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

в долгоиграющих программах всегда надо делать ретрай (причем с эксп/ таймаутом) и не расчитывать на вечность «ио» ресурсов, особенно сетевых, либо пул либо корутина либо открывать соединение в каждой итерации (и не забыть трай-кетчить и повторно вызывать):

def grab(url, timeout=.1):
  try:
    return fetch(url)
  except IOException:
    return grab(url, timeout + timeout)

такой логике

anonymous ()

Даже не могут понять в чем дело, а считают себя умными.

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

Ненравиться помогать, так не пиши.

Но ты же пишешь.

i-rinat ★★★★★ ()

программа завершиться

Я скоро не выдержу и начну ругаться матом, чистым русским матом! Откуда ж вы все только берётесь...

сработает один раз цикл

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

Магические константы, арифметика указателей, отсутствие проверки валидности входных данных. Мой говнокодомер упёрся в ограничитель. Мне влом проверять find_argument, для ошибок там просто непаханая поляна, просто намекну, что она может вернуть NULL и sprintf'у это не понравится.

Вот найдёшь в gdb точное место ошибки, возвращайся.

Инкрементирую стократно. От себя добавлю про море хардкода, хрен-пойми какое управление памятью, отсутствие читабельности и комментариев, куча кода сошкрябанного по углам stackoverflow и глубин гугла, бесполезная функция end_connection.

Если твой препод по проге читает этот тред, то надеюсь, что сессию ты не сдашь.

P.S.: остальным извините - накипело незнание основ русского языка. Или хотя бы родного языка, если русский - не родной. Или на худой конец симпл инглиша.

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

От себя добавлю про море хардкода, хрен-пойми какое управление памятью, отсутствие читабельности и комментариев, куча кода сошкрябанного по углам stackoverflow и глубин гугла, бесполезная функция end_connection.

Названия функций говорят сами за себя, здесь комментарии излишне. Почитал немного книгу «чистый код. рефакторинг», взял от туда некоторые идеи. Да может комментариев нет, но тебе разве обязательно вчитываться в функцию find_argument, даже если комментарий там не поможет. Если бы ты был опытный, то мог бы предположить в чем может быть проблема. А так понятно что опыта у тебя никакого нет.

u0atgKIRznY5 ()
Ответ на: комментарий от i-rinat

Но ты же пишешь.

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

u0atgKIRznY5 ()

Весь код ниасилил, да и не разбираюсь я в си, но

и программа завершиться.

Но после этого места хочу развидеть обратно.

burato ★★★ ()

В функции get_information :

parse_answer_from_server ( &buf[0] );

Зачем? buf сам по себе указатель на начало массива. Можно просто передать buf в качестве аргумента.

В функции parse_answer_from_server:

Если хоть один из указателей на «аргументы» равен нулю (т.е. вы не нашли такой «аргумент» при парсинге) вы очищаете память у всех «аргументов», а потом безусловно пихаете в sprintf строки по невалидном указателям. Если вам повезет и прога тут не упадет с сегфолтом, то она тут же упадет с double free, т.к. вы потом (опять же бузесловно) очищаете память под «аргументы», даже если уже очистили ее до.

Кроме того, в функции get_information вы проверяете что ваш answer не NULL, однако таковым он окажется только если память не будет выделена в parse_answer_from_server, но тогда вы тут же сегфолтнетесь на memset.

RiseOfDeath ★★★★ ()
Последнее исправление: RiseOfDeath (всего исправлений: 3)
Ответ на: комментарий от aido

Инкрементирую стократно.

Ты не в правильном направлении мыслишь. Если будет segfault, то ошибка появиться в консоли после запуска программы. Так как ее нет, значит проблема в другом. В чем может быть еще проблема? Да и хватило бы ваших мозгов, чтобы понять? Моих хватило. Я доходчиво код написал. Да и вообще что я тут объясняю, кому? Ты врядли поймешь, что какую я ошибку нашел, потому что когда ты заходил в этот тред, ты думал не о том как помочь, а тебе хотелось пообщаться.

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

Если хоть один из указателей на «аргументы» равен нулю

Ну да, я это уже заметил и исправил в основном коде, здесь только обновления не сделал, щас обновлю код.

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

вы очищаете память у всех «аргументов», а потом безусловно пихаете в sprintf строки по невалидном указателям

Это он так решил отреагировать на замечание про проверку аргументов, вчера этого куска кода ещё не было. А вот return добавить забыл.

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

К стати, а вы уверены что вам что-то приходит в ответ? Посмотрите ваершарком.

upd.

Скорее всего вы увидите что там придет ответ, но ваша прога все равно ничего не напечатает. Дело в том, что в get_information вы отправили запрос и тут же читаете ответ, которого еще может и не быть (а его 100% не будет, ибо в реальности существует куча «задержек», особенно если сей сайт реально где-то в интернетах, а не у вас на локальной машине). Пока чисто для теста добавте между отправкой и чтением sleep на секундочку (обращаю внимание, что вообще так не делают, но чтобы убедиться что вы просто сликшом рано читаете ответ сойдет). Потом я бы советовал вам запилить нормальную асинхронную обработку вместо порнографии со слипом (ну или если вам влом так делать, просто пытайтесь читать пока не прочитаете что-нибудь или пока соединение не будет закрыто на той стороне + какой-то таймаут на всякий случай).

RiseOfDeath ★★★★ ()
Последнее исправление: RiseOfDeath (всего исправлений: 8)
Ответ на: комментарий от u0atgKIRznY5

потому что когда ты заходил в этот тред, ты думал не о том как помочь, а тебе хотелось пообщаться

Троллеустойчивость, божественный дар, снизошедший на просвещённого ЛОРо-фага. Лишь избранный ЛОР-овец выдержит священные испытания от безызвестного анонимуса.

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

добавте между отправкой и чтением sleep на секундочку

Вообще то, если не настраивать socket_goodgame, то read будет как блокирующий вызов, тоесть будет ждать поступления данных. Так что в этом случае все нормально.

просто пытайтесь читать пока не прочитаете что-нибудь или пока соединение не будет закрыто на той стороне + какой-то таймаут на всякий случай).

После того как сервер отправляет мне xml данные, он закрывает соединение. Потом происходит sleep и запрос отправляется заного.

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

Скорее всего вы увидите что там придет ответ, но ваша прога все равно ничего не напечатает

А зависнет. Потому что for ( ; value != NULL; position_in_buffer++ ) — если подстрока не найдётся, то конопатить он будет долго.

вы отправили запрос и тут же читаете ответ, которого еще может и не быть

Даже если и будет, он всё равно зависнет на любом ответе, кроме 200/ОК с иксемелькой установленного формата.

Потом я бы советовал вам запилить нормальную асинхронную обработку

Окстись, ему половину этой программы надо перепилить, чтоб вообще заработало

P.S. Ну и вишенка на торте:

После того как сервер отправляет мне xml данные, он закрывает соединение

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

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

value != NULL

Это пять. Я с ходу и не заметил.

upd.

Хотя, если автор школьник, как я понял из сообщения анонимуса, то все не так уж и плохо.

RiseOfDeath ★★★★ ()
Последнее исправление: RiseOfDeath (всего исправлений: 3)

странно, но ошибки небыло когда я написал any_argument_is_null вместо any_argument_is_null ( ).

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

А зависнет. Потому что for ( ; value != NULL; position_in_buffer++ ) — если подстрока не найдётся, то конопатить он будет долго.

Молодец. А я забыл полностью эту ошибку исправить с value. Я там понаписывал и потом заметил что value использовал, а надо было другое. Что исправил но не все. Надо будет это учитывать и проверять дотошнее.

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

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

Только об этом до меня никто не догадался.

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

Окстись, ему половину этой программы надо перепилить, чтоб вообще заработало

Все работает, не преувеличивай.

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

Названия функций говорят сами за себя, здесь комментарии излишне

void get_information ( )

Очень понятно

Aswed ★★★★★ ()

Вижу, начал разбивать по функциям. Молодец. Сразу замечу, что стоит сделать ещё несколько шагов: избавиться от глобальных переменных (тут они тебе не нужны) и сделать так, чтобы функции хоть что-то возвращали. В Си void нужен не так уж и часто. Например, и connect_to_goodgame(), и build_subscribes(), и get_information(), если судить по их именам, могут завершиться неудачно, а у тебя это никак не обрабатывается. Лишь внутри функций есть диагностические сообщения, хотя им там не место — вынеси их в точку вызова и там уже обрабатывай код ошибки и errno.

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

Если честно, меня терзают смутные сомнения насчёт того, как ты используешь connect(). Мне довольно редко приходится иметь дело с сетевыми функциями, поэтому допускаю, что я чего-то не помню/не знаю, но я очень не уверен по поводу третьего аргумента. Вот, к примеру, моя функция подключения из одного рабочего проекта, практически целиком скопированная из мана по getaddrinfo (убрал обработку ошибок, чтобы не отвлекало):

int getConnection(config_t *config)
  {
	struct addrinfo hints, *addrinfo, *rp;
	int fd = -1;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family   = AF_UNSPEC;  /* IPv4 and IPv6 allowed */
	hints.ai_socktype = SOCK_DGRAM; /* Datagramm socket      */
	hints.ai_flags    = AI_PASSIVE; /* For wildcard address  */

	if (getaddrinfo(config->serv_addr, config->serv_port, &hints, &addrinfo) != 0)
	  {
		if (!config->daemonize)
			{…} /* Error handling for daemon mode */
		else {…};   /* Error handling for single run*/
		return -1;
	  }

	for (rp = addrinfo; rp != NULL; rp = rp->ai_next)
	  {
		if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1)
			continue;

		if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */

		close(fd);
	  }

	freeaddrinfo(addrinfo);
	return fd;
  }

Как видишь, в connect() нет никаких sizeof. И даже если в результате получается одно и то же, поле структуры более правильно с точки зрения логики. Ну и проверка ошибок, чего у тебя нет.

То же самое касаемо функции get_information: ты не проверяешь результат send(), а ответ проверяешь только в том смысле, что он есть, но не проверяешь, сколько именно и что именно тебе пришло. По-хорошему, для парсинга у тебя должен быть конечный автомат, и покуда он находится в состоянии «неполный запрос», ты должен продолжать чтение. А сейчас получается, что если после отправки команды тебе придёт кусок ответа, ты его скормишь парсеру, он, разумеется, обломится, очистит память, потом ещё раз очистит и упадёт. Или, если вдруг не упадёт, вернёт тебе непонятно что. Потом придёт ещё один кусок ответа, но ты об этом не узнаешь. Зато ты проверяешь результат парсера на NULL, хотя он его тебе не возвращает.

Про костыль вместо strncpy молчу, это несущественно

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

Блин, что ты делаешь? Так он минимальный нерабочий пример ни разу в жизни не напишет.

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

Судя по отметке темы как «решённая», минимального примера мы не увидим в любом случае. Да и у него код обычно такой, что проблем там просто море, достаточно посмотреть по истории редактирования ОП-поста

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