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.
Related
I'm studying sockets and client server communication with select. My problem is that at line 261 i get the Bad File Descriptor error and I have no idea why. The message on line 233 arrives to the client, in the one after (line 252) the client instead of receiving the size in bytes receives 0, and in the write after (line 261) I get the error. I'm really confused.
This is the SERVER
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define DIM_BUFF 100
#define max 10
#define mass(a, b) ((a) > (b) ? (a) : (b))
/********************************************************/
void gestore(int signo) {
int stato;
printf("esecuzione gestore di SIGCHLD\n");
wait(&stato);
}
/********************************************************/
//STRUTTURA DATI
typedef struct{
char Targa[max];
int Patente;
char Tipo[max];
char Folder[max];
}Prenotazione;
//REQUEST DATAGRAM
typedef struct{
char Targa[max];
int newPatente[max];
}Request;
int main(int argc, char **argv) {
//inizializziamo struttura
Prenotazione pren[3];
//dati mock
strcpy(pren[0].Targa,"ciao1");
pren[0].Patente=1234;
strcpy(pren[0].Tipo,"tipo1");
strcpy(pren[0].Folder,"prova1");
strcpy(pren[1].Targa,"ciao2");
pren[1].Patente=1234;
strcpy(pren[1].Tipo,"tipo2");
strcpy(pren[1].Folder,"prova2");
strcpy(pren[2].Targa,"ciao3");
pren[2].Patente=1234;
strcpy(pren[2].Tipo,"tipo3");
strcpy(pren[2].Folder,"prova3");
printf("struttura dati inizializzata!!\n");
int listenfd, connfd, udpfd, nready, maxfdp1;
const int on = 1;
FILE* fd_file;
char zero = '\0' ,Targa[max],fileName[20],path[128];
int buff[DIM_BUFF];
fd_set rset;
int len, nread, nwrite, num, port,count=0;
long size;
struct sockaddr_in cliaddr, servaddr;
Request *req = (Request *)malloc(sizeof(Request));
DIR *dir1;
struct dirent *dd1;
/* CONTROLLO ARGOMENTI ---------------------------------- */
if (argc != 2) {
printf("Error: %s port\n", argv[0]);
exit(1);
}
nread = 0;
while (argv[1][nread] != '\0') {
if ((argv[1][nread] < '0') || (argv[1][nread] > '9')) {
printf("porta non intero\n");
exit(2);
}
nread++;
}
port = atoi(argv[1]);
if (port < 1024 || port > 65535) {
printf("Porta scorretta...");
exit(2);
}
/* INIZIALIZZAZIONE INDIRIZZO SERVER ----------------------------------------- */
memset((char *)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(port);
printf("Server avviato\n");
/* CREAZIONE SOCKET TCP ------------------------------------------------------ */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0) {
perror("apertura socket TCP ");
exit(1);
}
printf("Creata la socket TCP d'ascolto, fd=%d\n", listenfd);
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
perror("set opzioni socket TCP");
exit(2);
}
printf("Set opzioni socket TCP ok\n");
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind socket TCP");
exit(3);
}
printf("Bind socket TCP ok\n");
if (listen(listenfd, 5) < 0) {
perror("listen");
exit(4);
}
printf("Listen ok\n");
/* CREAZIONE SOCKET UDP ------------------------------------------------ */
udpfd = socket(AF_INET, SOCK_DGRAM, 0);
if (udpfd < 0) {
perror("apertura socket UDP");
exit(5);
}
printf("Creata la socket UDP, fd=%d\n", udpfd);
if (setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
perror("set opzioni socket UDP");
exit(6);
}
printf("Set opzioni socket UDP ok\n");
if (bind(udpfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind socket UDP");
exit(7);
}
printf("Bind socket UDP ok\n");
/* AGGANCIO GESTORE PER EVITARE FIGLI ZOMBIE -------------------------------- */
signal(SIGCHLD, gestore);
/* PULIZIA E SETTAGGIO MASCHERA DEI FILE DESCRIPTOR ------------------------- */
FD_ZERO(&rset);
maxfdp1 = mass(listenfd, udpfd) + 1;
/* CICLO DI RICEZIONE EVENTI DALLA SELECT ----------------------------------- */
for (;;) {
FD_SET(listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
else {
perror("select");
exit(8);
}
}
//GESTIONE RICHIESTE CAMBIO NUMERO PATENTE--------------------
if (FD_ISSET(udpfd, &rset)) {
int result=-1;
printf("Server: ricevuta richiesta di cambio numero patente\n");
len = sizeof(struct sockaddr_in);
if (recvfrom(udpfd, req, sizeof(Request), 0, (struct sockaddr *)&cliaddr, &len) <
0) {
perror("recvfrom");
continue;
}
printf("targa: %s \n", req->Targa);
printf("nuovo numero patente: %s \n", req->newPatente);
for(int i=0;i<3 && result==-1;i++){
if(strcmp(req->Targa,pren[i].Targa)==0){
pren[i].Patente=*req->newPatente;
result=0;
}
}
printf("cambio numero patente effettuato!, invio risposta... \n");
if (sendto(udpfd, &result, sizeof(result), 0, (struct sockaddr *)&cliaddr, len) < 0) {
perror("sendto");
continue;
}
}//IF UDP
//GESTIONE RICHIESTE SCARICAMENTO IMMAGINI
if (FD_ISSET(listenfd, &rset)) {
printf("Ricevuta richiesta di get di un file\n");
len = sizeof(struct sockaddr_in);
if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len)) < 0) {
if (errno == EINTR)
continue;
else {
perror("accept");
exit(9);
}
}
if (fork() == 0) { /* processo figlio che serve la richiesta di operazione */
close(listenfd);
printf("Dentro il figlio, pid=%i\n", getpid());
char Fold[max];
int trovato=-1;
while ((nread = read(connfd, &Targa, sizeof(Targa))) > 0) {
printf("Server (figlio): targa richiesta: %s\n", Targa);
for(int i=0;i<3;i++){
if(strcmp(Targa,pren[i].Targa)==0){
strcpy(Fold,pren[i].Folder);
trovato=i;
}
}
if(trovato>=0){
dir1 = opendir(Fold);
while ((dd1 = readdir(dir1)) != NULL) {
if (strcmp(dd1->d_name, ".") != 0 && strcmp(dd1->d_name, "..") != 0) {
strcpy(fileName, dd1->d_name);
if (write(connfd, fileName,(strlen(fileName) + 1)) < 0) {
perror("Errore nell'invio del nome file\n");
continue;
}
path[0] = '\0'; //path reset
sprintf(path, "%s/%s", pren[trovato].Folder, dd1->d_name);
fd_file = fopen(path, "rb");
if (fd_file < 0) {
printf("ERRORE Apertura FILE\n");
}
fseek(fd_file, 0, SEEK_END);
size=ftell(fd_file);
fseek(fd_file, 0, SEEK_SET);
printf("le dimensioni sono: %ld" ,size);
//invio la dimensione
if (write(connfd, &size,sizeof(long))< 0) {
perror("Errore nell'invio della dimensione file\n");
exit(0);
}
/* lettura dal file (a blocchi) e scrittura sulla socket */
printf("Leggo e invio il file richiesto\n");
while (count<size) {
nread = fread(buff, sizeof(int), sizeof(buff),fd_file);
if (nwrite = write(connfd, buff, sizeof(buff)) < 0) {
perror("write");
break;
}
bzero(buff, sizeof(buff));
count=count+nread;
}
printf("Terminato invio file\n");
fclose(fd_file);
}
}//while DD1
strcpy(fileName,"fine");
if (write(connfd, fileName,(strlen(fileName) + 1)) < 0) {
perror("Errore nell'invio del nome file\n");
continue;
}
printf("Terminato invio di tutti i file\n");
closedir(dir1);
}//if trovato
else{
strcpy(fileName,"errore");
if (write(connfd, fileName,(strlen(fileName) + 1)) < 0) {
perror("Errore nell'invio del nome file\n");
continue;
}
}
}//while richieste
printf("Figlio TCP terminato, libero risorse e chiudo. \n");
close(connfd);
exit(0);
}//FORK
sleep(1);
close(connfd); //padre chiude la socket(non di ascolto)
}//IF TCP
}//for SELECT
}//main
this is the CLIENT
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define DIM_BUFF 100
#define LENGTH_FILE_NAME 20
int main(int argc, char *argv[]) {
int sd, nread, port,count=0;
char nome_file[LENGTH_FILE_NAME],Targa[10];
struct hostent *host;
struct sockaddr_in servaddr;
int c;
long size;
/* CONTROLLO ARGOMENTI ---------------------------------- */
if (argc != 3) {
printf("Error:%s serverAddress serverPort\n", argv[0]);
exit(1);
}
printf("Client avviato\n");
/* PREPARAZIONE INDIRIZZO SERVER ----------------------------- */
memset((char *)&servaddr, 0, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
host = gethostbyname(argv[1]);
if (host == NULL) {
printf("%s not found in /etc/hosts\n", argv[1]);
exit(2);
}
nread = 0;
while (argv[2][nread] != '\0') {
if ((argv[2][nread] < '0') || (argv[2][nread] > '9')) {
printf("Secondo argomento non intero\n");
exit(2);
}
nread++;
}
port = atoi(argv[2]);
if (port < 1024 || port > 65535) {
printf("Porta scorretta...");
exit(2);
}
servaddr.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
servaddr.sin_port = htons(port);
/* CREAZIONE E CONNESSIONE SOCKET (BIND IMPLICITA) ----------------- */
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) {
perror("apertura socket ");
exit(3);
}
printf("Creata la socket sd=%d\n", sd);
if (connect(sd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) {
perror("Errore in connect");
exit(4);
}
printf("Connect ok\n");
//inizio ciclo richieste
printf("numero della targa o EOF: \n");
while (gets(Targa)) {
if (write(sd, Targa, (strlen(Targa) + 1)) < 0) {
perror("write");
continue;
}
printf("Richiesta della targa %s inviata... \n", Targa);
//ricezione nome file ogni volta
if (read(sd, &nome_file, sizeof(nome_file)) < 0) {
perror("read");
break;
}
while(strcmp(nome_file,"fine")!=0 ){
FILE* f;
printf("il nome del file: %s \n" ,nome_file);
if (read(sd, &size, sizeof(long)) < 0) {
perror("read");
break;
}
if(size==0){
printf("size 0");
exit(1);
}
printf("la size e': %ld" ,size);
f=fopen(nome_file,"wb");
while (count<size){
nread = read(sd, &c, 1);
fwrite(&c,sizeof(int),1,f);
count=count+nread;
}
fclose(f);
printf("immagine ricevuta\n");
if (read(sd, &nome_file, sizeof(nome_file)) < 0) {
perror("read");
break;
}
}
if(strcmp(nome_file,"fine")==0){
printf("tutte le immaigini ricevute\n");
printf("numero della targa o EOF: \n");
}
else{
printf("ERRORE PROTOCOLLO\n");
shutdown(sd, 0);
shutdown(sd, 1);
close(sd);
exit(0);
}
}//whilw
printf("\nClient: termino...\n");
shutdown(sd, 0);
shutdown(sd, 1);
close(sd);
exit(0);
}//main
I've literally tried everything but it doesn't seem to work.
Thanks for your time and sorry form my bad english.
this is my code for the server so far:
a function that finds if a word is in a file:
int Search_in_File_name(char *fname, char *str) {
FILE *fp;
int line_num = 1;
int find_result = 0;
char temp[512];
if((fp = fopen(fname, "r")) == NULL) {
return(-1);
}
while(fgets(temp, 512, fp) != NULL) {
if((strstr(temp, str)) != NULL) {
//printf("\n[copil] logare reusita");
find_result++;
}
line_num++;
}
if(find_result == 0) {
//printf("\nnume incorect");
fclose(fp);
return(3);
}
//Close the file if still open.
if(fp) {
fclose(fp);
}
return(4);
}
and main where i have to look see if a client logs in before doing something else. I used fork for every client that connects to the server. I want to create a file in my project directory for every client and i need the number of the client to do that( or the port specified by "ntohs(newAddr.sin_port)" but i can't obtain the number of the client because i can't declare any int variables.
int main(){
int sockfd, ret;
struct sockaddr_in serverAddr;
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Server Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); //asociaza adresa serverAddr(localhost) la socketul creat (sockfd)
if(ret < 0){
printf("[-]Error in binding.\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
if(listen(sockfd, 10) == 0){ //marcheaza socketul (sockfd) ca fiind socketul care va accepta o conexiune viitoare si limita maxima de conexiuni in asteptare
printf("[+]Listening....\n");
}else{
printf("[-]Error in binding.\n");
}
while(1){
newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size); //ia prima conexiune din lista asociata lui sockfd prin listen si creaza un nou socket si returneaza un descriptor de fisier pentru acel nou socket
if(newSocket < 0){
exit(1);
}
printf("Connection accepted from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
int i=0;
if((childpid = fork()) == 0){
close(sockfd);
int ok=0;
char* nume_fisier;
while(1){
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, ":exit") == 0){
printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
break;
}else if(strncmp(c1, buffer, strlen(c1))==0 && ok ==0){
int lungCom, lungNume;
char name[lungNume];
lungCom=strlen(buffer); //lungimea comenzii
lungNume=lungCom-strlen(c1); //lungimea numelui
name[lungNume]='\0';
strncpy(name,&buffer[lungCom-lungNume],lungNume);//pun numele din comanda in variabia name
printf("\n[copil] asta e numele: %s ", name);
printf("\n[copil] %s", w1);
if(Search_in_File_name("nume.txt", name)==4){// daca am gasit numele in lista
i=i+1;
printf("----%d----",i);
send(newSocket, v1, strlen(v1), 0);
bzero(buffer, sizeof(buffer));
ok=1;
printf("\n[copil] am trimis mesajul: %s \n", v1);
}else{ // daca nu am gasit numele in lista
send(newSocket, v2, strlen(v2), 0);
printf("\n[copil] am trimis mesajul: %s \n", v2);
bzero(buffer, sizeof(buffer));
}
}else if(strcmp(buffer, "logout")==0 && ok == 1){
printf("incercare delogare de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
printf("delogat de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
ok=0;
printf("Client: %s\n", buffer);
send(newSocket, d1, strlen(d1), 0);
bzero(buffer, sizeof(buffer));
}else if(strcmp(buffer, "logout")==0 && ok == 0){
printf("incercare delogare de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
printf("Client: %s\n", buffer);
send(newSocket, d2, strlen(d2), 0);
bzero(buffer, sizeof(buffer));
}else if(strcmp(buffer, "cos")==0 && ok == 1){
printf("incercare creare cos de la %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
printf("Client: %s\n", buffer);
printf("----%d---:", ntohs(newAddr.sin_port));
//nume_fisier=creare_cos_client(nume_client);
//printf("---nume_fisier: %s", nume_fisier);
send(newSocket, cos1, strlen(cos1), 0);
bzero(buffer, sizeof(buffer));
}else{
printf("Client: %s\n", buffer);
send(newSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(newSocket);
return 0;
}
If i delete that "int i=0; " before the fork my program works fine but as soon as i add it back(anywhere) the client can't take any input and the server doesn't check if the name is in the file or not.
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, ":exit") == 0){
Two mistakes here:
You ignore the return value of recv. So you have no idea how many bytes you received. How can you do anything useful with some data if you have no idea how much data you have?
You can only pass a C-style string to strcmp. At this point, buffer only contains the raw data you received from the other side. It isn't a C-style string because, by definition, a C-style string has a terminating zero byte.
You have another more fundamental problem though -- your use of strcmp suggests you think you are using a message protocol and have received a message. But you are using TCP and TCP is not a message protocol.
It's hard to say precisely why adding int i =0; saves you from crashing or freezing. But my guess is that the zero just happens to be stored in memory after the buffer and so, by luck, provides the terminating zero byte that strcmp requires. But that's just a guess.
I googled and stack-overflowed a lot but didn't find any solution. I have a simple echo client-server program in which client sends a word and the server echoes it.
This is my server.c file:
#define PORT 4444
#define MAX_CONNESSIONI 100
int main ()
{
int serverSocket, bindStatus;
struct sockaddr_in serverAddress;
int clientSocket;
struct sockaddr_in newAddress;
char buffer[1024];
pid_t child;
socklen_t addrSize;
ssize_t nread;
// Creazione della socket
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Echo-Server socket has been created\n");
memset(&serverAddress, '\0', sizeof(serverAddress));
// Riempimento dei campi della struct
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
// Binding della socket all'indirizzo specificato. Associa alla socket un indirizzo in modo da poter essere contattata dai client
if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("[-]Errore durante il binding\n");
exit(1);
}
printf("[+]Bind to port %d\n", PORT);
// Imposta la socket all'ascolto. I parametri sono il descrittore della socket e la massima lunghezza della coda di connessioni entranti
if (listen(serverSocket, MAX_CONNESSIONI) != -1) {
printf("Listening . . .\n\n");
}
else {
perror("[-]Error during listening\n");
exit(1);
}
while (1) {
// Accettazione della connessione
clientSocket = accept(serverSocket, (struct sockaddr*)&newAddress, &addrSize);
if (clientSocket == -1) {
exit(-1);
}
printf("%s:%d joined\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
child = fork();
if (child == 0) {
close(serverSocket);
while (1) {
// Ricezione del messaggio
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
}
if (strcmp(buffer, ":exit") == 0) {
printf("%s:%d left\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port));
break;
}
else {
printf("%s:%d wrote: %s\n", inet_ntoa(newAddress.sin_addr), ntohs(newAddress.sin_port), buffer);
// Invio del messaggio
send(clientSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(clientSocket);
return 0;
}
you can compile it using
gcc -o server.out server.c
and execute it using
./server.out
and this is my client.c file:
#define PORT 4444
int main ()
{
int clientSocket;
struct sockaddr_in serverAddress;
char buffer[1024];
ssize_t nread;
// Creazione della socket
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("[-]Errore durante la creazione della socket\n");
exit(-1);
}
printf("[+]Client socket has been created\n");
memset(&serverAddress, '\0', sizeof(serverAddress));
// Riempimento dei campi della struct
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = INADDR_ANY;
// Connessione
if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
perror("Errore con la connessione\n");
exit(-1);
}
printf("[+]Connected to Server\n");
printf("[+]Use single-word and :exit to logout\n");
while (1) {
printf("> ");
//fgets(buffer, 1024, stdin); Per ottenere una stringa con gli spazi
fflush(stdin);
scanf("%s", buffer);
// Invio dei dati al server
if (send(clientSocket, buffer, strlen(buffer), 0) == -1) {
perror("Errore con l'invio");
exit(1);
}
// Per uscire dalla connessione
if(strcmp(buffer, ":exit") == 0) {
close(clientSocket);
printf("[-]Disconnected from Server\n");
exit(0);
}
// Riceve i dati dal server
if ( (nread=recv(clientSocket, buffer, sizeof buffer - 1, 0)) <= 0) {
perror("[-]Error in receiving data from server\n");
}
else {
buffer[nread] = '\0';
printf("Server received: %s\n", buffer);
}
}
close(clientSocket);
return 0;
}
you can compile it using gcc -o client.out client.c
and execute it using ./client.out
This works fine.
How can I edit so that I can execute the server on two different computers?
Change INADDR_ANY to your server IP address.
serverAddress.sin_addr.s_addr = inet_addr("192.168.1.20");
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'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.