[C] Programmation réseau et socket

Résolu/Fermé
jro-daemon Messages postés 10 Date d'inscription mardi 13 février 2007 Statut Membre Dernière intervention 24 février 2007 - 13 févr. 2007 à 23:24
 nanou - 11 janv. 2008 à 11:33
Bonjour,
je suis actuellement en train de m'attaquer à l'apprentissage de l'utilisation de socket. Je travaille sous Ubuntu Edgy. J'ai deja fait le test de faire communiquer un client et un serveur en utilisant la boucle locale. Ma question est de savoir s'il est possible que je fasse tourner un client et un serveur dans un même programme en utilisant les descripteurs de fichiers.
Mon idée est la suivante:
Tout d'abord je crée un set de descripteur de fichiers avec:
fd_set master
int fd_max

Puis dans le fichier principal, je taperais un truc de ce genre:
#define PORT_CLIENT 5060
#define PORT_SERVER 7000

int client_fd;
int server_fd;
fd_set read_fds;
struct timeval tv;
/*
J'utilise ici la structure timeval pour fixer un timeout à 10 ms
*/
tv.tv_sec = 0;
tv.tv_usec = 10;

FD_ZERO(&master);
FD_ZERO(&read_fds);
/*
J'initialise ici un descripteur de fichier pour le serveur et le client. Les procédures client_start() et server_start() retournent ce socket.
*/
client_fd = client_start(PORT_CLIENT); 
server_fd = server_start(PORT_SERVER);

FD_SET(client_fd,&master);
FD_SET(server_fd,&master);
FD_SET(0,&master);

/*...*/

/*Boucle principale*/
while(1)
{
 read_fds = master;
 if (pselect(fdmax+1,&read_fds,NULL,NULL,&tv,NULL) <0)
 /*controle d'erreur*/
 if (FD_ISSET(0,&read_fds)) // On lit quelque chose dans le descripteur de fichier de stdin
{
/*Action a entreprendre en conséquence*/
}
if(FD_ISSET(client_fd,&read_fds))
{
 /*Le client a reçu quelque chose provenant du serveur, il répond en conséquence*/
}
if (FD_ISSET(server_fd,&read_fds))
{
/*Le serveur reçoit un message provenant du client, il réagit en conséquence en traitant le message dans la partie application*/
}
}

Lire l'entrée de stdin permet de sortir de la boucle infinie. Est-ce que l'idée pourrait marcher?
Johnny

5 réponses

jro-daemon Messages postés 10 Date d'inscription mardi 13 février 2007 Statut Membre Dernière intervention 24 février 2007 1
14 févr. 2007 à 12:36
Bonjour,
l'idée serait donc de le faire avec des threads. C'est-à-dire qu'il y aurait un thread pour le client et en pour le serveur. As-tu par hasard un lien sur les applications multi-thread histoire que je voie comment ça marche. Peux-tu me donner un exemple concret d'utilisation pour que je pige bien la mise en pratique?
Merci pour l'idée. Je vais continuer à réfléchir dans ce sens.
Johnny
1
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
14 févr. 2007 à 09:26
Salut.
Je n'ai pas compris ce que tu voulais faire.
Mais je ne voi aucun problème à avoir un programme qui fait à la foi client et serveur. En fait, c'est une espèce de logiciel routeur.
Moi, j'ai fait un programme qui fait plusieurs clients.
par contre, je gèrerai ça en thread plutôt qu'en while if.
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
15 févr. 2007 à 08:52
regarde ça :
https://khayyam.developpez.com/articles/cpp/multithreads/
je pense que ça correspond bien
0
jro-daemon Messages postés 10 Date d'inscription mardi 13 février 2007 Statut Membre Dernière intervention 24 février 2007 1
16 févr. 2007 à 00:08
Salut,
Je me suis renseigné et implémenter un code en utilisant un processus fils créé avec
fork()
pour s'occuper d'un nouveau client.
Et aussi, dans mon cas, si je veux faire tourner un client et un serveur dans le même programme, il est vrai que les threads sont plus adaptés.
Lorsque je reçois une requête d'un client, je lance le thread du serveur et il la traite puis si je reçois une réponse d'un serveur, je lance le thread du client tout ça en veillant à ne pas écraser des éventuelles données partagées en utilisant l'exclusion mutuelle. Je crois que ça pourrait bien se goupiller.
Merci pour ton exemple.

