套接字C:使用select进行广播,向所有客户端发送服务器响应

时间:2017-01-21 20:29:01

标签: c sockets select client-server broadcast

对不起,我是C套接字编程的初学者。我有一个服务器和更多的客户端。当客户端向服务器发送消息时,服务器应将此消息转发给所有客户端。 我使用Select()设计了Server和Client,现在我不知道如何以广播方式向所有客户端发送消息。 这是我的服务器端名为SelectServer.c:



#include "Header.h"
#include "Utility.h"

/**
variabili globale client sockets array
rappresenta l'array di socket descriptor connessi ai client TCP
*/
int conn_set[SIZE]; 



/**
@brief aggiunge la nuova connessione all'array di client connessi
@param sockfd, il socket della nuova connessione
@param conn_set, ptr all'array delle connessioni
@param dim, dimensione dell'array
@return true se la nuova connessione è stata registrata, false se la coda è piena
*/
bool add_client(int sockfd, int *conn_set, int dim){
	
	int i = 0;
	bool is_registered = false;
	for (i = 0; i < dim; i++)
	{
		if (conn_set[i] == -1)
		{
			conn_set[i] = sockfd;
			is_registered = true;
			break;
		}
	}

	return is_registered;
}


/**
@brief Funzione che gestisce l'arrivo di nuove connessioni sul listening socket TCP.
@param sockT - listening TCP socket del server
@return intero:
-# pari a -1 se la connessione è stata rifiutata.
-# pari al socket descriptor della nuova connessione (se correttamente inserita in elenco)
*/
int handleNewConn(int sockT){

	struct sockaddr_storage client; 
	socklen_t sslen = sizeof(client);

	int conn = accept(sockT, (struct sockaddr *)&client, &sslen);
	if (conn == -1)
	{
		perror("accept() error: ");
		return -1;
	}

	printf("TCP listening socket accepted new connection from ");
	printAddressInfo((struct sockaddr *)&client, sslen);
	printf("\n");

	bool is_added = add_client(conn, conn_set, SIZE);
	if (is_added == false)
	{
		printf("max client queue\n");
		close(conn);
		return -1;
	}

return conn;
}


/** 
@brief Inizializza l'array dei socket connessi
@param conn_set, ptr all'arrayd di interi
@param dim, dimensione dell'array
*/
void setConnSet(int *conn_set, int dim){

	int i = 0;
	for (i = 0; i < dim; i++)
	{
		conn_set[i] = -1;
	}
}


/**
@brief Funzione di utilità
@param name, nome dell'eseguibile
*/
void usage(char *name){
	printf("Usage: %s <domain>\n", name);
	printf("\tdomain: 0 (UNSPEC), 4 (INET), 6 (INET6)\n");
} 



