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