Cordialement,
Johnny D.
0
Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007 94
16 févr. 2007 à 11:38
Coucou, évite d'utiliser fork() si tu peux, pour plusieurs raisons:

-fork réplique la totalité du processus, il est donc bcp plus lourd
-les données à communiquer entre père et fils sont bien plus dures à communiquer qu'avec les threads
-coder avec fork c est moche

Sous Linux, tu peux utiliser pthread.h qui est super et très facile à prendre en main. Je peux te poster un exemple de serveur multi protocle et multi client si tu as besoin.
0
jro-daemon Messages postés 10 Date d'inscription mardi 13 février 2007 Statut Membre Dernière intervention 24 février 2007 1 > Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007
16 févr. 2007 à 13:31
Salut,
En comparant les deux méthodes, je pense que tes reamarques sont tout à fait judicieuses. Merci. Les threads, j'en avais jamais manipulés avant mais je pense que c'est très avantageux. Il faut par contre prendre ces précautions face aux variables partagées. Mais quand on en a pas, on s'en fout. Chaque tâche peut tourner dans un thread indépendant en se partageant les ressources mémoire du processus en cours, c'est bien ça l'idée qui est derrière le partage?
J'aimerais bien que tu me postes ton exemple, stp.
Cordialement,
Johnny D.
0
Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007 94 > Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007
16 févr. 2007 à 13:46
Oui les threads partagent le meme adressage memoire. Ainsi le plus simple (mais c'est assez dangereux dans un programme complexe, et puis c est pas tres propre), c est d utiliser des variables globales. Tout les threads y ont acces et tous peuvent ecrire. Cependant des que tu as des fonctions concurrentes, cela pose probleme. Tu peux alors utiliser des flags (blocage de la valeur le temps qu une fonction y accede) ou des semaphores. Il y a d'autres utilisations pour l exclusion mutuelle mais ces deux là sont faciles a prendre en main (en tout cas sous Linux !). Je te post le code du main d un serveur que j ai fait l annee derniere, c est donc assez recent ;)