int main(int argc, char *argv[]){
	
	//*********************
	char buf2[50000];
	int posxy[2];	
	int pos[100][100];
	int x, y;
	//*********************
	

	if (argc != 2) 
	{
		usage(argv[0]);
		return INVALID;
	}
	
	int family = getFamily(argv[1]);
	
	
	int sockT = 0; //TCP listening socket
	int sockU = 0; //UDP listening socket
	
	sockT = passiveOpen(family, NULL, SERVICEPORT, SOCK_STREAM); 
	sockU = passiveOpen(family, NULL, SERVICEPORT, SOCK_DGRAM); 
	
	
	if ((sockT == -1) || (sockU == -1))
	{
		printf("Errore nell'avviare i socket\n");
		return ERROR;
	} 
	
	/* su Mac OS X: 
	$ netstat -a | grep 49152
	tcp4       0      0  *.49152                *.*                    LISTEN     
	udp4       0      0  *.49152                *.*                            
	*/
	printf("TCP Server and UDP server running on port %s\n", SERVICEPORT);

	//inizializzo l'array
	setConnSet(conn_set, SIZE); 

	//handle delle nuove connessioni (socket connessi)
	int conn = 0; 

	//protocol-independent management of connections
	struct sockaddr_storage client; 
	socklen_t sslen = sizeof(client);


	/*
	definiamo il set dei file descriptor da monitorare:
	il server sarà in attesa di:
	- connessioni 
	- messaggi, 
	- e tutte condizioni monitorabili in lettura
	*/

	//dichiaro 2 read file descriptor set
	fd_set rset, allset; 

	FD_ZERO(&rset); //azzero set descrittori
	FD_ZERO(&allset); //azzero set descrittori copia

	FD_SET(sockT, &rset); //aggiungo socket TCP
	FD_SET(sockU, &rset); //aggiungo socket UDP

	//prendo il max tra i 2, più 1
	int max = (sockT > sockU)?sockT+1: sockU+1; 

	//duplico il set - allset contiene sempre i 2 socket TCP ed UDP
	allset = rset; 
	
	//***************
	ssize_t n = 0;
	//***************
	
	int result = 0;
	int quit = 0;
	while (!quit)
	{
		/*
		rfds è un value-result argument, modificato da select():
		dobbiamo re-inizializzarlo
		*/
		FD_ZERO(&rset);
		rset = allset; 

		//wait for select forever
		result = select(max, &rset, NULL, NULL, NULL);

		if (result == -1)
		{
			perror("select() error: ");
			continue;
		}
		else if (result == 0)
		{ 
			//timeout su select (non specificato, non dovrei mai arrivarci)
			continue;	
		} 
		else 
		{
			//result è pari al numero di descriptor pronti in lettura...
			printf("%d socket ready for reading\n", result);

			

			//verifichiamo chi ha dati da leggere...
			if ( FD_ISSET(sockU, &rset))
			{
			
			//*******
			n = recv(sockU, posxy, sizeof(posxy), 0);
					printf ("Prova %d",posxy[0]);
			//******
				printf("Received a datagram...\n");
				handleUDPMessage(sockU);
				//printf("decrement result...\n");
				result--;
			}

			if ( FD_ISSET(sockT, &rset))
			{
				//new TCP Connection 
				conn = handleNewConn(sockT);
			
				if (conn != -1)
				{ 
					//printf("add new conn to allset\n");
					FD_SET(conn, &allset);
				
					if ( (conn + 1) > max)
						max = conn+1;
				}
				result--;
			}

			if (result == 0)
			{
				//skip the rest
				continue;
			}

			//a questo punto devo controllare tutte le connessioni attive dei client
			int j = 0; //indice dell'array di connessioni TCP client
			while (result > 0)
			{
				if ( (conn_set[j] != -1)  && FD_ISSET(conn_set[j], &rset))
				{
					
					printf("Client Connection number %d ready for reading ...\n", j);
					int status = handleTCPClient(conn_set[j]);

					//decremento result
					result--;

					if (status == 0)
					{ 
						//client ha chiuso la connessione
						close(conn_set[j]);

						//rimuovo il socket dal set da monitorare
						FD_CLR(conn_set[j], &allset);

						//libero la sua posizione nell'array
						conn_set[j] = -1;
					}//fi status
				}//fi FD_ISSET
				
				//passo al prossimo elemento dell'array di connessioni TCP 
				j++;
			}//wend client connection

		}//fi result

	}//wend
	
	//never here
	close(sockT);
	close(sockU);
	
return 0;
}
&#13;
&#13;
&#13;

这是我的客户端名为SelectClient.c:

&#13;
&#13;
#include "Header.h"
#include "Utility.h"


/**
@brief Utility function
@param name, nome dell'eseguibile
*/
void usage(char *name){
	printf("Usage: %s <servername> <protocol> <domain>\n", name);
	printf("\tprotocol= TCP aut UDP;\n");
	printf("\tdomain= 0 (UNSPEC), 4(INET), 6(INET6)\n"); 
}


