[C]Connessione server/client "casuale"

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Avatar utente
boh
Linux 4.x
Linux 4.x
Messaggi: 1027
Iscritto il: ven 16 set 2005, 0:00
Slackware: 14.2 (x64)
Kernel: 4.4.111
Desktop: KDE 4.14.32
Località: Milano
Contatta:

[C]Connessione server/client "casuale"

Messaggio da boh »

Allora ho scritto due programmi che emulano il modello server/client:

Client:

Codice: Seleziona tutto

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>


#define PORT 4000
#define IP 15

int main(int argc, char** argv)
{
	int sd, error;
	struct sockaddr_in server_addr, mio_addr;
	int mio_addr_len = sizeof(mio_addr);
	char ip[IP] = "127.0.0.1";
	
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons((u_short)PORT);
	server_addr.sin_addr.s_addr = (long)inet_addr(ip);
	
	sd = socket(AF_INET, SOCK_STREAM, 0);
	error = connect(sd, &server_addr, sizeof(server_addr));
	
	if (error==0) {
		printf("Connessione stabilita! \n");
		getsockname(sd,  &mio_addr, &mio_addr_len);
		printf("Il mio port e': %i \n", ntohs(mio_addr.sin_port));
	}
	
	else
		printf("Fallito!\n");
		
	close(sd);
	
	return 0;
}
Server:

Codice: Seleziona tutto

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 4000
#define MAXCONN 5

int main(int argc, char** argv)
{
	int sd, new_sd;
	struct sockaddr_in server_addr, client_addr;
	int client_len=sizeof(client_addr);
	
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons((u_short)PORT);
	server_addr.sin_addr.s_addr = INADDR_ANY;
	
	sd = socket(AF_INET, SOCK_STREAM, 0);
	bind(sd, &server_addr, sizeof(server_addr));
	listen(sd, MAXCONN);
	printf("In attesa sul mio port %i \n", ntohs(server_addr.sin_port));
	
	new_sd = accept(sd, &client_addr, &client_len);
	
	printf("Ho accettato la connessione \n");
	printf("dal client con port: %i \n", ntohs(client_addr.sin_port));
	close(new_sd);
	close(sd);
	
	return 0;
}
Il problema non è che non funzionano, è che funzionano quando vogliono loro!
E' ovvio che c'è un problema ma non riesco a capire qual'è!
Praticamente avvio il server, poi il client, e tutto fila liscio, comunicano; ritento subito dopo e la connessione non avviene più.
Qualcuno sa spiegarmi dove ho sbagliato?
"Be yourself. Everyone else is already taken." ~ Oscar Wilde

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da Blizzard »

ciao
a parte che ad occhio il server mi sembra un tantino strano. È fatto per accettare 5 connessioni ma al massimo ne accetta una e poi termina.
Adesso non ho letto bene il codice, comunque se cerchi le slides di qualche corso di laboratorio di sistemi operativi anche di quello della mia università (univaq) dovresti arrivare a codici funzionanti. Io stesso li ho utilizzati.

Ciao
Gio

Avatar utente
boh
Linux 4.x
Linux 4.x
Messaggi: 1027
Iscritto il: ven 16 set 2005, 0:00
Slackware: 14.2 (x64)
Kernel: 4.4.111
Desktop: KDE 4.14.32
Località: Milano
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da boh »

Ma il codice proviene da un libro del mio corso :D
L'unica modifica che ho apportato è nel client, in cui lui usava argv[1] ad un certo punto, e mi andava in seg.
Nonostante questo il tutto funziona, quello che volevo capire era da cosa poteva dipendere che ogni tanto si mettono in comunicazione e altre volte no :-k
"Be yourself. Everyone else is already taken." ~ Oscar Wilde

Avatar utente
ksniffer
Linux 3.x
Linux 3.x
Messaggi: 540
Iscritto il: lun 30 lug 2007, 13:18
Kernel: 2.6.34
Desktop: KDE 4.4.4
Distribuzione: ArchLinux
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da ksniffer »

Se dici precisamente cosa succede posso provarci io a vedere cosa non va. Spiega passo passo qual è il problema.

" si mettono in comunicazione e altre volte no"... Che vuol dire? Il server parte? si mette in ascolto?

Avatar utente
alessiodf
Linux 3.x
Linux 3.x
Messaggi: 823
Iscritto il: ven 14 ott 2005, 21:04
Slackware: current
Kernel: 2.6.26.4
Desktop: Kde 4.1
Località: Roma
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da alessiodf »

boh ha scritto:Ma il codice proviene da un libro del mio corso :D
Cambia libro!

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C]Connessione server/client "casuale"

Messaggio da Dani »

boh ha scritto: Praticamente avvio il server, poi il client, e tutto fila liscio, comunicano; ritento subito dopo e la connessione non avviene più.
Qualcuno sa spiegarmi dove ho sbagliato?
Sbagli nel non verificare che la chiamata a bind() sia avvenuta con successo.
Dopo la chiusura della connessione la porta su localhost rimane in TIME_WAIT per un po', quindi se non passa un certo lasso di tempo eventuali nuove bind() falliranno.