int main()
{
	/* Variables Network */
   	struct sockaddr_in sin1;
   	struct sockaddr_in sin2;
   	struct sockaddr_in cliaddr1,cliaddr2;
   	struct sigaction sa;
   	int fd1,new_fd1;
   	int fd2,new_fd2;
   	int address_size;
   	int maxfd;
    pid_t childpid;
   	socklen_t clilen1,clilen2;
   	fd_set rset;
   	pthread_t w1;
   	pthread_t server_th;
   	pthread_t server_th2;
	
	/* Variables Video */
   	char *videodevice = "/dev/video0";
   	int format = VIDEO_PALETTE_YUV420P;
   	int width = 640;
   	int height = 480;

	/* Variables Temp */
   	char buf[16384];
   	int err,re,i,len;
	
	/* Initialisation de la video en mode mmap par defaut */
   	printf("%sVideo initialization in progress ...%s\n",ppurple,pnormal);
	memset (&videoIn, 0, sizeof (struct vdIn));
	if (init_videoIn(&videoIn, videodevice, width, height, format,1) != 0)
     		printf ("%sInitialisation error !%s\n",pred,pnormal);
	printf("%sVideo initialization correctly done !%s\n",ppurple,pnormal);
    
  	/* Creation du thread pour le Grab */
	if((err= pthread_create (&w1, NULL, (void *) grab, NULL)) != 0)
	{
		printf("%sGrab creation thread error %d %s\n",pred,err,pnormal);
		close_v4l (&videoIn);
		exit(1);
 	}

	/* Socket UDP */
  	if((fd1=socket(AF_INET,SOCK_DGRAM,0))==-1)
    		erreur("socket");
 
	/* Socket TCP */
   	if((fd2=socket(AF_INET,SOCK_STREAM,0))==-1)
     		erreur("socket");
		
   	bzero(&sin1,sizeof(sin1));
   	sin1.sin_family=AF_INET;
   	sin1.sin_addr.s_addr=INADDR_ANY;
   	sin1.sin_port=htons(port1);

   	bzero(&sin2,sizeof(sin2));
   	sin2.sin_family=AF_INET;
   	sin2.sin_addr.s_addr=INADDR_ANY;
   	sin2.sin_port=htons(port2);

	printf("%sBinding ...%s\n",pgreen,pnormal);
   	if(bind(fd1,(struct sockaddr*)&sin1,sizeof(sin1))==-1)
   		erreur("bind");
   	if(bind(fd2,(struct sockaddr*)&sin2,sizeof(sin2))==-1)
   		erreur("bind");
		
	printf("%sListening ...%s\n",pgreen,pnormal);
   	if(listen(fd2,20)==-1)
  		erreur("listen");
 
   	/* Ignore sigpipe */
    	signal(SIGPIPE, SIG_IGN);	

    	sa.sa_handler = sigchld_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;

    	printf("%sWaiting for connection ...%s\n",pblue,pnormal);
    
    	signal(SIGCHLD,sig_handle);
    	FD_ZERO(&rset);
         
	/* Beginning Client Loop */                                                                        
    	for(;;)
    	{
      		FD_SET(fd1,&rset);
     		FD_SET(fd2,&rset);
      		maxfd=max(fd1,fd2)+1;
      		if (select(maxfd,&rset,NULL,NULL,NULL)<0)
      		{
        		if(errno==EINTR)
         			continue;
        		else
        		{
         			printf("Select error : %s\n",strerror(errno));
         			exit(1);
        		}
		}
		/* Socket UDP */
     		if(FD_ISSET(fd1,&rset))
      		{
       			//printf("%s[%sUDP%s] Connection acquired from (%s%s%s)%s\n",pblue,pred,pblue,ppurple,inet_ntoa(cliaddr1.sin_addr),pblue,pnormal);
			pthread_create(&server_th2, NULL, (void *)service_udp, &fd1);
     		}
   
   		/* Socket TCP */
      		if(FD_ISSET(fd2,&rset))
      		{
       			clilen2=sizeof(cliaddr2);
       			if((new_fd2=accept(fd2,(struct sockaddr*)&cliaddr2,&clilen2))<0)
       			{
         			if(errno==EINTR)
          			continue;
          			else
          			{
           				printf("accept error \n");
           				exit(1);
          			}
       			}
			printf("%s[%sTCP%s] Connection acquired from (%s%s%s)%s\n",pblue,pred,pblue,ppurple,inet_ntoa(cliaddr2.sin_addr),pblue,pnormal);
	
			/* Creation d'un thread par client */
         		pthread_create(&server_th, NULL, (void *)service, &new_fd2);
		}
     	} /* Fin du For */
	
	/* En attente de l'arret du thread Grab */
      	pthread_join (w1, NULL);
	
	/* Fermeture programme */
      	close(fd1);
      	close(fd2);
      	close_v4l (&videoIn);
      	exit(0);
}
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298 > Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007
16 févr. 2007 à 15:54
NOTE : pthread existe aussi sous windows
0
The Incredible JSG
18 févr. 2007 à 13:47
Bonjour,


j'ai écrit un tutoriel qui explique comment utiliser les fonctions sockets, aussi bien sous Linux que sous Windows :

http://www.quantic-storm.com/qs/index.php?menu=Community&sm0=Sockets&language=FR

Tout le code est téléchargeable, ainsi qu'un exemple de client-serveur. Celui-ci utilise bien des threads (un par client ou par serveur) et le tout troune dans la même application. Le code se compile aussi bien sous Windows que sous Linux (testé avec Ubuntu).
0
jro-daemon Messages postés 10 Date d'inscription mardi 13 février 2007 Statut Membre Dernière intervention 24 février 2007 1
24 févr. 2007 à 19:08
Oui, merci pour ton information. La librairie est une API utilisable pour n'importe quel type d'application, n'est-ce-pas? Je pense que je pourrais m'en servir pour développer une application fonctionnant avec le protocole SIP.
Cordialement,
Johnny
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
slt
je cherche de la doc sur winsock
je debute en programmation socket
0