/**
@brief Esegue l'I/O multiplexing su stdin e socket connesso (UDP/TCP)
@param sock, il socket da monitorare
@param type, tipo di socket
@return nulla
*/
void multiplex(int sock, int type){

//*******************************
	int pos[100][100];
	int posxy[2];
	int x,y,xx,yy;
	char movimento;
	
	for(x=0;x<100;x++)
		for(y=0;y<100; y++)
			pos[x][y]=0;
			
	time_t tt;

   
   /* Intializes random number generator */
   srand((unsigned) time(&tt));
   
   xx = rand() % 50;
   yy = rand() % 50;
   printf("xx vale %d, yy vale %d",xx,yy);
   pos[xx][yy] = 1;
	
	
	printf("MAPPA INIZIALE:\n");
	for(x=0;x<100;x++)
		for(y=0;y<100; y++)
				printf("%d",pos[x][y]);
//*******************************				
				
				
				
	
	printf("Insert messages for server\n");
	
	fd_set rset; 
	FD_ZERO(&rset);
	
	FD_SET(STDIN_FILENO, &rset);
	FD_SET(sock, &rset);
	
	int max = (sock > STDIN_FILENO)? sock: STDIN_FILENO;

	struct timeval timer;
	timer.tv_sec = 5;
	timer.tv_usec = 0;
	
	int result = 0;
	bool quit = false;
	
	//predispongo la comunicazione ed il file descriptor set da monitorare
	ssize_t n = 0;
	char msg[BUFSIZE] = "";
	
	//***********************************
	int msgpos[100][100];
	char msgposc[50000] = "";
	
	//***********************************
	
	while (!quit)
	{
		result = select(max+1, &rset, NULL, NULL, &timer);
		
		if (result == -1)
		{
			perror("select() error: ");
			break;
		}	
		
		if (result == 0)
		{
			//printf("select timeout\n");
		}
		
		if (result > 0)
		{
			if (FD_ISSET(STDIN_FILENO, &rset))
			{
				if (fgets(msg, BUFSIZE-1, stdin) != NULL)
				{
				//**************************
				printf("scrivi\n");
				//scanf("%c",&movimento);
				movimento = getchar();
				printf("movimento %c\n",movimento);
	
				if(movimento == 'j'){
					 printf("destra\n");
					 pos[xx][yy] = 0;
					 yy++;
					 printf("xx vale %d, yy vale %d",xx,yy);
					 pos[xx][yy] = 1;
					 }
				else if(movimento == 'h'){
					 printf("sinistra\n");
					 pos[xx][yy] = 0;
					 yy--;
					 printf("xx vale %d, yy vale %d",xx,yy);
					 pos[xx][yy] = 1;
					 }
				else if(movimento == 'u'){
					 printf("sopra\n");
					 pos[xx][yy] = 0;
					 xx++;
					 printf("xx vale %d, yy vale %d",xx,yy);
					 pos[xx][yy] = 1;
					}
				else if(movimento == 'n'){
					 printf("sotto\n");
					 pos[xx][yy] = 0;
					 xx--;
					 printf("xx vale %d, yy vale %d",xx,yy);
					 pos[xx][yy] = 1;
					 }
				else
					printf("Non hai inserito un comando valido\n");
	
				for(x=0;x<100;x++)
					for(y=0;y<100; y++)
						printf("%d",pos[x][y]);
	
				//snprintf(msgposc, 50000, "%d", pos);
	
			//snprintf(posx, 10, "%d", xx);
				//snprintf(posy, 10, "%d", yy);

	
				//printf("PROVAaa: %s \n", posx);
	
	
				posxy[0] = xx;
				posxy[1] = yy;
				//**************************
					/*
					fgets ritorna una stringa che termina con la sequenza
					'\n\0'
					il null-terminated non è contato da strlen,
					ma '\n' si.
					Per tagliare '\n' trasmetto (strlen(msg) - 1).
					
					@note: ATTENZIONE
					Ogni volta che premo "Return" (dò invio), fgets() ritorna una stringa è vuota.
					La stringa vuota viene letta da send che trasmette 0 bytes dal socket "sock".
					Dobbiamo distinguere 2 casi:
					- se sock è di tipo SOCK_STREAM, l'operazione non genera dati da trasmettere;
					- se sock è di tipo SOCK_DGRAM, l'operazione genera un datagram UDP vuoto, che viene inviato al server UDP
					
					Per eliminare questo scenario, possiamo effettuare send solo su stringhe non vuote.
					*/
					//if ( (strlen(msg) - 1) != 0){
						n = send(sock, posxy, sizeof(posxy), 0);
						//n = send(sock, msg, strlen(msg) - 1, 0);
						printf("sent %d bytes\n", (int)n);
					//}//fi
				}
				else
					break; //chiusura
			}
			
			
			if (FD_ISSET(sock, &rset))
			{
				//n = recv(sock, msg, BUFSIZE-1, 0);
				//******************************
				n = recv(sock, posxy, sizeof(posxy), 0);
				//*******************************
				if (n == -1)
				{
					perror("recv() error: ");
					close(sock);
					return; // ERROR;
				}
				else if (n > 0)
				{
					//**************************
					msg[n] = 0;
					msgpos[n][n]=0;
					printf("mappa:\n");
					printf("server reply: '%d'\n", posxy[0]);
					//**************************
				//	msg[n] = 0;
				//	printf("\tResponse %d bytes message '%s'\n", (int)n, msg);
				}
				else
				{	
					//n==0 over TCP: closed connection
					//if (type == SOCK_STREAM)
					//	break;
					
					/*
					In realtà non abbiamo necessità di usare il parametro type in input alla funzione,
					perché il tipo del socket può essere ottenuto leggendo le opzioni del socket:
					*/	
					int sockType = 0;
					socklen_t optlen = sizeof(sockType);
					if ( getsockopt(sock, SOL_SOCKET, SO_TYPE, &sockType, &optlen) == 0){
						if (sockType == SOCK_STREAM) {
							printf("This is a TCP socket that received a FIN segment\n");
							break;
						} else {
							printf("This is an UDP socket that received an empty datagram\n");
						}	
					}//fi getsockopt	
								
				}
			
				
						
			}//fi sock
		}//fi result

		FD_ZERO(&rset);
		FD_SET(STDIN_FILENO, &rset);
		FD_SET(sock, &rset);
		max = (sock > STDIN_FILENO)? sock: STDIN_FILENO;

		timer.tv_sec = 5;
		timer.tv_usec = 0;
	}//wend
	printf("Multiplex ended\n");
}