Codice: Seleziona tutto

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 4000
#define MAXCONN 5

int main(int argc, char** argv)
{
   int sd, new_sd;
   struct sockaddr_in server_addr, client_addr;
   int client_len=sizeof(client_addr);
   
   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons((u_short)PORT);
   server_addr.sin_addr.s_addr = INADDR_ANY;
   
   sd = socket(AF_INET, SOCK_STREAM, 0);
   
   while (bind(sd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0)
   {
	printf ("Chiamata bind() fallita, pausa di 3 sec.\n");
	usleep (3000000);
   }
   
   listen(sd, MAXCONN);
   printf("In attesa sul mio port %i \n", ntohs(server_addr.sin_port));
   
   new_sd = accept(sd, (struct sockaddr*) &client_addr, &client_len);
   
   printf("Ho accettato la connessione \n");
   printf("dal client con port: %i \n", ntohs(client_addr.sin_port));
   close(new_sd);
   close(sd);
   
   return 0;
}


Avatar utente
ildiama
Linux 3.x
Linux 3.x
Messaggi: 536
Iscritto il: mar 27 dic 2005, 16:49
Slackware: mine
Kernel: 2.6.alto..
Desktop: KDE4
Località: Senigallia
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da ildiama »

Non sono sicuro al 100 %, ma secondo me quello della bind() è un falso problema, anche perché per come è adesso il codice dopo 1 connessione server e client si chiudono.
Se ho ben capito il tuo problema (anche qui, non 100%) secondo me dovresti risolvere con un ciclo sulla accept() del server. Qualcosa tipo

Codice: Seleziona tutto

while((new_sd = accept(sd, &client_addr, &client_lent)) == -1);
Prova e fai sapere. E in bocca al lupo. Per cose così, ci vuole sempre...

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C]Connessione server/client "casuale"

Messaggio da Dani »

Se bind() fallisce il socket resta senza nome, di conseguenza accept() non potrà mai andare a buon fine.

Avatar utente
ildiama
Linux 3.x
Linux 3.x
Messaggi: 536
Iscritto il: mar 27 dic 2005, 16:49
Slackware: mine
Kernel: 2.6.alto..
Desktop: KDE4
Località: Senigallia
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da ildiama »

Dani ha scritto:Se bind() fallisce il socket resta senza nome, di conseguenza accept() non potrà mai andare a buon fine.
Hai ragionissima Dani. Con le mie parole volevo intendere che nel codice scritto da lui, la bind() del server moooolto difficilmente fallirebbe e che eventuali problemi di connessione sono (secondo me) dovuti ad un timeout sì, ma della accept().

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C]Connessione server/client "casuale"

Messaggio da Dani »

Boh ha detto "ritento subito dopo e la connessione non avviene più", quindi sono convinto al 99% che il problema sia dovuto proprio al fallimento della funzione bind(), per il motivo detto prima.
Prendi il codice di boh, compilalo ed avvialo piu' volte. Prova quindi a telnettarti su localhost:4000, dopo ogni avvio del server. Poi prova con quello che ho postato prima, che è lo stesso identico a parte il while() sulla funzione incriminata e vedrai che finchè su localhost la porta del programma resta in TIME_WAIT bind() non ne vorrà sapere :)

Avatar utente
ildiama
Linux 3.x
Linux 3.x
Messaggi: 536
Iscritto il: mar 27 dic 2005, 16:49
Slackware: mine
Kernel: 2.6.alto..
Desktop: KDE4
Località: Senigallia
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da ildiama »

Adesso ho capito il problema di Boh! #-o
Ha ragione Dani... il mio suggerimento resta valido per il time_out della accept(), cioè per un lungo tempo di attesa fra avvio del server e avvio del client.

Avatar utente
boh
Linux 4.x
Linux 4.x
Messaggi: 1027
Iscritto il: ven 16 set 2005, 0:00
Slackware: 14.2 (x64)
Kernel: 4.4.111
Desktop: KDE 4.14.32
Località: Milano
Contatta:

Re: [C]Connessione server/client "casuale"

Messaggio da boh »

Credo che l'intuizione di Dani sia corretta!
Solo non ho capito cosa faccia esattamente quel ciclo while, e perchè risolve il problema.
Scusate sono alle prime armi con la programmazione di rete (l'ho presa in mano ieri la prima volta).
"Be yourself. Everyone else is already taken." ~ Oscar Wilde

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C]Connessione server/client "casuale"

Messaggio da Dani »

Il ciclo semplicemente chiama bind() finchè la funzione non termina con successo, facendo una pausa di tre secondi tra una chiamata e l'altra. Quando il tuo server termina la connessione rimane comunque attiva per un certo lasso di tempo, quindi la porta usata dal tuo server rimane in uso e di conseguenza bind() fallisce, il socket resta senza nome e il server non potra' accettare connessioni.
Per forzare il successo di eventuali chiamate a socket()/bind() dovresti usare SO_REUSEADDR tra le opzioni del socket, ma non so fino a che punto sia conveniente :roll:

Rispondi