Serwer TCP daemon

0

Cześć,
robię z kolegami projekt serwera TCP na procesie daemona. Na początku zrobiłem testowy serwer echo na TCP i on normalnie działał, żadnych zarzutów. Specyfika zadania wymaga jednak zastosowania serwera daemona, więc dodaliśmy funkcję zamieniającą proces na daemona (zmieniliśmy również port serwera na 2000 z 7, klientom również) i tu zaczęły się problemy.

Po zmianie, klienci nie mogą się podłączyć do serwera. Bez przerwy wyskakuje komunikat Connect error : Connection refused . Pierwsza rzecz, która nam przyszła do głowy, to zapora, więc usunęliśmy wszystkie zasady w firewallu :
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

Niestety, to nie pomogło. Komputery widzą się, ponieważ mogą się wzajemnie pingować, ponadto połączenia przy pomocy zwykłego serwera TCP działają prawidłowo.
Jedyne zmiany, jakie zostały wprowadzone, to dodanie funkcji daemon_init, zmieniającej postać procesu oraz jej wywołanie w funkcji main (oczywiście stosowne biblioteki zostały dodane), stąd nie do końca rozumiemy, dlaczego połączenia zostają odrzucone. Serwer jest włączany przy pomocy sudo ./serwer, jednak przy zwykłym ./serwer też nie działa.

int daemon_init(const char* pname, int facility, uid_t uid)
{
	int		i, p;
	pid_t	pid;

	if ((pid = fork()) < 0)
		return (-1);
	else if (pid)
		exit(0);			//skasowanie rodzica

	//dziecko 1 kontynuuje

	if (setsid() < 0)			//stanie sie leaderem sesji
		return (-1);

	signal(SIGHUP, SIG_IGN);
	if ((pid = fork()) < 0)
		return (-1);
	else if (pid)
		exit(0);			//kasowanie dziecka pierwszego

	//dziecko drugie kontynuuje

	chdir("/tmp");				//zmiana folderu
//	chroot("/tmp");

	//zamkniecie deskryptora plikow
	for (i = 0; i < MAXFD; i++) {
			close(i);
	}

	//przekierowanie stdin, stdout i stderr do /dev/null
	p = open("/dev/null", O_RDONLY);
	open("/dev/null", O_RDWR);
	open("/dev/null", O_RDWR);

	openlog(pname, LOG_PID, facility);

	setuid(uid); //zmiana uzwytkownika
	syslog(LOG_NOTICE, "Daemon started!");
	return (0);				//sukces
}

W funkcji main zostało dodanych kilka zmiennych, niezbędnych do funkcjonowania procesu daemona i jest on inicjalizowany:

    setlogmask(LOG_UPTO(LOG_INFO));
	daemon_init(argv[0], LOG_LOCAL1, 1000);

Proces daemona serwera normalnie funkcjonuje, chociaż nie do końca rozumiemy, dlaczego UID nie jest 1000, tylko test. Tak jest na Ubuntu, na CentOS normalnie się wyświetla, jako 1000. Połączenie jest odrzucane na obu platformach. Próbowaliśmy zmieniać porty na 2653, 2536, 2001, niestety, nie przynosiło to pożądanych rezultatów.
screenshot-20210206024709.png

Bylibyśmy wdzięczni za pomoc.
Załączam nasze kody, jakby ktoś chciał rzucić okiem. Aplikacja serwera jest zwykłym serwerem ECHO, który sprawdza, czy wiadomość, którą wysłał klient, jest tą oczekiwaną, czy nie. Serwer jest napisany dla dwóch klientów, żeby przyjmować od nich naprzemiennie informacje i odpisywać, czy została podana oczekiwana wartość. Daemon serwera, jak już mówiłem, jest tym samym, co aplikacja serwera ECHO, z tym, ze ma inny charakter procesu. Klient jedynie wysyła pakiet, który jest stringiem (zwykła wiadomość tekstowa).

Spakowane pliki:
serwer TCP.zip

3

Ten kod jest problemem:

//zamkniecie deskryptora plikow
for (i = 0; i < MAXFD; i++) {
    close(i);
}

Po usunięciu u mnie działa.

2

A netstat pokazuje że serwer słucha? Jestem na telefonie to i całości kodu nie zobaczyłem, ale kod wspomniany przez @overcq może być problemem jeśli najpierw ustawiasz listening socket serwera a potem dopiero zamykasz deskryptory.

0

@alagner:

Trochę wstyd, ale nie pomyślałem o tym, żeby sprawdzić netstatem.
screenshot-20210206143423.png
Ciężko mi określić, jak by nazwać ten stan, ale na pewno nie jest to nasłuchiwanie.
.
.
.

alagner napisał(a):

kod wspomniany przez @overcq może być problemem jeśli najpierw ustawiasz listening socket serwera a potem dopiero zamykasz deskryptory.

Bardzo celna uwaga. Przerzuciłem init daemona na sam początek maina i już działa (z zamykaniem deskryptorów, niczego nie usuwałem, chociaż tak też można)
screenshot-20210206144645.png

0
overcq napisał(a):

Ten kod jest problemem:

//zamkniecie deskryptora plikow
for (i = 0; i < MAXFD; i++) {
    close(i);
}

Po usunięciu u mnie działa.

Super! Dzięki wielkie :D no, na deskryptory to bym nie wpadł szybko.
Swoją drogą, czy niezamknięte deskryptory nie będą powodowały problemów? Spodziewam się, że Ubuntu pozamyka wszystko, gdy serwer zostanie zamknięty, jednak jak to by wyglądało z długo działającym programem?

2

Tzn. o co dokładnie pytasz? Generalnie - zamykanie tych deskryptorów to bardziej dobra praktyka niż wymóg.
Będzie z nimi problem o tyle, że w systemie jest ich limit per proces i jak go przekroczysz możesz dostać na twarz aborta albo inną formę crasha (EDIT: tak robi OSX. Na Linuxie - nie wiem, sprawdź ;) ale nie spodziewaj się, że coś dobrego się stanie ;)).
Na desktopowym Linuxie to raczej nie problem bo ten limit jest spory, ale na MacOS czy jakimś starszym serwerze łatwo wpaść w taką pułapkę. No i pytanie, po co trzymać otwarty, nieużywany zasób.

0

W ogóle po co chcesz zamykać te desktryptory, skoro ich używasz?
Natomiast przekierowanie standardowych deskryptorów coś w rodzaju, ale z potrzebnym sprawdzaniem błędów:

//przekierowanie stdin, stdout i stderr do /dev/null
p = open("/dev/null", O_RDONLY);
dup2( p, 0 );
p = open("/dev/null", O_WRONLY);
dup2( p, 1 );
p = open("/dev/null", O_WRONLY);
dup2( p, 2 );

Tutaj nie zamykasz connfd, jeśli jest za dużo klientów.

for (i = 0; i < FD_SETSIZE; i++)
    if (client[i] < 0) {
        client[i] = connfd;	/* save descriptor */
        break;
    }
if (i == FD_SETSIZE){
    fprintf(stderr,"too many clients");
    continue;
}

Tylko pobieżnie przeglądałem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1