int main(int argc, char *argv[]){

	if (argc != 4)
	{
		usage(argv[0]);
		return INVALID;
	}
	
	int family = getFamily(argv[3]); 
	
	int type = 0;
	if ((strcmp(argv[2], "TCP") == 0) || (strcmp(argv[2],"tcp") == 0))
	{
		type = SOCK_STREAM;
	}
	else if (strcmp(argv[2], "UDP") == 0 || (strcmp(argv[2],"udp") == 0))
	{
		type = SOCK_DGRAM;
	}
	else
	{
		printf("Invalid service type\n");
		return FAILURE;
	}

	int sockfd = open_socket(family, argv[1], SERVICEPORT, type);
	if (sockfd == INSUCCESS)
	{
		printf("Errore nell'aprire il socket e stabilire la connessione al server (TCP only)\n");
		return ERROR;
	}

	//ho un socket CONNESSO verso la destinazione specificata:
	struct sockaddr destination;
	socklen_t len = sizeof(destination);
	int res = getpeername(sockfd, &destination, &len);
	if (res != 0) {
		close(sockfd);
		return FAILURE;
	}
	//visualizzo il remote address
	printf("Connected to remote address: ");
	printAddressInfo(&destination, len);
	printf("\n");

	
	multiplex(sockfd, type);

	printf("Closing the socket...\n");
	close(sockfd);

return 0;
}
&#13;
&#13;
&#13;

这是Utility.c(实现了一些功能):

&#13;
&#13;
/**
@addtogroup Group11
@{
*/
/**
@file 	Utility.c
@author Catiuscia Melle

@brief 	Implementazione di funzioni di utilità.

*/

#include "Utility.h"


void printAddressInfo(struct sockaddr * addr, socklen_t len){
	
	//no reverse lookup in getnameinfo
	int niflags = NI_NUMERICSERV | NI_NUMERICHOST;
	char IP[INET6_ADDRSTRLEN] = "";
	char port[PORT_STRLEN] = "";
	
	//visualizzo l'indirizzo locale del socket
	int rv = getnameinfo(addr, len, IP, INET6_ADDRSTRLEN, port, PORT_STRLEN, niflags);
	
	if (rv == 0)
	{
		printf("'%s:%s'", IP, port);
	}
	else
	{
		printf("getnameinfo() error: %s\n", gai_strerror(rv));
	}
}





