Related
I want to implement an UDP server that works with three threads (over three port) that do the same thing. In one thread each there is a parent and a child: parent waiting for requests from the client, child increment a variable. When parent receive the request, it send a signal (SIGUSR1) to the pid of the child (to try, I use parentpid+1). Child by default increment the variable, by SIGUSR1 write something (for example: "I'm in sigurs1"), but actually I want also to send the status of the variable to the main thread. Howevere, this is the code:
/**
#defgroup Group4 UDP Client and Server
#brief UDP/IPv4 Client and Server
#{
*/
/**
#file UDPServer.c
#author Catiuscia Melle
#brief Presentazione di un UDP Echo Server IPv4.
Il server, in un ciclo infinito:
- riceve un messaggio
- lo re-invia in echo.
*/
#include "Header.h"
//### PRIMA DI TUTTO INCLUDIAMO LA LIBRERIA PER I SEGNALI
#include <signal.h>
void *thread_function(void *arg);
int stock = 0;
//### Il sigset_t viene utilizzato per rappresentare un signal set
sigset_t mask;
int main(){
printf("\tIPv4 UDP Server app\n");
int port1 = PORT, port2 = PORT2, port3 = PORT3;
//INITIALITE THREAD AND VARIABLES FOR THREAD
int thres; //response of the thread
pthread_t a_thread, a_thread2, a_thread3;
void *thread_result;
//CREATE THREAD 1
thres = pthread_create(&a_thread, NULL, thread_function, &port1);
if (thres != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
//CREATE THREAD 2
thres = pthread_create(&a_thread2, NULL, thread_function, &port2);
if (thres != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
//CREATE THREAD 3
thres = pthread_create(&a_thread3, NULL, thread_function, &port3);
if (thres != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
thres = pthread_join(a_thread, &thread_result);
if (thres != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
thres = pthread_join(a_thread2, &thread_result);
if (thres != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
thres = pthread_join(a_thread3, &thread_result);
if (thres != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
return 0;
}
void *thread_function(void *arg) {
pid_t pid;
int parentpid = getpid();
printf("Il pid della thread vale %d\n",parentpid);
int port = *((int *) arg);
//### Nella variabile signo salverò il numero di segnale che mi restituisce la wait
int err, signo;
printf("Porta %d\n",port);
printf("ENTER TO THREAD\n");
int res = 0; //valore di ritorno delle APIs
/*
socket: servirà per la comunicazione col server
*/
int sockfd = 0;
/*
open socket di tipo datagram
*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("socket error: ");
return FAILURE;
}
/*
indirizzo IPv4 del server, senza hostname resolution
*/
struct sockaddr_in server;
socklen_t len = sizeof(server);
memset(&server, 0, sizeof(server)); //azzero la struttura dati
server.sin_family = AF_INET; //specifico l'Address Family IPv4
/*
Specifico l'indirizzo del server: qualsiasi interfaccia
*/
server.sin_addr.s_addr = htonl(INADDR_ANY);
/*
Specifico la well-known port
*/
server.sin_port = htons(port);
//setto l'indirizzo well-known del socket
res = bind(sockfd, (struct sockaddr *)&server, len);
if (res == -1)
{
perror("Bind error: ");
close(sockfd);
exit(1);
}//fi
ssize_t n = 0;
char buffer[BUFSIZE];
struct sockaddr_in client;
char address[INET_ADDRSTRLEN] = "";
int quit = 0;
if ((pid = fork()) < 0) {
printf("Fork error<n");
} else if (pid == 0) { /* child */
printf("child dal pid %d\n",getpid());
while(1){
//### La sigwait non fa che attendere l'arrivo di un segnale
err = sigwait(&mask, &signo);
//### Una volta terminata la sigwait, ossia quando ha ricevuto un segnale
//(se no è successo un errore), possiamo switchare il segnale arrivato, che
//è salvato in signo
switch (signo) {
//### Ora gestisco, se gli ho mandato un SIGUSR1, ossia un flag che, arrivato
//a destinazione indica di eseguire quel segnale che il processo che lo riceve
//lo implementa come vuole. Si sa che si deve eseguire quel segnale, di libera
//interpretazione
case SIGUSR1:
printf("Sigusr1\n");
printf("Stock vale %d\n",stock);
break;
//### In caso gli mandassi SIGINT, valuta sempre se ci sono errori e poi esci
case SIGINT:
printf("Sigint\n");
//### Di default comunque, controlla se ci sono errori e poi esci
default:
stock++;
printf("Sto producendo %d dalla porta %d\n",stock, port);
sleep(2);
}
}
} else {
printf("parent dal pid %d\n",getpid()); /* parent */
while (!quit)
{
printf("Main thread entrato nel ciclo\n");
n = recvfrom(sockfd, buffer, BUFSIZE-1, 0, (struct sockaddr *)&client, &len);
printf("Mando segnali");
//### Inizializza il segnale settato set a escludere tutti i segnali definiti
sigemptyset(&mask);
//### Aggiunge il segnale signum al segnale settato set. Con sigaddset modifichiamo
//set, ma non blocchiamo o sblocchiamo alcun segnale!
//Mettiamoli quindi SIGURS1
sigaddset(&mask, SIGUSR1);
//### E anche SIGINT
sigaddset(&mask, SIGINT);
//### pthread_sigmask esamina e cambia segnali bloccati. Con SIG_BLOCK il set
//risultante è l'unione del set corrente e il set di segnale indicato da set
if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)
{
fprintf(stderr, "thread mask failed\n");
exit(EXIT_FAILURE);
}
kill(parentpid+1,SIGUSR1);
printf("Segnale inviato al pid %d\n",(parentpid+1));
if (n == -1)
{
perror("recvfrom() error: ");
continue;
// close(sockfd);
// return FAILURE;
}
}//wend
printf("Stockmann %d\n",stock);
//qui non ci arrivo mai...
close(sockfd);
}
return NULL;
}
/** #} */
this is Header.h (but it's not necessary to see it)
/**
#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>
//THIS FOR RAND FUNCTION
#include <stdlib.h>
#include <time.h>
//THIS FOR THREADS
#include <pthread.h>
#define PORTNUMBER 49152 /**< UDP listening port, decimal */
#define PORT 49152 /**< UDP listening port, decimal */
#define PORT2 49153 /**< UDP listening port, decimal */
#define PORT3 49154 /**< UDP listening port, decimal */
#define SERVICEPORT "49152" /**< UDP 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 */
#define SEMAPHORE_NAME "gbrunetta317"
#endif /* __HEADER_H__ */
/** #} */
The problem is that when I send something with the client, the value inside case: Sigurs1 doesn't appear:
Actually, it doesn't returns nothing from the SIGUSR1 defined in child, but you can see that it stop that process (in fact you can see that it doesn't work again with port 49512, because pidparent+1 is associated with that port). I hope I was clear. How I can solve it?
I discovered that it fail with shmat.. I don't know why, but I rewrite the code according with this example: How to trigger SIGUSR1 and SIGUSR2?
And now it works fine.
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.
I'm trying to do an echo server using SSL and verifying certificates of both sides. The socket connection seems to work perfectly but the SSL_Accept on the server returns error. The error is:
CONEXION: 127.0.0.1:55387 3073529532:error:140890B2:SSL routines: \
SSL3_GET_CLIENT_CERTIFICATE:no certificate returned:s3_srvr.c:3283:
This is the client code:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//carga los certificados como en el servidor
void CargaCertificados(SSL_CTX* ctx, char* CertFile, char* KeyFile){
/* setea el certificado local */
if (SSL_CTX_use_certificate_file(ctx, CertFile , SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
abort();
}
/* setea la clave privada */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 ){
ERR_print_errors_fp(stderr);
abort();
}
/* verifica la clave prievada */
if ( !SSL_CTX_check_private_key(ctx) ){
fprintf(stderr, "la clave privada no coincide con el certificado publico\n");
abort();
}
}
//conecta el socket como en las practicas anteriores
int ConectaSocket(const char *hostname, int port){
int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL ){
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ){
close(sd);
perror(hostname);
abort();
}
return sd;
}
//inicializa el contexto a traves de una instancia
SSL_CTX* InitCTX(void){
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* carga los cifrados etc */
SSL_load_error_strings(); /* carga los mensajes de error */
ctx = SSL_CTX_new(SSLv23_client_method()); /* crea un nuevo contexto con la instancia del cliente*/
if ( ctx == NULL ){
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
//muestra los certificados
void MuestraCertificados(SSL* ssl){
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* coge el certificado del servidor */
if ( cert != NULL ){
printf("CERTIFICADOS EN EL CLIENTE:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("SUJETO: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("EMISOR: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("NO EXISTEN CERTIFICADOS.\n");
}
int main(int argc, char*argv[]){
SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
char msg[100];
if(argc != 4)
return -1;
SSL_library_init();
ctx = InitCTX();
CargaCertificados(ctx, argv[2], argv[3]);
server = ConectaSocket("localhost", atoi(argv[1]));
ssl = SSL_new(ctx); /* crea el estado de conexion SSL */
SSL_set_fd(ssl, server); /* setea el socket a conexion ssl */
if ( SSL_connect(ssl) < 0 ) /* conecta con el servidor */
ERR_print_errors_fp(stderr);
else{
printf("CONECTADO CON ENCRIPTACION %s\n\n", SSL_get_cipher(ssl));
MuestraCertificados(ssl); /* muestra los certificados */
printf("\nMANDAS: ");
scanf("%s", msg);
SSL_write(ssl, msg, strlen(msg)); /* encripta y manda el mensaje */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* obtiene respuesta y desencripta */
buf[bytes] = 0;
printf("RECIBO: %s\n", buf);
SSL_free(ssl); /* libera el estado de conexion */
}
close(server); /* cierra el socket */
SSL_CTX_free(ctx); /* libera el contexto */
return 0;
}
and the server code:
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
int CreaEscuchador(int port){
int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("no se puede vincular puerto");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("no se puede configurar puerto de escucha");
abort();
}
return sd;
}
SSL_CTX* InitServerCTX(void){
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* carga y registra todos los cifrados etc */
SSL_load_error_strings(); /* carga todos los mensajes de error */
ctx = SSL_CTX_new(SSLv23_server_method()); /* crea un contexto para la instancia del servidor */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void CargarCertificados(SSL_CTX* ctx, char* CertFile, char* KeyFile){
if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
ERR_print_errors_fp(stderr);
/* setea el certificado local a traves de CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile , SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
abort();
}
/* setea la clave privada a traves de keyFile (puede ser igual que certfile) */
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0){
ERR_print_errors_fp(stderr);
abort();
}
/* verifica la clave privada */
if (!SSL_CTX_check_private_key(ctx)){
fprintf(stderr, "la clave privada no coincide con el certificado publico\n");
abort();
}
//fuerza al cliente a tener un certificado
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
}
void MuestraCertificados(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* obtiene los certificados */
if ( cert != NULL )
{
printf("CERTIFICADOS EN EL SERVIDOR:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("SUJETO: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("EMISOR: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("NO EXISTEN CERTIFICADOS.\n");
}
void Servlet(SSL* ssl) /* servicio del servidor */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* echo="%s\n";
if ( SSL_accept(ssl) < 0 ) /* hace el accept ssl */
ERR_print_errors_fp(stderr);
else
{
MuestraCertificados(ssl); /* muestra los certificados */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* recibe el mensaje */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("RECIBO: %s\n", buf);
sprintf(reply, echo, buf); /* contruyo la respuesta */
SSL_write(ssl, reply, strlen(reply)); /* mando la respuesta */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* coge la conexion del socket */
SSL_free(ssl); /* libera la conexion ssl */
close(sd); /* cierra la conexion */
}
int main(int argc, char*argv[])
{ SSL_CTX *ctx;
int server;
if(argc != 4)
return -1;
SSL_library_init();
ctx = InitServerCTX(); /* inicilaiza SSL */
CargarCertificados(ctx, argv[2], argv[3]); /* carga los certificados */
server = CreaEscuchador(atoi(argv[1])); /* crea el escuchador */
while (1){
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* acepta la conexion como siempre */
printf("CONEXION: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* coge le nuevo estado ssl con el contexto */
SSL_set_fd(ssl, client); /* setea el socket a conexion ssl */
Servlet(ssl); /* servicio del servidor */
}
close(server); /* cierra el socket */
SSL_CTX_free(ctx); /* libera el contexto */
}
to generate my certificates I use a root certificate:
openssl genrsa -out rootkey.pem 2048
openssl req -new -x509 -key rootkey.pem -out rootcert.pem
then I create a client and a server cert:
openssl genrsa -out clientkey.pem 2048
openssl req -new -key clientkey.pem -out client_solicit.csr
openssl x509 -req -CAcreateserial -in client_solicit.csr -CA rootcert.pem -CAkey rootkey.pem -out clientcert.pem
//same lines to server cert
done! the arguments of SSL_CTX_load_verify_locations were wrong. The cert file points to a file of CA certificates in PEM format.
SSL_CTX_load_verify_locations(ctx, "rootcert.pem", "rootkey.pem") != 1)
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);
}
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.