Ошибка Broken Pipe

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by ch3cker, 12 Jun 2012.

  1. ch3cker

    ch3cker New Member

    Joined:
    12 Mar 2011
    Messages:
    3
    Likes Received:
    0
    Reputations:
    0
    Делаю сервер на си с неблокирующими сокетами. Изначально он работает нормально, но в какой то момент происходит ошибка Broken Pipe (в sendall). Не знаю как правильно на нее реагировать? в данном случае я пытаюсь закрыть сокет. в список дескрипторов для select его больше не помещаю и программа работает дальше. Но netstat показывает это соединение как CLOSED и оно не исчезает. Причем изначально сервер может работать стабильно достаточно долго до возникновения первой ошибки потом за ней начинают появляться аналогичные.

    Всвязи с этим вопросы:
    1. Как можно специально вызвать ошибку Broken Pipe чтобы тестить и не ждать пол дня пока она проявится на рабочем сервере?
    2. Как закрыть ошибочный сокет полностью чтобы его небыло в netstat?

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

    OS: FreeBSD 8.3

    Code:
    // структура клиентов
    struct deskr_socket
    {
    int sd; 								// сам дескриптор
    int uid; 								// уид юзера по базе
    ...
    };
    
    struct deskr_socket sockets[MAX_SOCK];	// создание массива клиентов
    
    
    //функция обнуления юзера
    void zerouser(int no)
    {
    sockets[no].sd = 0;
    sockets[no].uid = 0;
    ...
    }
    
    void clossing(int number)
    {
    //FD_CLR(sockets[number].sd, &readset);		//удаляем дескриптор из списка для select
    //if (shutdown(sockets[number].sd, 2) != 0) printf("shutdown failed: %s\n", strerror( errno )); 				//закрываем сокет 
    close(sockets[number].sd);
    zerouser(number);
    users_count--;
    printf("clossing %d OK...\n", number);
    }
    
    
    //Функция отправки данных в сокет (отправляет весь буфер данных) и в случае ошибки будет закрывать сокет
    int sendall(int s, char *buf, int len, int flags, int no)		//no - номер сокета
    {
        int total = 0;
        int n;
    
    	
        while(total < len)
        {
            n = send(s, buf+total, len-total, MSG_NOSIGNAL); // Вот тут появляется ошибка Broken Pipe
            if(n == -1) 
    			{ 
    			clossing(no); //В случае ошибки закрываем
    			}
            total += n;
        }
    	
    	if (total == len) return 1; else return -1;
    }
    
    
    
    int func(int n)//n- номер сокета в массиве с которого пришла мессага
    {
    //обработка
    ...
    sendall(sockets[n].sd, sendbuf, strlen(sendbuf)+1,0,n); //Отправка ответа
    
    }
    
    
    while(1)
    {
    FD_ZERO(&readset);//обнуляем множество дескрипторов
    FD_SET(sock, &readset);// добавляем сокет прослушки в множество дескрипторов
    	
    //цикл добавления сокетов к множеству дескрипторов проверки сокетов с которых осуществляется чтение
    for (i=0; i < MAX_SOCK; i++) if (sockets[i].sd > 0 && sockets[i].doclose==0) FD_SET(sockets[i].sd, &readset);
    
    timeout.tv_sec = 15;
    timeout.tv_usec = 0;
    	
    retval = select(MAX_SOCK+1, &readset, NULL, NULL, &timeout); //получаем список каналов готовых к чтению
    	
    if (retval) //если есть готовые сокеты
    	{
    	....
    	....
    bytes=recv(sockets[i].sd,buf,BUF_SIZE,0);// читаем
    
    	if (bytes > 0)//если инфа принята то запускаем функцию обработки мессаг
    		{
    			if (func(i) != 1) //если функция завершилась неправильно то 
    			{
    				printf("Error in func()...\n");
    				clossing(i);//закрываем сокет
    			}
    				
    		}else if (bytes == 0) //если = 0 значит клиент вырубился закрваем сокет
    			{
    				printf("-------------BYTES==========0--------------\n");
    							
    				if (sockets[i].up)
    					{
    						sockets[i].doclose=1;				//ставим метку необходимости закрытия сокета после того как данные сохранятся
    					}else
    						{
    						clossing(i);			//запускаем функцию которая заркывает сокет 
    						}
    					}
    					else if (bytes < 0)
    					{
    					printf("-------------BYTES<<<<<<<<<<<<0--------------\n");
    					printf("RECV failed: %s\n", strerror( errno ));
    					//clossing(i);
    						
    					}
    
    	}
    }
    
    Буду благодарен за любую полезную информацию
     
  2. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
  3. ch3cker

    ch3cker New Member

    Joined:
    12 Mar 2011
    Messages:
    3
    Likes Received:
    0
    Reputations:
    0
    Эту ссылу я видел и прочитал, но решения там не нашел да и ситуация там другая описана