int open_socket(int family, char *hostname, char *servicename, int type){

	int sockfd = 0; //valore di ritorno della funzione
	int result = 0;
	
	struct addrinfo hints, *res, *p;
		
	memset(&hints, 0, sizeof(hints)); //azzero hints
		
	hints.ai_family = family; //richiedo la risoluzione per IPv6
	hints.ai_socktype = type; //service type
	
	/*
	Se richiedo AF_INET6 come family, 
	allora specificando il flag AI_V4MAPPED, 
	getaddrinfo() deve ritornare l'IPv4-mapped IPv6 address 
	se non trova indirizzi IPv6. 
	Diversamente, l'opzione non è presa in considerazione
	*/
	hints.ai_flags = AI_V4MAPPED;
	
	result = getaddrinfo(hostname, servicename, &hints, &res);
	if (result != 0)
	{
		printf("getaddrinfo: %s\n", gai_strerror(result));
		return INSUCCESS; 
	}
	
	printf("Resolution for: %s:%s Done!\n", hostname, servicename);
	
	for (p = res; p != NULL; p = p->ai_next)
	{
		sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
		if (sockfd == -1)
		{	
			perror("socket() error: ");
			continue;	
		}
		//TCP o UDP, il socket viene comunque connesso al destination address
		result = connect(sockfd, p->ai_addr, p->ai_addrlen);
		if (result == -1)
		{
			perror("connect() error: ");
			close(sockfd);
			continue;
		}

	break;
	}//for

	if (p == NULL) //if (!p)
	{
		printf("Connessione al server %s:%s fallita\n", hostname, servicename);
		return INSUCCESS; 
	}

	//dealloco risorse resolver
	freeaddrinfo(res);

return sockfd;
}



int getFamily(char *param){
	int family = 0;
	if (strncmp(param, "4", 1) == 0){
		family = AF_INET;
	} else if (strncmp(param, "6", 1) == 0){
		family = AF_INET6;
	} else {
		family = AF_UNSPEC;
	} 
	return family;
}








/*************************************************************************/ 

int passiveOpen(int family, char *nodename, char *servicename, int socktype) {

	int sock = INSUCCESS; 
	int result = 0;

	struct addrinfo hints, *res, *p;

	memset(&hints, 0, sizeof(hints));

	hints.ai_family = family;
	hints.ai_flags = AI_PASSIVE; 
	hints.ai_socktype = socktype;

	hints.ai_flags |= AI_V4MAPPED;
	hints.ai_flags |= AI_NUMERICSERV;

	result = getaddrinfo(nodename, servicename, &hints, &res);
	if (result != 0)
	{
		printf("getaddrinfo: %s\n", gai_strerror(result));
		return INSUCCESS;
	}

	int reuse = 1; //opzione SO_REUSEADDR

	for (p = res; p != NULL ; p = p->ai_next)
	{
		sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
		if (sock == -1)
		{
			perror("socket() error: ");
			continue;	
		}
		
		/*
		Per un socket nel dominio AF_INET6, se l'opzione IPV6_V6ONLY è abilitata
		viene meno la compatilibità con IPv4: il socket accetterà comunicazioni solo se
		provenienti da nodi IPv6 (ritornando l'errore 'connection refused' al client che 
		cerca di connettersi).
		Altrimenti, al socket sono consegnati anche datagram IPv4.
		
		Per abilitare l'opzione:
		*/	
    	
    	int v6flag = 1;
    	if (v6flag == 1)
    	{
    		//turn-on V6ONLY option
    		if (p->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &v6flag, sizeof(v6flag)) < 0) 
    		{
    			close(sock);
        		continue;
			}
		}
		
		if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0 )
		{
			perror("setsockopt() error: ");
			continue;
		}


		result = bind(sock, p->ai_addr, p->ai_addrlen);
		if (result == -1)
		{
			perror("bind() error: ");
			close(sock);
			continue;
		}

		break;
	}//for
	
	if (p == NULL) 
	{
		printf("Non siamo riusciti ad avviare il server %s:%s per il servizio %d\n", nodename, servicename, socktype);
		sock = INSUCCESS;
	}

	//dealloco le risorse
	freeaddrinfo(res);

	if (socktype == SOCK_STREAM)
	{
		//TCP passive open 
		result = listen(sock, BACKLOG);
		if (result == -1)
		{
			perror("listen() error: ");
			close(sock);
			return INSUCCESS;
		}
	}

