Вечный неблокирующий сервер

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by cupper, 14 Jul 2010.

  1. cupper

    cupper Elder - Старейшина

    Joined:
    6 Jun 2007
    Messages:
    369
    Likes Received:
    92
    Reputations:
    5
    пример: сделать сервер, для приему текстовых сообщений, чтобы могло коннектиться много клиентов. С Сокетами почти не работал, нашел статью в нете, наваял такой ког (только сетевая часть)
    Code:
    while(1){
    		// Заполняем множестно сокетов
    		fd_set readset;
    		FD_ZERO(&readset);
    		FD_SET(listener, &readset);
    		
    		for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
    			FD_SET(*it, &readset);
    		
    		timeval timeout;
    		timeout.tv_sec = 30;
    		timeout.tv_usec = 0;
    		
    		// Ждем появления конекта
    		int mx = max(listener, *max_element(clients.begin(), clients.end()));
    		select(mx+1, &readset, NULL, NULL, &timeout);
    		if(select(mx+1, &readset, NULL, NULL, &timeout) <= 0){
    			cerr<<"select";
    			exit(3);
            	}
            	
            	if(FD_ISSET(listener, &readset)){
            		// Есть новый запрос на соединение
    			int sock = accept(listener, NULL, NULL);
    			if(sock < 0){
    				cerr<<"error accept\n";
    				exit(3);
    			}
    			fcntl(sock, F_SETFL, O_NONBLOCK);
    			clients.insert(sock);
    		}
    
    		for(set<int>::iterator it = clients.begin(); it != clients.end(); it++){
    			if(FD_ISSET(*it, &readset)){
    				//cout<<"Accept connections...\n";
    				bytes_read = recvall(*it, XMLstr, 1024, 0);
    				if(bytes_read <= 0){
    					close(*it);
    					clients.erase(*it);
    					continue;
    				}
    				cout<<XMLstr<<endl;
    				//cout<<"Accept stoped...\n";
    				XMLstr = "";
    			}
    		}
    
    	}
    
    в таком случае сервер работает некоторое время (в зависимости от таймаута, и завершает свою работу, а нужно чтобы он висел до тех пор пока его не закроют. Закоментил вот этот код
    Code:
    if(select(mx+1, &readset, NULL, NULL, &timeout) <= 0){
    			cerr<<"select";
    			exit(3);
            	}
    
    теперь сервер весит бесконечно, но так как я не совсем понимаю суть этого кода у меня возникает вопрос, какие из этого могут быть проблемы ?) И как сделать правильней ?

    И еще одна маленькая проблема, запускаю сервер, запускаю клиент, он отправляет порцию данные, сервер все нормально получает и выводит на экран. Если запустить клиент повторно, то на сервер в конце полученный данных приписывается пару кривых символов, не знаю почему и откуда они. Если сервер перезапустить, то опять в первый раз все нормально, во второй и т.д. приписываются несколько кривых символов
    Мб проблема где то в логике функции используемой для считывание всего массива данных через сокет
    Code:
    int recvall(int s, string &str, int len, int flags){
    	int total = 0;
    	int n;
    	char buf[1024];
    
    	while(1){
    		n = recv(s, buf, len, flags);
    		if(n <= 0) { break; }
    		str += buf;
    		total += n;
    	}
    
    	return total;
    }
    
     
  2. Faost

    Faost New Member

    Joined:
    11 Jul 2009
    Messages:
    18
    Likes Received:
    3
    Reputations:
    0
    Этот код "ждет", пока от клиента станет возможным принимать данные. Т.е. в данном случае прога ждет 30 сек. Если условие не выполнилось, то вызывает exit(3) (по всей видимости выходит я так понимаю).
    Чтобы сделать ожидание вечным, параметр, где задается timeout, должен быть равен NULL.
    Т.е. так:
    Code:
    if(select(mx+1, &readset, NULL, NULL, NULL) <= 0){
    			cerr<<"select";
    			exit(3);
            	}
    следующий код выполняется даже если еще нет возможности принять данные.
    по всей видимости ты не очищаешь буфер перед последующими приемами данных. Попробуй очистить str перед заходом в функцию recvall.
     
    1 person likes this.