Socket C: broadcast with select, send Server Response to all Clients - c

I'm sorry but I'm a beginner in C Socket Programming. I have a Server and more client. When a Client send a message to the Server, the Server should forward this message to all Clients.
I designed Server and Client using the Select(), now I don't know how I can do to send in broadcast the message to all Clients, in broadcast way.
This is my Server side called 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;
}
This is my Client side called SelectClient.c:
#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;
}
This is Utility.c (where are implemented some functions):
/**
#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;
}
and these are my libraries called Utility.h and Header.h:
/**
#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
/** #} */
/**
#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__ */
/** #} */
In particular, look that the message that I send from Client to Server is called "posxy". The Server receive "posxy", print it and send it again to the client who sent. But if I open more Client, the Server send "posxy" only at the Client who sent it, I want to send "posxy" from Server al all Clients connected.
I hope that somebody can help me.

Related

Multi-homed TCP server and client stuck in a loop

This is my first try to realize a multi-homed file server (kind of) using fork(). The intention is to handle multiple hosts that send operations in the form 'create delete open close write read seek -filetarget ...' (e.g. create -hello.c write -hello.c delete -hello.c).
SERVER
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<ctype.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<sys/socket.h>
#define BACKLOG 10
extern int inet_ntoa();
extern int inet_pton();
int master(int, int);
int control(char []);
int execute(int, int, char [], char [], char[], int);
int main(int argc, char *argv[]){
int server, accepted, porta, nuovo;
struct sockaddr_in listener, client;
socklen_t len;
if(argc!=2){ //CONTROLLO PARAMETRI
printf("Errore nei parametri.\n");
return -1;
}else porta = atoi(argv[1]); //CONVERSIONE NUMERO DI PORTA
if((server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0){ //CREAZIONE DELLA SOCKET
perror("Errore nella creazione della socket.");
return -1;
}
memset(&listener, 0, sizeof(listener)); //SETTAGGIO ATTRIBUTI LISTENER
client.sin_family = AF_INET;
client.sin_addr.s_addr = htonl(INADDR_ANY);
listener.sin_port = htons(porta);
if(bind(server, (struct sockaddr *)&listener, sizeof(listener)) < 0){ //BINDING SERVER
perror("Errore binding!");
return -1;
}
if(listen(server, BACKLOG) < 0){ //LISTENING
perror("Errore listening!\n");
return -1;
}
printf("Socket inizializzata con successo..\n");
sleep(2);
system("clear");
while(1){
printf("FATHER: *** in attesa ***\n");
len = sizeof(client);
accepted = accept(server, (struct sockaddr *)&client, &len); //ACCETTO NUOVA CONNESIONE SU ACCEPTED
if(accepted < 0){
perror("Errore nella accept!");
return -1;
}
printf("FATHER: *** connessione stabilita con il client %d ***\n", inet_ntoa(client.sin_addr));
nuovo = fork(); //FORK()
if(nuovo == 0){ //FIGLIO
master(accepted, server);
}else if(nuovo < 0){
perror("Errore fork!");
exit(-1);
}else close(accepted);
}
return 0;
}
int master(int accepted, int server){
int fd, i, k, j, flag;
char richiesta[256], operazione[256], result[256], file[256], file_opened[256];
printf("Figlio\n");
close(server); //CHIUDO SERVER CHE HO EREDITATO E NON MI SERVE
recv(accepted, richiesta, sizeof(richiesta), 0); //RICEVO RICHIESTA
//printf("Richiesta -> %s", richiesta);
if(strcmp(richiesta,"exit") == 0){ //SE RICHIESTA DI USCITA, ESCO
close(accepted);
exit(0);
}
fd = -1; //AZZERO GLI INDICI E PONGO IN STATO DI ERRORE fd
j = 0;
k = 0;
i = 0;
while(i < strlen(richiesta)){ //FINCHÈ LA RICHIESTA NON È STATA ESAMINATA PER INTERO
while(richiesta[i] != '-'){ //FINCHÈ NON INCONTRO UN CARATTERE "-"
operazione[j] = richiesta[i]; //COPIO OGNI LETTERA DI RICHIESTA IN OPERAZIONE
j++;
i++;
}
operazione[strlen(operazione) - 1] = '\0'; //TERMINO LA STRINGA CON '\0'
i = i+1; //AVANZO DI UNO SUPPONENDO DI TROVARMI SU UNO SPAZIO
while(richiesta[i] != ' '){ //FINCHÈ NON TROVO UN ALTRO SPAZIO
file[k] = richiesta[i]; //COPIO OGNI LETTERE DI RICHIESTA IN FILE
i++;
k++;
}
if(!isalpha(file[strlen(file) - 1]))file[strlen(file) - 1] = '\0'; //TERMINO LA STRINGA CON '\0'
flag = control(operazione); //CONTROL VERIFICA LA VALIDITÀ
if(flag == -1) strcpy(result,"Errore nella richiesta!\n\0"); //SE ERRORE, RESULT CONTERRÀ IL MESSAGGIO DI ERRORE
else execute(flag, fd, result, file, file_opened, accepted); //ALTRIMENTI SI PROCEDE CON L'ESECUZIONE DI QUANTO CHIESTO
send(accepted, result, sizeof(result), 0); //SENDO IL RISULTATO
memset(result, '\0', sizeof(result)); //AZZERO LE STRINGHE ED I CONTATORI UTILIZZATE
memset(file, '\0', sizeof(file));
memset(operazione, '\0', sizeof(operazione));
j = 0;
k = 0;
}
send(accepted, "end", sizeof("end"), 0); //NOTIFICO LA FINE DELL'ESECUZIONE E CHIUDO
close(accepted);
printf("Fine figlio\n");
exit(0);
}
int control(char operazione[]){
if((strcmp(operazione,"write"))==0) return 1;
else if((strcmp(operazione,"read"))==0) return 2;
else if((strcmp(operazione,"seek"))==0) return 3;
else if((strcmp(operazione,"open"))==0) return 4;
else if((strcmp(operazione,"close"))==0) return 5;
else if((strcmp(operazione,"delete"))==0) return 6;
else if((strcmp(operazione,"create"))==0) return 7;
else return -1;
}
int execute(int flag, int fd, char result[], char file[], char file_opened[], int client_descriptor){
char testo[8192], off[5];
int offset;
char operation[3][6] = {"read\0", "write\0", "seek\0"};
char noop[] = "noop";
if(fd != -1){
if(strcmp(file_opened, file) != 0){
strcpy(result,"Errore, il file aperto non è quello sul quale si vuole operare!\n\0");
return -1;
}
}
switch(flag){
case 1: //write
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
send(client_descriptor, operation[1], strlen(operation[1]), 0); //ask for text over network
recv(client_descriptor, testo, sizeof(testo), 0);
while(lockf(fd, F_TEST, 0) != 0);
lockf(fd, F_LOCK, 0);
write(fd, testo,sizeof(testo));
lockf(fd, F_ULOCK, 0);
memset(testo, '\0', sizeof(testo));
}
break;
case 2: //read
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
send(client_descriptor, operation[0], strlen(operation[0]), 0);
while(read(fd, testo, sizeof(testo)) > 0) send(client_descriptor, testo, strlen(testo), 0);
}
break;
case 3: //seek
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
send(client_descriptor, operation[2], strlen(operation[2]), 0);
recv(client_descriptor, off, sizeof(off), 0);
offset = atoi(off);
while(lockf(fd, F_TEST, 0) != 0);
lockf(fd, F_LOCK, 0);
lseek(fd, (long int)offset, SEEK_SET);
lockf(fd, F_ULOCK, 0);
}
break;
case 4: //open
send(client_descriptor, noop, sizeof(noop), 0);
if(fd == -1){
if((fd = open(file, O_RDWR))<0){
strcpy(result,"Errore, file inesistente!\n\0");
return -1;
}else strcpy(file_opened, file);
}else{
strcpy(result,"Errore, un file è già aperto!\n\0");
return -1;
}
break;
case 5: //close
send(client_descriptor, noop, sizeof(noop), 0);
if(fd == -1){
strcpy(result,"Errore, nessun file aperto!\n\0");
return -1;
}else{
close(fd);
memset(file_opened, '\0', strlen(file_opened));
}
break;
case 6: //delete
send(client_descriptor, noop, sizeof(noop), 0);
if(strcmp(file_opened, file) == 0){
strcpy(result,"Errore, il file da eliminare è attualmente aperto!\n\0");
return -1;
}else if(remove(file) < 0){
strcpy(result,"Errore, il file da eliminare non esiste!\n\0");
return -1;
}
break;
case 7: //create
send(client_descriptor, noop, sizeof(noop), 0);
if(open(file, O_CREAT)<0){
strcpy(result,"File inestente, creane uno prima di scriverci!\n\0");
return -1;
}
break;
}
strcpy(result,"\nSuccesso!\n\0");
return 0;
}
Server create a listening socket, accept a new connection, fork() itself, father goes back to listen and child serves the client.
In specific, child receive the client request and break it into two pieces: operazione[] that is the operation to perform and file[] which is the target. Then control them and execute the operation. Repeat until request string is terminated.
CLIENT
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
extern int inet_pton();
int main(int argc, char *argv[]){
int server, porta;
struct sockaddr_in addr;
char result[256], richiesta[256], risposta[256], testo[8192];
socklen_t len;
if(argc!=3){ //CONTROLLO I PARAMETRI
printf("Errore nei parametri.\n");
return -1;
}else porta = atoi(argv[2]); //CONVERTO IN NUMERO LA PORTA
if((server = socket(AF_INET, SOCK_STREAM, 0))<0){ //CREAZIONE SOCKET
perror("Errore nella creazione della socket.");
return -1;
}
memset(&addr, 0, sizeof(addr)); //AZZERO LA STRUTTURA
addr.sin_family = AF_INET; //SETTAGGIO ATTRIBUTI STRUTTURA
addr.sin_port = htons(porta);
if((inet_pton(AF_INET, argv[1], &addr.sin_addr))<0){
printf("Settaggio attributi fallito.\n");
return -1;
}
len = sizeof(addr); //LUNGHEZZA IN BYTE DELLA STRUTTURA
if((connect(server, (struct sockaddr *)&addr, len))<0){ //CONNESSIONE AL SERVER
perror("Connessione fallita.");
return -1;
}
printf("Connessione stabilita!\n");
while(1){ //PER SEMPRE
sleep(2);
system("clear"); //PULISCI SCHERMO
memset(richiesta, '\0', sizeof(richiesta)); //AZZERAMENTO RICHIESTA
memset(risposta, '\0', sizeof(risposta)); //AZZERAMENTO RISPOSTA
do{
printf("SUPPORTATE (read write seek open close delete create) -file ...\n");
printf("Richiesta: ");
}while((fgets(richiesta, sizeof(richiesta), stdin)) == NULL);
printf("RICHIESTA %s\n", richiesta);
printf("Hey"); //ACQUISISCO RICHIESTA
if(strcmp(richiesta,"exit") == 0){ //SE È UGUALE ALLA STRINGA "exit", ESCE DAL CICLO
send(server, "exit\0", 5, 0); //SENDO "exit" AL SERVER
close(server); //CHIUDO LA CONNESSIONE
return 0;
}
printf("HELLO");
send(server, richiesta, strlen(richiesta), 0); //SENDO RICHIESTA
while(1){
while(recv(server, risposta, sizeof(risposta), 0) == 0); //RICEVO LA PRIMA RISPOSTA
if(strcmp(risposta,"end") == 0) break; //RICHIESTA PROCESSATA PER INTERO
if((strcmp(risposta,"read") == 0) || (strcmp(risposta,"write") == 0) || (strcmp(risposta,"seek") == 0)){ //SE LA RISPOSTA È UGUALE A "read", "write" O "seek"
memset(testo, '\0', sizeof(testo)); //AZZERO TESTO
if(strcmp(risposta,"read") == 0){ //SE È UGUALE A "read"
while(recv(server, testo, sizeof(testo), 0) > 0){ //LEGGO TUTTO E STAMPO A VIDEO
printf("%s", testo);
memset(testo, '\0', sizeof(testo));
}
}else if(strcmp(risposta,"write") == 0){ //SE È UGUALE A "write"
printf("Testo da scrivere sul file: ");
scanf("%s", testo);
send(server, testo, sizeof(testo), 0); //ACQUISISCO IL TESTO E LO MANDO AL SERVER
}else if(strcmp(risposta,"seek") == 0){ //SE È UGUALE A "seek"
printf("Numero di byte spostamento dall'inizio del file: ");
scanf("%s", testo); //ACQUISISCO NUMERO BYTE E SENDO
send(server, testo, sizeof(testo), 0);
}
}
recv(server, result, sizeof(result), 0);
printf("RESULT %s\n", result); //STAMPO LA RISPOSTA & AZZERO LA RISPOSTA
memset(risposta, '\0', sizeof(risposta));
memset(result, '\0', sizeof(result));
}
}
return 0;
}
Client should send to the server the request, send more text when required (e.g. write or seek) and display it when needed (e.g. read) and then display the state of the operation (Success or Error) sent by the server after execution.
My problem is that after type the request in the client it seems to be stuck and do nothing. No one of the control printf such 'Hey' or 'Hello' are shown.
It appears if I replace while(recv(server, risposta, sizeof(risposta), 0) == 0); with recv(server, risposta, sizeof(risposta), 0); but then it starts looping as if recv() does not block.
Where are the errors? I'm going mad.
You cannot write correct networking code without storing the result of recv() into a variable and testing it for (i) -1, indicating an error, (ii) zero, indicating that the peer has closed the connection, or (iii) a positive number, which indicates the number of bytes you have actually received. In case (i) you need to print or log an error, close the socket, and exit; in case (ii) you need to close the socket and exit.
You also cannot assume that entire requests are received in a single recv(): you have to loop; or that the buffer resulting from any single recv() operation is null-terminated.
You also need to test the result of send(): you cannot just assume it succeeded.
Fix all this and try again.