return sock;
}




void handleUDPMessage(int sockU){
	
	//protocol-independent addresses management
	struct sockaddr_storage client; 
	socklen_t sslen = sizeof(client);
	
	char msg[BUFSIZE] = "";
	ssize_t n = 0;
	
	
	int posxy[2];
	
	
	
	//n = recvfrom(sockU, msg, BUFSIZE-1 , 0, (struct sockaddr *)&client, &sslen);
	//*******************
	n = recvfrom(sockU, posxy, sizeof(posxy), 0, (struct sockaddr *)&client, &sslen);
	//*****************
	if (n < 0)
	{
		perror("error on recvfrom(): ");
		return;
	}
	
	printAddressInfo((struct sockaddr *)&client, sslen);
	msg[n] = '\0';
	//printf("Received UDP %d bytes message '%s'\n", (int)n, msg);
	printf("Received UDP %d bytes message '%d'\n", (int)n, posxy[0]);

		
	char c = toupper(msg[n-1]);
	msg[n-1] = toupper(msg[0]);	
	msg[0] = c;
	
	printf("Reply to msg\n");
	//n = sendto(sockU, msg, strlen(msg), 0, (struct sockaddr *)&client, sslen);
	n = sendto(sockU, posxy, sizeof(posxy), 0, (struct sockaddr *)&client, sslen);
	if (n == -1)
	{
		perror("sendto() error: ");
	}
	
return;
}



int handleTCPClient(int sock){
	
	char msg[BUFSIZE] = "";
	ssize_t n = 0;
	
	
	int posxy[2];
	
	
	
	//get the message from client
	//n = recv(sock, msg, BUFSIZE-1, 0);
	n = recv(sock, posxy, sizeof(posxy), 0);
	
	if (n > 0)
	{
		//protocol-independent management of connections
		struct sockaddr_storage client; 
		socklen_t sslen = sizeof(client);
		char ipstr[INET6_ADDRSTRLEN] = "";
		char portstr[INET6_ADDRSTRLEN] = "";
		
		getpeername(sock, (struct sockaddr *)&client, &sslen);
		
		
		int niflags = NI_NUMERICSERV | NI_NUMERICHOST;
		int res = getnameinfo( (struct sockaddr *)&client, sslen, \
							ipstr, INET6_ADDRSTRLEN, portstr, INET6_ADDRSTRLEN, niflags);
		
		if (res == 0)
		{
			printf("Received TCP message from client da %s:%s\n", ipstr, portstr);
		}
		
		msg[n] = '\0';
		//printf("\tmessage '%s'\n\t%d bytes\n",  msg, (int)n);
		printf("\tmessage '%d'\n\t%d bytes\n",  posxy[0], (int)n);
		
		msg[0] = toupper(msg[0]);
		msg[n/2] = toupper(msg[n/2]);	
		msg[n-1] = toupper(msg[n-1]);	
		//n = send(sock, msg, strlen(msg), 0);
		n = send(sock, posxy, sizeof(posxy), 0);
		if (n == -1)
		{
			perror("send() error: ");
		}
	return 1;
	}
	
	if (n == 0)
	{
		printf("il client ha chiuso la connessione\n");
		return 0;
	} 
	
	
	if (n < 0)
	{
		perror("error on recv(): ");
		return -1;
	}
    
    return -1;
}
&#13;
&#13;
&#13;

这些是我的名为Utility.h和Header.h的库:

&#13;
&#13;
/**
@addtogroup Group11
@{
*/
/**
@file 	Utility.h
@author Catiuscia Melle

@brief 	Interfaccia del modulo di funzioni di utilità.

*/

#ifndef __UTILITY_H__
#define __UTILITY_H__


