В общем это мультипроцессный сервер, призванный ретранслировать аудиопоток. Написал как попало, и оно немножко работает. Помогите разобраться в глюках.
Принцип работы: порождается клиентский процесс, соединяющийся с аудио каналом 128 кб/с и читающий оттудова данные без метаинформации и заносящий их в общий буфер;
затем, при подключении клиентов, им отдается содержимое этого буфера.Проще для себя способа синхронизации, чем изменение общей переменной, не нашел, возможно он глюкавый.
[gpk@localhost server]$ ./serv 10.25.250.1 / 8000 9988
Rebroadcastinf 128 kbps mp3 stream without metadata
listener 2: Invalid argument
[gpk@localhost server]$ op
op
op
opВозникает ошибка Invalid argument в родительском прцессе и он завершается, в то время, как порожденный клиент работает некоторое время, получая данные, но потом, все равно, отрубается.
server.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>#define SERVER_PORT 9999
#define LINE_SPEED 128const unsigned int BFFER_LEN = LINE_SPEED / 8 * 100
int main( int argc, char* argv[] ){
printf( "Rebroadcastinf 128 kbps mp3 stream without metadata\n" );if( argc != 5 ){
printf( "%s stream_ip /stream_path stream_port local_port\n\n", argv[0] );
return 1;
}int listener, k;
struct sockaddr_in addr;
char buf[BFFER_LEN], ch;if( ( listener = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
exit( 1 );addr.sin_family = AF_INET;
int shfd_buf = shmget( IPC_PRIVATE, BFFER_LEN, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO );
if( shfd_buf == -1 )
return 1;
int shfd_blink = shmget( IPC_PRIVATE, 1, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO );
if( shfd_blink == -1 )
return 1;switch( fork() ){ // === 1 ===
case -1: perror("fork");break;
case 0:
char* sh_buf = (char*) shmat( shfd_buf, 0, 0 );
if( sh_buf == (char*) -1 ){
perror("sh_buf w");
exit( 2 );
}
char* sh_blink = (char*) shmat( shfd_blink, 0, 0 );
if( sh_blink == (char*) -1 ){
perror("sh_blink w");
exit( 2 );
}addr.sin_port = htons( atoi( argv[3] ) );
addr.sin_addr.s_addr = inet_addr( argv[1] );
if( connect( listener, (struct sockaddr *) &addr, sizeof( addr ) ) < 0 ){
printf( "%s:%s\n" , argv[1], argv[3] );
perror( "connect" );
exit( 2 );
}strcpy( buf, "GET " );
strncat( buf, argv[2], strlen( argv[1] ) );
strcat( buf, " HTTP/1.0\nUser-Agent: WinampMPEG/5.53\nAccept: */*Icy-MetaData:0\nConnection: close\n\n" );send( listener, buf, strlen( buf ), 0 );
while( recv( listener, &ch, 1, 0 ) > 0 ){
strncat( buf, &ch, 1 );
if( strlen( buf ) < BFFER_LEN )
continue;
strcpy( sh_buf, buf );
strcpy( sh_blink, strcmp( "1", sh_blink ) ? "1" : "0" );
buf[0] = '0';
printf( "op\n" );
sleep(1);
}
shmdt( sh_buf );
shmdt( sh_blink );
close( listener );
_exit( 0 );
} // === 1 ===int sock;
addr.sin_port = htons( atoi( argv[4] ) );
addr.sin_addr.s_addr = INADDR_ANY;if( bind( listener, (struct sockaddr *) &addr, sizeof( addr ) ) < 0 ){
perror("listener 2");
exit( 2 );
}
listen( listener, 5 );
signal(SIGCHLD, SIG_IGN);
printf( "------------\n" );
fflush( stdout );
char* sh_buf = (char*) shmat( shfd_buf, 0, SHM_RDONLY );
if( sh_buf == (char*) -1 )
return 1;
char* sh_blink = (char*) shmat( shfd_blink, 0, 0 );
if( sh_blink == (char*) -1 )
return 1;
char tmp;while( 1 ){
sock = accept( listener, NULL, NULL );
if( sock < 0 ){
perror( "accept" );
exit( 3 );
}
switch( fork() ){
case 0:
close(listener);printf( "user connected\n" );
strcpy( buf, "ICY 200 OK\nicy-name: First Radio Project\n\n" );
while( recv( sock, &ch, 1, 0 ) > 0 );
send( sock, buf, strlen( buf ), 0 );
while( 1 ){
while( !strncmp( &tmp, sh_blink, 1 ) );
strncpy( &tmp, sh_blink, 1 );
send( sock, sh_buf, BFFER_LEN, 0 );
}shmdt( sh_buf );
close( sock );
_exit( 0 );
default:
close( sock );
}
}close( listener );
return 0;
}
>В общем это мультипроцессный сервер, призванный ретранслировать аудиопоток. Написал как попало, и
>оно немножко работает. Помогите разобраться в глюках.А у тебя не плохое чувство юмора! :)
Первая ошибка: плохое документирование исходника ======1===== это не коментарий.
касаемов вылета, сделайте два! сокета и два раза вызовите socket
и для первого через который вы гет посылаете измените название.strncat( buf, argv[2], strlen( argv[1] ) );
это ерунда какаято.strcpy( sh_blink, strcmp( "1", sh_blink ) ? "1" : "0" );
при всей ненужности этого кода, вы выделили 1 байт, а копируете 2.
надо как то так:
*sh_blink = (*sh_blink == '1' ?'1':'0');самое главное нет концепции как все это должно правильно работать.
вот почитайте про семафоры думаю поможет http://www.codenet.ru/progr/cpp/7/3.phpглавное: когда начинает писать в шару поставщик контента, все реады должны быть закончены и новые блокироваться.
для этого нужно два семафора, один для всех читателей, которые могут начинать чтение только когда писатель закончит заполнение буфера.
второй для писателя, который может писать в буфер когда все читатели его освободят.
>strcpy( sh_blink, strcmp( "1", sh_blink ) ? "1" : "0" );
>при всей ненужности этого кода, вы выделили 1 байт, а копируете 2.пардон, там не в байтах а в страницах выделяется. упустил.
NuINu, Спасибо ;-)
>NuINu, Спасибо ;-)Собственно, не зачто :)
простая отсылка к семаформа вряд ли сильно поможет, там надо релизовывать алогоритм один писатель несколько читателей, я у хассан гома, видел подобный, на 3 семафорах.
но мой алгоритм работает аж на 4 х :), работает в тестах, скажем так показывает нормальную синхронную работу(отставшие задачи, пропускают буфер), правда сетевую версия я не доделал, некогда.