C language - Sockets - A chat between two clients (using one server as middle man)

I need to write a chat program in C using sockets and I got stuck on my way.
I have three files: server, client1, client2. My initial plan:
- Client1 sends the messages to server
Server receives it and sends it to Client2
Client2 receives Client1's message, writes something back and sends it to server
Server receives Client2's message and sends it to Client1
Client1 receives it and writes something back which is firstly received by server, etc.etc.etc.
The loop ends when either of the clients sends "exit".
My problem in a few words:
The first exchange is successful (Client1 -> Client2, then Client2 to Client1)
However, after Client2 has sent its first message to Client1, he doesn't wait for Client1's response. He writes "Client1 : " with an empty line for the message and then immediately opens his own "Client2 : " message field.
What in God's name can be wrong here?
Client1.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int compare_strings(char a[], char b[])
{
int c = 0;
while (a[c] == b[c])
{
if (a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if (a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
int main() {
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
int cmdEXIT = 0;
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
while (cmdEXIT == 0)
{
printf("Client 1 : ");
scanf(" %[^\n]s", buffer);
send(clientSocket,buffer,sizeof buffer - 1,0);
if (compare_strings(buffer, "exit")==-1)
{
memset(&buffer[0], 0, sizeof(buffer));
recv(clientSocket, buffer, sizeof buffer - 1, 0);
if (compare_strings(buffer, "exit")==-1)
{
printf("Client 2 : ");
printf("%s\n", buffer);
memset(&buffer[0], 0, sizeof(buffer));
}
else cmdEXIT=1;
}
else cmdEXIT=1;
}
return 0;
}
Server.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int compare_strings(char a[], char b[])
{
int c = 0;
while (a[c] == b[c])
{
if (a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if (a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
int main() {
int welcomeSocket, newSocket, Client2;
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
char buffer[1024];
welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr("127.0.01");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if (listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
addr_size = sizeof serverStorage;
newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
Client2 = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
int cmdEXIT = 0;
while (cmdEXIT == 0)
{
recv(newSocket, buffer, 1024, 0);
printf ("%s\nEnvoie au Client2\n", buffer);
send(Client2,buffer,1024,0);
if (compare_strings(buffer, "exit")==0)
{
cmdEXIT = 1;
}
else
{
memset(&buffer[0], 0, sizeof(buffer));
recv(Client2, buffer, 1024, 0);
printf ("%s\nEnvoie au Client1\n", buffer);
send(newSocket,buffer,1024,0);
if (compare_strings(buffer, "exit")==0)
{
cmdEXIT = 1;
}
}
}
return 0;
}
Client2.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int compare_strings(char a[], char b[])
{
int c = 0;
while (a[c] == b[c])
{
if (a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if (a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
int main() {
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
int cmdEXIT = 0;
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
while (cmdEXIT == 0)
{
recv(clientSocket, buffer, sizeof buffer - 1, 0);
if (compare_strings(buffer, "exit")==-1)
{
printf("Client 1 : ");
printf("%s\n", buffer);
memset(&buffer[0], 0, sizeof(buffer));
printf("Client 2 : ");
scanf(" %[^\n]s", buffer);
send(clientSocket,buffer,sizeof buffer - 1,0);
if (compare_strings(buffer, "exit")==-1)
{
memset(&buffer[0], 0, sizeof(buffer));
}
else cmdEXIT = 1;
}
else cmdEXIT = 1;
}
return 0;
}
Result in a screenshot:
Client 2 being too bossy and not waiting for his turn to speak
Disclaimer: I haven't run your code myself, so the below analysis could be wrong.
I recommend you check the return value of recv, which would return -1 on error. If recv is encountering an error in this line of Client2.c: recv(clientSocket, buffer, sizeof buffer - 1, 0); at the beginning of the while loop the buffer would remain zeroed out.
Thus, Client 2 would not wait for Client 1's message, and would simply print an empty string for the message from Client 1.
Let me know if any of this helps or you need more assistance. If the above is true, you should make sure that the connection is not getting interrupted, among other things.
So, as promised in the previous comment, here is my solution. To cut long story short: every time I test what the value of recv is. If it is equal to 1, it means that there is no message received, "the line is free" and the client can type his own message. Otherwise, he has to display the received message and only after that he can send his own text.
Client1.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
//fonction pour comparer deux strings : renvoie 0 si les valeurs sont égales
//et -1 sinon
int compare_strings(char a[], char b[])
{
int c = 0;
while (a[c] == b[c])
{
if (a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if (a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
int main() {
//déclaration des variables
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
int cmdEXIT = 0;
//paramètrage du socket
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
//connection au serveur
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
//premier message du Client1
printf("Client 1 : ");
scanf(" %[^\n]s", buffer);
send(clientSocket,buffer,sizeof buffer - 1,0);
//continuer à envoyer et recevoir des messages
//tant qu'un des clients n'envoive pas "exit"
while (cmdEXIT == 0)
{
//si le message envoyé n'est pas "exit"
if (compare_strings(buffer, "exit")==-1)
{
//vider le buffer
memset(&buffer[0], 0, sizeof(buffer));
//la valeur de recv qui est égale a 1 si recv n'a pas
//encore reçu de message
//sinon, elle est égale au nombre de bits reçu
int recvValue = recv(clientSocket, buffer, sizeof buffer - 1, 0);
//si recv n'est pas égal a 1 => un message a été reçu
if (recvValue != 1)
{
//si le contenu n'est pas "exit"
if (compare_strings(buffer, "exit")==-1)
{
//afficher le message du Client2
printf("Client 2 : ");
printf("%s\n", buffer);
//vider le buffer
memset(&buffer[0], 0, sizeof(buffer));
}
//si Client2 a envoyé "exit"
else cmdEXIT=1;
}
//si rcv est égal a 1 => pas de message reçu
else
{
//Client1 peut saisir son message
printf("Client 1 : ");
scanf(" %[^\n]s", buffer);
//et l'envoyer à Client2
send(clientSocket,buffer,sizeof buffer - 1,0);
}
}
//sinon finir la boucle
else cmdEXIT=1;
}
return 0;
}
Server.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
//fonction pour comparer deux strings : renvoie 0 si les valeurs sont égales
//et -1 sinon
int compare_strings(char a[], char b[])
{
int c = 0;
while (a[c] == b[c])
{
if (a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if (a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
int main() {
//déclaration des variables : Serveur et deux Clients
int welcomeSocket, Client1, Client2;
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
char buffer[1024];
//paramètrage du Serveur
welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr("127.0.01");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
//Serveur à l'écoute
if (listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
//lier le serveur et les deux clients
addr_size = sizeof serverStorage;
Client1 = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
Client2 = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
int cmdEXIT = 0;
//continuer à recevoir et envoyer des messages
//tant qu'un des clients n'envoive pas "exit"
while (cmdEXIT == 0)
{
//recevoir le message de Client1
recv(Client1, buffer, 1024, 0);
//le renvoyer a Client2
printf ("%s\nEnvoie au Client2\n", buffer);
send(Client2,buffer,1024,0);
//sortir de la boucle si Client1 a envoyé "exit"
if (compare_strings(buffer, "exit")==0)
{
cmdEXIT = 1;
}
//sinon
else
{
//vider le buffer
memset(&buffer[0], 0, sizeof(buffer));
//recevoir le message de Client2
recv(Client2, buffer, 1024, 0);
//le renvoyer a Client1
printf ("%s\nEnvoie au Client1\n", buffer);
send(Client1,buffer,1024,0);
//si Client2 a envoyé "exit"
if (compare_strings(buffer, "exit")==0)
{
cmdEXIT = 1;
}
}
}
return 0;
}
Client2.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
//fonction pour comparer deux strings : renvoie 0 si les valeurs sont egales et -1 sinon
int compare_strings(char a[], char b[])
{
int c = 0;
while (a[c] == b[c])
{
if (a[c] == '\0' || b[c] == '\0')
break;
c++;
}
if (a[c] == '\0' && b[c] == '\0')
return 0;
else
return -1;
}
int main() {
//déclaration des variables
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
int cmdEXIT = 0;
//paramètrage du socket
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
//connection au serveur
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
//continuer à envoyer et recevoir des messages
//tant qu'un des clients n'envoive pas "exit"
while (cmdEXIT == 0)
{
//la valeur de recv qui est égale a 1 si recv n'a pas
//encore reçu de message
//sinon, elle est egale au nombre de bits reçu
int recvValue = recv(clientSocket, buffer, sizeof buffer - 1, 0);
//si recv n'est pas égal a 1 => un message a été reçu
if (recvValue != 1)
{
//si le contenu n'est pas "exit"
if (compare_strings(buffer, "exit")==-1)
{
//afficher le message du Client1
printf("Client 1 : ");
printf("%s\n", buffer);
memset(&buffer[0], 0, sizeof(buffer));
}
//sinon sortir de la boucle
else cmdEXIT = 1;
}
else
{
//Client2 peut saisir son message
printf("Client 2 : ");
scanf(" %[^\n]s", buffer);
//Client2 envoie son message au serveur
send(clientSocket,buffer,sizeof buffer - 1,0);
//si le contenu n'est pas "exit"
if (compare_strings(buffer, "exit")==-1)
{
//vider le buffer
memset(&buffer[0], 0, sizeof(buffer));
}
//sinon sortir de la boucle
else cmdEXIT = 1;
}
}
return 0;
}

Windows Socket (UDP) - Client TIMEOUT issue

I've a server and a client (code posted bellow).
Im testing the setsockopt function with the SO_RCVTIMEO timeout option in the client program, and it seems to be compiling fine.
The procedure is: server binds to socket for reading - client sends a message to it - server shows message and resends it to whichever client sent it - and finally, client shows message recieved from server
So, to check if the timeout actually fails after X amount of miliseconds (timeout is only used when the client is waiting for the message to be sent back from the server), i inserted a Sleep(miliseconds) function in the server just before it resends the message to the client, so as to balance this delay between the client and the server.
So, when testing with Sleep(0) and timeout at 0 aswell, everything works perfectly synchronized, but if i lift the values to, say, 10 ms on both ends, the result should be the same as with 0, but actually, everything works as planned except when the client awaits for the server's response, it timeout's, eventhough the delay on both ends is exactly the same.
As a last example: if the Sleep on the server is 10ms, and the timeout on the client is 11, or even 15 to leave some more room, what happens is, server recieves message, waits 10ms, resends it, the client that was suposed to wait another 5ms to complete the 15ms, actually timeout's. Even worse, the server after completeting it's whole process resumes it's initial awaiting-response loop, somehow gives me an error on the recvfrom.
Excuse the huge text but it'd be really hard to summarize all of this without leaving some crutial details out.
Client.c (ignore the broadcast, it's not being used)
#include <winsock.h>
#include <stdio.h>
#define SERV_HOST_ADDR "127.0.0.1"
#define SERV_UDP_PORT 6000
#define PORT_MAX 7000
#define PORT_MIN 1000
#define NUM_IT 10
#define BUFFERSIZE 4096
void Abort(char *msg);
/*________________________________ main _______________________________________
*/
int main(int argc, char *argv[])
{
SOCKET sockfd;
int msg_len, iResult, nbytes, addrlength, local_port;
struct sockaddr_in serv_addr, local;
char buffer[BUFFERSIZE];
WSADATA wsaData;
//broadcast
int broadcast, broadcast_loop;
//timeout
DWORD timeout;// = TIMEOUT;
/*========================= TESTA A SINTAXE =========================*/
if (argc != 9){
fprintf(stderr, "(%d argumentos) Sintaxe: %s -msg \"msg\" -ip ip -port port -timeout microsegundos\n (ordem arbitraria)\n", argc, argv[0]);
exit(EXIT_FAILURE);
}
//tratar os argumentos//
int pos_msg, pos_port, pos_ip, pos_timeout, i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "-msg") == 0)
pos_msg = i + 1;
if (strcmp(argv[i], "-ip") == 0)
pos_ip = i + 1;
if (strcmp(argv[i], "-port") == 0)
pos_port = i + 1;
if (strcmp(argv[i], "-timeout") == 0)
pos_timeout = i + 1;
}
timeout = atol((char*)(LPCTSTR)argv[pos_timeout]); //converter timeout STRING para DWORD
if (strcmp(argv[pos_ip], "255.255.255.255") == 0)
{
broadcast_loop = 1;
broadcast = 1;
}
else
{
broadcast_loop = 0;
broadcast = 0;
}
/*=============== INICIA OS WINSOCKS ==============*/
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
getchar();
exit(1);
}
/*=============== CRIA SOCKET PARA ENVIO/RECEPCAO DE DATAGRAMAS ==============*/
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET)
Abort("Impossibilidade de criar socket");
/*================ CONFIGURA O SOCKET PARA TIMEOUT DE RECEPCAO ==============*/
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
//this call is what allows broadcast packets to be sent:
if (broadcast_loop == 1)
{
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof broadcast) == -1)
{
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
}
/*================= PREENCHE ENDERECO DO SERVIDOR ====================*/
memset((char*)&serv_addr, 0, sizeof(serv_addr)); /*Coloca a zero todos os bytes*/
serv_addr.sin_family = AF_INET; /*Address Family: Internet*/
//serv_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); /*IP no formato "dotted decimal" => 32 bits*/
serv_addr.sin_addr.s_addr = inet_addr(argv[pos_ip]);
//serv_addr.sin_port = htons(SERV_UDP_PORT); /*Host TO Netowork Short*/
serv_addr.sin_port = htons(atoi(argv[pos_port]));
/*====================== ENVIA MENSAGEM AO SERVIDOR ==================*/
msg_len = strlen(argv[pos_msg]);
if (broadcast_loop == 1)
{
//loop sem esperar pelo reenvio
for (int i = 0; i < NUM_IT; i++)
{
for (int pt = PORT_MIN; pt <= PORT_MAX; pt++)
{
serv_addr.sin_port = htons(pt);
if (sendto(sockfd, argv[pos_msg], msg_len, 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
Abort("SO nao conseguiu aceitar o datagram");
printf(" -Enviada mensagem %d (port: %d)\n", i, pt);
//ir buscar a porta gerada automaticamente pare este socket e mostrá-la
addrlength = sizeof(local);
if (getsockname(sockfd, (struct sockaddr *)&local, &addrlength) == 0 && local.sin_family == AF_INET && addrlength == sizeof(local))
{
local_port = ntohs(local.sin_port);
}
printf("<CLI1>Mensagem enviada (port: %d) ... aguardando pelo seu reenvio.\n", local_port);
}
//////// ESPERAR QUE MESMA MENSAGEM SEJA REENVIADA PELO SERVIDOR //////
////nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
////memset((char*)&serv_addr, 0, sizeof(serv_addr));
//addrlength = sizeof(serv_addr);
//nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serv_addr, &addrlength);
//if (nbytes == SOCKET_ERROR)
// Abort("Erro na recepcao da mensagem");
//buffer[nbytes] = '\0'; /*Termina a cadeia de caracteres recebidos com '\0'*/
//printf("\n<CLI1>Mensagem recebida {%s}\n", buffer);
//if (strcmp(inet_ntoa(serv_addr.sin_addr), SERV_HOST_ADDR) == 0 && ntohs(serv_addr.sin_port) == SERV_UDP_PORT)
// printf(" -Mensagem enviada pelo servidor -> %s:%d\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
//else
// printf(" -Mensagem NAO enviada pelo servidor -> %s:%d\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
}
}
else
{
if (sendto(sockfd, argv[pos_msg], msg_len, 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
Abort("SO nao conseguiu aceitar o datagram");
//ir buscar a porta gerada automaticamente pare este socket e mostrá-la
addrlength = sizeof(local);
if (getsockname(sockfd, (struct sockaddr *)&local, &addrlength) == 0 && local.sin_family == AF_INET && addrlength == sizeof(local))
{
local_port = ntohs(local.sin_port);
}
printf("<CLI1>Mensagem enviada (port: %d) ... aguardando pelo seu reenvio (timeout).\n", local_port);
////// ESPERAR QUE MESMA MENSAGEM SEJA REENVIADA PELO SERVIDOR //////
//nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
//memset((char*)&serv_addr, 0, sizeof(serv_addr));
addrlength = sizeof(serv_addr);
nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serv_addr, &addrlength);
if (nbytes == SOCKET_ERROR)
if (WSAGetLastError() != WSAETIMEDOUT)
Abort("Erro na recepcao da mensagem");
else
Abort("Timeout de recepcao");
buffer[nbytes] = '\0'; /*Termina a cadeia de caracteres recebidos com '\0'*/
printf("\n<CLI1>Mensagem recebida {%s}\n", buffer);
if (strcmp(inet_ntoa(serv_addr.sin_addr), SERV_HOST_ADDR) == 0 && ntohs(serv_addr.sin_port) == SERV_UDP_PORT)
printf(" -Mensagem enviada pelo servidor -> %s:%d\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
else
printf(" -Mensagem NAO enviada pelo servidor -> %s:%d\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
}
/*========================= FECHA O SOCKET ===========================*/
closesocket(sockfd);
printf("\n");
system("Pause");
exit(EXIT_SUCCESS);
}
/*________________________________ Abort________________________________________
Mostra uma mensagem de erro e o código associado ao ultimo erro com Winsocks.
Termina a aplicacao com "exit status" a 1 (constante EXIT_FAILURE)
________________________________________________________________________________*/
void Abort(char *msg)
{
fprintf(stderr, "<CLI1>Erro fatal: <%s> (%d)\n", msg, WSAGetLastError());
exit(EXIT_FAILURE);
}
and Server.c
#include <stdio.h>
#include <winsock.h>
#include <Windows.h> //Sleep()
#define SERV_UDP_PORT 6000
#define BUFFERSIZE 4096
void Abort(char *msg);
/*________________________________ main ________________________________________
*/
int main(int argc, char *argv[])
{
SOCKET sockfd;
int iResult, nbytes, msg_len, len;
struct sockaddr_in serv_addr, cli_addr;
char buffer[BUFFERSIZE];
WSADATA wsaData;
/*========================= TESTA A SINTAXE =========================*/
if (argc != 5){
fprintf(stderr, "(%d argumentos) Sintaxe: %s -port port -delay delay\n", argc, argv[0]);
exit(EXIT_FAILURE);
}
//tratar os argumentos//
int pos_port, pos_delay, i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "-port") == 0)
pos_port = i + 1;
if (strcmp(argv[i], "-delay") == 0)
pos_delay = i + 1;
}
/*=============== INICIA OS WINSOCKS ==============*/
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
getchar();
exit(1);
}
/*============ CRIA O SOCKET PARA RECEPCAO/ENVIO DE DATAGRAMAS UDP ============*/
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
Abort("Impossibilidade de abrir socket");
/*=============== ASSOCIA O SOCKET AO ENDERECO DE ESCUTA ===============*/
/*Define que pretende receber datagramas vindos de qualquer interface de
rede, no porto pretendido*/
memset((char*)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; /*Address Family: Internet*/
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*Host TO Network Long*/
serv_addr.sin_port = htons(atoi(argv[pos_port])); /*Host TO Network Short*/
/*Associa o socket ao porto pretendido*/
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR)
Abort("Impossibilidade de registar-se para escuta");
/*================ PASSA A ATENDER CLIENTES INTERACTIVAMENTE =============*/
while (1){
fprintf(stderr, "<SER1>Esperando datagram...\n");
len = sizeof(cli_addr);
//recieve from, tem agora de saber de quem recebeu, para reenviar
nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&cli_addr, &len);
if (nbytes == SOCKET_ERROR)
Abort("Erro na recepcao de datagrams");
buffer[nbytes] = '\0'; /*Termina a cadeia de caracteres recebidos com '\0'*/
printf("<SER1>Mensagem recebida {%s} de %s:%d\n", buffer, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
////// REENVIAR A MENSAGEM AO CLIENTE //////
msg_len = strlen(buffer);
Sleep(atoi(argv[pos_delay])); //sleep de 'delay' milisegundos
if (sendto(sockfd, buffer, msg_len, 0, (struct sockaddr*)&cli_addr, sizeof(cli_addr)) == SOCKET_ERROR)
Abort("SO nao conseguiu aceitar o datagram");
printf("<SER1>Mensagem reenviada.\n\n");
}
system("Pause");
}
/*________________________________ Abort________________________________________
Mostra uma mensagem de erro e o código associado ao ultimo erro com Winsocks.
Termina a aplicacao com "exit status" a 1 (constante EXIT_FAILURE)
________________________________________________________________________________*/
void Abort(char *msg)
{
fprintf(stderr, "<SER1>Erro fatal: <%s> (%d)\n", msg, WSAGetLastError());
printf("\n");
system("Pause");
exit(EXIT_FAILURE);
}
If anyone could make sense out of all this post and provide some helpful answers, i'd greatly appreciate it.

socket programming problems in c

Client code
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
int main ()
{
struct sockaddr_in server ;
struct socklen_t;
int sockid,status,count,count1 ;
char buffer[1024];
char buffer1[1024];
/* socket */
sockid = socket( AF_INET, SOCK_STREAM,0);
if (sockid == -1)
{
printf("could not create socket");
}
else
{
printf(" socket created\n");
}
memset((char *) &server, 0, sizeof(server));
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family =AF_INET;
server.sin_port = htons(20143);
/* connection */
status = connect(sockid ,(struct sockaddr *)&server, sizeof(struct sockaddr));
if (status == -1)
{
printf ("error in connection\n ");
}
else
{
printf("no error \n");
}
/* send*/
strcpy(buffer, "hello \n"),
printf("message: %s\n", buffer);
if(send(sockid, buffer ,strlen("buffer"),0) < 0 )
{
puts("sends failed");
return 1;
}
puts("data send");
/* receive
count1 = recv(sockid,,buf,0 );*/
if(recv(sockid, buffer1, 1024, 0) < 0 )
{
puts("receive failed ");
return 1;
}
puts("receive success");
puts(buffer1);
/*---- Print the received message ----*/
printf("Data received: %s",buffer1);
close (sockid);
}
server code is
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
struct sockaddr_in server ;
struct socklen_t ;
int s,sockid,status;
char buffer[1024];
char buffer1[1024];
/* socket */
sockid = socket(AF_INET, SOCK_STREAM,0);
if(sockid == -1)
{
printf("could not create socket");
}
{
printf(" socket created\n");
}
memset((char *)&server, 0, sizeof(server));
server.sin_addr.s_addr =inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(20143);
if((bind(sockid,(struct sockaddr *)&server, sizeof(struct sockaddr)))== -1)
{
puts("failure ");
return 1;
}
puts("success");
listen(sockid,5);
s = accept(sockid,(struct sockaddr *)&server, (socklen_t *)sizeof(server));
if(recv(sockid,buffer, 1024, 0)< 0 )
{
puts("receive failed ");
return 1;
}
puts("receive success");
puts(buffer1);
/*---- Print the received message ----*/
printf("Data received: %s",buffer);
enter code here
strcpy(buffer1,"Hello World\n");
if(send(sockid,buffer1,13,0) < 0 )
{
puts("failed ");
return 1;
}
puts("success");
close (sockid);
}
here i am trying to make two way connection between client and the server but i am unbale to finish it beacuse i am facing the problem of bind that is server did not bind with the client, every time it show error in binding . plz provide me the sufficient solution for that ..
Here you have a way to do sockets in "C", Comments are in Spanish but I hope it helps.
Link to my Github: https://github.com/MarcosAguayo/sockets-c
Client
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
/**
* Función que usa socket INET para conectarse con un servidor.
* #params char *hostServer, char *service
* #return res
*/
int abrirConexion (char *hostServer, char *service){
struct sockaddr_in dir;
struct servent *puerto;
struct hostent *host;
int res;
puerto = getservbyname (service, "tcp");
if(puerto == NULL) return -1;
host = gethostbyname (hostServer);
if(host == NULL) return -1;
dir.sin_family = AF_INET;
dir.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
dir.sin_port = puerto->s_port;
res = socket (AF_INET, SOCK_STREAM, 0);
if(res == -1) return -1;
if(connect (res, (struct sockaddr *)&dir, sizeof (dir)) == -1){
return -1;
}
return res;
}
/**
* Función para leer los datos del socket. Devuelve el total de bytes que
* ha leído, un -1 si da algun error o un 0 si se cierra.
* #params int fd, char *data, int longitud
* #return total
*/
int leerSocket (int fd, char *data, int longitud){
int total = 0;
int temp = 0;
// Validación de los parámetros de entrada
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
// Bucle que se ejecuta siempre que no hayamos leido todos los datos
while (total < longitud){
temp = read (fd, data + total, longitud - total);
if (temp > 0){
// Si se han leido los datos incrementamos la variable que después devolveremos
total = total + temp;
}else{
// Si devuelve 0, es que se ha cerrado el socket por lo que terminamos u devolvemos total
if (temp == 0) return total;
if (temp == -1){
switch (errno){
case EINTR:
case EAGAIN:
usleep (100);
break;
default:
return -1;
}
}
}
}
return total;
}
/**
* Escribe datos en el socket del cliente y devuelve el total de bytes que ha escrito
* #params int fd, char *data, int longitud
* #return num (Total bytes escritos) o -1
*/
int escribirSocket (int fd, char *data, int longitud){
int num = 0;
int temp = 0;
// Validar los parámetros
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
while (num < longitud){
temp = write (fd, data + num, longitud - num);
if (temp > 0){
num = num + temp;
}else{
if (temp == 0)
return num;
else
return -1;
}
}
return num;
}
/**
* Función MAIN
*/
void main (void){
int socketServer;
char cad[100];
// Abrimos la conexión con el server pasandole "localhost" y el nombre del servicio (/etc/services)
socketServer = abrirConexion ("localhost", "aguayo");
if (socketServer == 1){
printf ("No puedo establecer conexion con el servidor\n");
exit (-1);
}
strcpy(cad, "Hola");
escribirSocket(socketServer, cad, 5);
leerSocket (socketServer, cad, 6);
printf ("Hola buenas soy el cliente y he recibido: %s\n", cad);
close (socketServer);
}
Server
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/**
* Función para aceptar la conexion del socket
* #param int res
* #return int ch
*/
int aceptarConexion (int res){
socklen_t long_cl;
struct sockaddr cl;
int ch;
long_cl = sizeof (cl);
ch = accept (res, &cl, &long_cl);
if (ch == -1)return -1;
return ch;
}
/**
* Función que usa socket INET
* #params char *servicio
* #return res
*/
int abrirConexion (char *servicio){
struct sockaddr_in dir;
struct sockaddr cl;
struct servent *puerto;
socklen_t long_cl;
int res;
res = socket (AF_INET, SOCK_STREAM, 0);
if (res == -1) return -1;
// obtenemos el servicio del fichero /etc/services
puerto = getservbyname (servicio, "tcp");
if (puerto == NULL) return -1;
// Se comletan los campos de la estructura
dir.sin_family = AF_INET;
dir.sin_port = puerto->s_port;
dir.sin_addr.s_addr =INADDR_ANY;
if (bind (res, (struct sockaddr *)&dir, sizeof (dir)) == -1){
close (res);
return -1;
}
if (listen (res, 1) == -1){
close (res);
return -1;
}
return res;
}
/**
* Función para leer los datos del socket. Devuelve el total de bytes que
* ha leído, un -1 si da algun error o un 0 si se cierra.
* #params int fd, char *data, int longitud
* #return num
*/
int leerSocket (int fd, char *data, int longitud){
int num = 0;
int temp = 0;
// Validación de los parámetros de entrada
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
// Bucle que se ejecuta siempre que no hayamos leido todos los datos
while (num < longitud){
temp = read (fd, data + num, longitud - num);
if (temp > 0){
num = num + temp;
}else{
if (temp == 0) return num;
if (temp == -1){
switch (errno){
case EINTR:
case EAGAIN:
usleep (100);
break;
default:
return -1;
}
}
}
}
return num;
}
/**
* Escribe datos en el socket del cliente y devuelve el total de bytes que ha escrito
* #params int fd, char *data, int longitud
* #return total (Total bytes escritos) o -1
*/
int escribirSocket (int fd, char *data, int longitud){
int total = 0;
int temp = 0;
// Validar los parámetros
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
while (total < longitud){
temp = write (fd, data + total, longitud - total);
if (temp > 0){
total = total + temp;
}else{
if (temp == 0) return total;
else return -1;
}
}
return total;
}
/**
* Función MAIN
*/
void main (void){
int socketServer;
int socketClient;
char cad[100];
socketServer = abrirConexion ("aguayo");
if (socketServer == -1){
printf ("No se puede abrir socket servidor\n");
exit (-1);
}
socketClient = aceptarConexion (socketServer);
if (socketServer == -1){
printf ("No se puede abrir socket de cliente\n");
exit (-1);
}
leerSocket (socketClient, cad, 5);
printf ("Soy el Servidor y he recibido: %s\n", cad);
strcpy (cad, "Adios");
escribirSocket (socketClient, cad, 6);
close (socketClient);
close (socketServer);
}

Limit clients that can connect to server

I made a TCP client-server program in C under Linux using select(). I was wondering how can I limit the number of clients that connect to the server. That is if I can before they get accept()-ed.
Here is the code, sorry of the language of comments. I still didn't get where to put that if.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
/* portul folosit */
#define PORT 2728
extern int errno; /* eroarea returnata de unele apeluri */
/* functie de convertire a adresei IP a clientului in sir de caractere */
char * conv_addr (struct sockaddr_in address)
{
static char str[25];
char port[7];
/* adresa IP a clientului */
strcpy (str, inet_ntoa (address.sin_addr));
/* portul utilizat de client */
bzero (port, 7);
sprintf (port, ":%d", ntohs (address.sin_port));
strcat (str, port);
return (str);
}
int v[4]; //vector cu 5 tipuri de mancare
/* programul */
int main ()
{ int nrclienti=0; v[0]=0; v[1]=0; v[2]=0; v[3]=0; v[4]=0;
int inchid=1;
int x,max,pmax;max=v[0];pmax=0;int pref;
struct sockaddr_in server; /* structurile pentru server si clienti */
struct sockaddr_in from;
fd_set readfds; /* multimea descriptorilor de citire */
fd_set actfds; /* multimea descriptorilor activi */
struct timeval tv; /* structura de timp pentru select() */
int sd, client; /* descriptori de socket */
int optval=1; /* optiune folosita pentru setsockopt()*/
int fd; /* descriptor folosit pentru
parcurgerea listelor de descriptori */
int nfds; /* numarul maxim de descriptori */
int len; /* lungimea structurii sockaddr_in */
/* creare socket */
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server] Eroare la socket().\n");
return errno;
}
/*setam pentru socket optiunea SO_REUSEADDR */
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,&optval,sizeof(optval));
/* pregatim structurile de date */
bzero (&server, sizeof (server));
/* umplem structura folosita de server */
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
/* atasam socketul */
if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server] Eroare la bind().\n");
return errno;
}
/* punem serverul sa asculte daca vin clienti sa se conecteze */
if (listen (sd, 5) == -1)
{
perror ("[server] Eroare la listen().\n");
return errno;
}
/* completam multimea de descriptori de citire */
FD_ZERO (&actfds); /* initial, multimea este vida */
FD_SET (sd, &actfds); /* includem in multime socketul creat */
tv.tv_sec = 1; /* se va astepta un timp de 1 sec. */
tv.tv_usec = 0;
/* valoarea maxima a descriptorilor folositi */
nfds = sd;
printf ("[server] Asteptam la portul %d...\n", PORT);
fflush (stdout);
/* servim in mod concurent clientii... */
while (inchid)
{ /* ajustam multimea descriptorilor activi (efectiv utilizati) */
bcopy ((char *) &actfds, (char *) &readfds, sizeof (readfds));
/* apelul select() */
if (select (nfds+1, &readfds, NULL, NULL, &tv) < 0)
{
perror ("[server] Eroare la select().\n");
return errno;
}
/* vedem daca e pregatit socketul pentru a-i accepta pe clienti */
if (FD_ISSET (sd, &readfds))
{
/* pregatirea structurii client */
len = sizeof (from);
bzero (&from, sizeof (from));
/* a venit un client, acceptam conexiunea */
client = accept (sd, (struct sockaddr *) &from, &len);
/* eroare la acceptarea conexiunii de la un client */
if (client < 0)
{
perror ("[server] Eroare la accept().\n");
continue;
}
if (nfds < client) /* ajusteaza valoarea maximului */
nfds = client;
printf("[server] S-a conectat clientul cu descriptorul %d, de la adresa %s.\n",client, conv_addr (from));
/* includem in lista de descriptori activi si acest socket */
FD_SET (client, &actfds);
fflush (stdout);
}
/* vedem daca e pregatit vreun socket client pentru a trimite raspunsul */
for (fd = 0; fd <= nfds; fd++) /* parcurgem multimea de descriptori */
{
/* este un socket de citire pregatit? */
if (fd != sd && FD_ISSET (fd, &readfds))
{ //func
char buffer[100]; /* mesajul */
int bytes; /* numarul de octeti cititi/scrisi */
char msg[100]; //mesajul primit de la client
char msgrasp[100]; //mesaj de raspuns pentru client
int replies=0;
do
{
//citim mesajul de la client
bytes = read (fd, msg, sizeof (buffer));
if (bytes < 0)
{
perror ("Eroare la read() de la client.\n");
return 0;
}
printf ("[server]Clientul cu descriptorul %d a ales mancarea %s\n",fd, msg);
int poz; //comanda alease introdusa in vectorul de comenzi
poz = msg[0] - '0';
v[poz-1]++;
//decidem felul preferat din meniu
printf("[server]");
for(x=0;x<=4;x++)
if (max<v[x]) {max=v[x];pmax=x;}
pref=pmax+1;
for(x=0;x<=4;x++) printf("%d|",v[x]);
printf(" Val max e %d\n",pref);
/*pregatim mesajul de raspuns */
bzero(msgrasp,100);
sprintf(msgrasp, "%d", pref);
//daca clientului corespunde cu mancarea favorita, trimitem raspunsul
if (msg[0]==msgrasp[0]) sprintf(msgrasp, "%d", 1);
else sprintf(msgrasp, "%d", 0);
printf("[server]Trimitem %s clientului %d\n",msgrasp,fd);
if (bytes && write (fd, msgrasp, bytes) < 0)
{
perror ("[server] Eroare la write() catre client.\n");
return 0;
}
//func
replies++;
}while((msgrasp[0]!=49)&&(replies<3));
printf ("[server] S-a deconectat clientul cu descriptorul %d.\n\n",fd);
fflush (stdout);
close (fd); /* inchidem conexiunea cu clientul */
FD_CLR (fd, &actfds);/* scoatem si din multime */
}
} /* for */
} /* while */
close(sd);} /* main */
I'm going to assume that you are running a non-threaded non-forking application using select(). If not, then the you will need to modify this a little but not much.
Prior to select(), you will be adding each of your fd's corresponding to an open session to your fd_set using FD_SET; you can count these whilst you loop through. You will also add your listener fd. Simply omit this second step if the number of open connections is at its maximum.
Note that open connections may still be accepted later - see how backlog works on listen().
Well, if you don't need a client you may not accept() him :) Thus you may limit the number of clients currently being processed. Just ignore events on your master socket and you've done.
Also you can limit the size of the queue for clients not been accepted yet using TCP backlog, notice the second parameter of listen()
But typically it's not quite, ehmm, polite. Maybe you should re-think your entire task and decide how to handle more clients simultaneously.

Resources