#include "Header.h"


/**
@brief Utility function per la visualizzazione dell'indirizzo associato ad un socket,
protocol-independent
@param addr, ptr alla struct sockaddr da leggere
@param len, dimensione della struttura puntata da addr
@return nulla
*/
void printAddressInfo(struct sockaddr * addr, socklen_t len);

/**
@brief Utility per l'apertura di un connection socket TCP IPv6
@param family - ipv4 o ipv6 protocol family domain...
@param hostname - stringa contenente l'hostname per cui è invocato il resolver 
@param servicename - stringa contenente il service name per cui è invocato il resolver
@param type - intero pari al tipo di socket SOCK_STREAM o SOCK_DGRAM
@return intero, pari al socket descriptor creato (-1 in caso di errore).

Attenzione, restituisce sempre un socket connesso (UDP e TCP)
*/
int open_socket(int family, char *hostname, char *servicename, int type);


/**
@brief Legge il valore di param e ritorna l'Address Family corrispondente
@param param, contiene il valore di argv[] corrispondente al dominio inserito.
@return il valore di Address Family corrispondente al dominio specificato
*/
int getFamily(char *param);








/**
@brief Funzione per la hostname resolution che ritorna il socket descriptor per un server.

@param nodename -  hostname da risolvere
@param servicename - indirizzo del servizio
@param socktype - tipo di sock (SOCK_STREAM, SOCK_DGRAM)
@return intero pari al socket descriptor allocato o -1 in caso di errore

*/
int passiveOpen(int family, char *nodename, char *servicename, int socktype);

/**
@brief Funzione che gestisce l'arrivo di messaggi sul socket UDP in ascolto
@param sockU - socket UDP in ascolto
@return nulla

Effettua ricezione ed invio al client UDP. Usa <em>getnameinfo()</em> per recuperare 
l'indirizzo del client UDP. 

*/
void handleUDPMessage(int sockU);


/**
@brief Funzione che gestisce l'arrivo di nuovi messaggi su connessioni TCP.
@param sock - socket TCP della connessione client pronta.
@return intero:
-# pari a -1 in caso di errore;
-# pari a 0 se la connessione è stata chiusa;
-# pari a 1 se il messaggio è stato elaborato con successo.
*/
int handleTCPClient(int sock);

#endif
/** @} */
&#13;
&#13;
&#13;

&#13;
&#13;
/**
@addtogroup Group11
@{
*/
/**
@file 	Header.h
@author Catiuscia Melle

@brief 	Header comune al client e server dell'esempio

L'header definisce costanti comuni al client e server.
*/

#ifndef __HEADER_H__
#define __HEADER_H__

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> //resolver related functions

#include <sys/types.h> //necessario su Mac
#include <stdlib.h>

#include <ctype.h> //toupper()
#include <stdbool.h>

#define PORTNUMBER 		49152 		/**< TCP listening port, decimal */
#define SERVICEPORT 	"49152" 	/**< TCP listening port, name */
#define PORT_STRLEN 6 /**< lunghezza di una stringa rappresentativa di un indirizzo di trasporto */

#define BACKLOG 10 	/**< dimensione della coda di connessioni */

#define SIZE 15 /**< dimensione della coda di connessioni concorrenti gestite dal server */

#define BUFSIZE 512 /**< dimensione del buffer di messaggio */

#define FAILURE 3 	/**< definizione del valore di errore di ritorno del processo in caso di errori delle Sockets API */

#define INVALID 5 	/**< se i due processi non sono avviati col giusto numero di parametri */

#define ERROR 1 /**<  valore di errore */

#define INSUCCESS -1 /**< valore di ritorno non valido */


#endif /* __HEADER_H__ */

/** @} */
&#13;
&#13;
&#13;

特别是,看看我从客户端发送到服务器的消息被称为&#34; posxy&#34;。服务器接收&#34; posxy&#34;,将其打印并再次发送给发送的客户端。但是,如果我打开更多客户端,服务器发送&#34; posxy&#34;只有在发送它的客户,我想发送&#34; posxy&#34;从服务器al所有客户端连接。

我希望有人可以帮助我。

0 个答案:

没有答案