Pagina 1 di 1

[C]Connessione server/client "casuale"

Inviato: mar 25 mar 2008, 19:53
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?

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

Inviato: mar 25 mar 2008, 20:08
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

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

Inviato: mar 25 mar 2008, 20:55
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

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

Inviato: mar 25 mar 2008, 22:09
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?

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

Inviato: mar 25 mar 2008, 23:31
da alessiodf
boh ha scritto:Ma il codice proviene da un libro del mio corso :D
Cambia libro!

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

Inviato: mar 25 mar 2008, 23:47
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;
}


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

Inviato: mer 26 mar 2008, 0:16
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...

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

Inviato: mer 26 mar 2008, 0:25
da Dani
Se bind() fallisce il socket resta senza nome, di conseguenza accept() non potrà mai andare a buon fine.

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

Inviato: mer 26 mar 2008, 0:54
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().

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

Inviato: mer 26 mar 2008, 1:00
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 :)

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

Inviato: mer 26 mar 2008, 13:16
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.

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

Inviato: mer 26 mar 2008, 13:17
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).

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

Inviato: mer 26 mar 2008, 16:43
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: