Newsgroup: it.comp.os.linux.development
Titolo: [C+socket] comunicazione server client

sto implementando una comunicazione server - client per implementare il
protocollo tpc-modbus  (se non conoscete questo protocollo non importa,
in questa discussione č marginale, potete vederlo come un normale invio
di dati attraverso un socket) su un sistema embedded su cui gira linux.
vi posto i due listati:
SERVER
/* file server_i.c */
/* Implementazione di server iterativo */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#define Max 8000
int main(void) {
char buff[Max];
struct sockaddr_in server;
struct sockaddr_in client;
int sd, temp_sd;
int address_size;
unsigned short port = 502; //porta di default del tcp-modbus
unsigned char func_code;
int len;
struct s_MBAP //questa struttura ricrea la struttura dell'header del
protocollo tcp-modbus
{
unsigned char transaction_id1;
unsigned char transaction_id2;
unsigned char protocol_id1;
unsigned char protocol_id2;
unsigned char leght_fld1;
unsigned char leght_fld2;
unsigned char unit_id;
} MBAP;
/* Creiamo il socket e riempiamo i campi della struttura
* server
*/
if ( (sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
printf("Errore nella craazione del server!\n");
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
/* assegnamo al socket un processo tramite la funzione BIND */
if (bind(sd, (struct sockaddr *)&server, sizeof(server)) < 0)
printf("Errore nella chiamata di sistema BIND!\n");
/* Mettiamolo in ascolto */
listen (sd, 20);
/* il nostro č un socket bloccante, secondo
* quanto esposto in precedenza, quindi
* non occorre un gestione troppo oculata
*  delle connessioni infatti....*/
while(1) {
if ((temp_sd= accept(sd, (struct sockaddr *)&client,
&address_size)) <
0)
printf("Errore nella chiamata ACCEPT\n");
/*Riceviaimo i dati dal client */
recv(temp_sd, buff, sizeof(buff), 0);
MBAP.transaction_id1=buff[0];
MBAP.transaction_id2=buff[1];
MBAP.protocol_id1=buff[2];
MBAP.protocol_id2=buff[3];
MBAP.leght_fld1=buff[4];
MBAP.leght_fld2=buff[5];
MBAP.unit_id=buff[6];
func_code=buff[7];
//essendo in fase di debug, provo a scrivere i valori letti
printf("scrivo i dati ricevuti :\n " );
printf("transaction= %u%u \n"
,MBAP.transaction_id1,MBAP.transaction_id2);
printf("protocol= %u%u \n" ,MBAP.protocol_id1,MBAP.protocol_id2);
printf("leght= %u%u \n" ,MBAP.leght_fld1, MBAP.leght_fld2);
printf("unit= %u \n" ,MBAP.unit_id);
printf("function code= %u \n" ,func_code);    //sembra bloccarsi qui'
//printf("ciao");
//i due dati leght_fld1 e leght_fld2 sono due byte che mi comunicano la
lunghezza dei byte che seguono fino alla
//fine del messaggio. calcolo questo valore
len=(int)MBAP.leght_fld1*256+(int)MBAP.leght_fld2;
printf("len= %i" ,len);
//per ora finisco qui'
close(temp_sd);
}
send(sd, "OK",10 , 0);
return EXIT_SUCCESS;
}
CLIENT:
/*file client1.c */
/* implementazione di client per il server iterativo */
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netdb.h>
#include<netinet/in.h>
#include <stdlib.h>
#define Max 8000
int main(void) {
int sd;
struct sockaddr_in client;
struct hostent *hp;
unsigned short port = 502;
char buff[Max];
unsigned char func_code;
//struttura dati dell'header del tcp-modbus
struct s_MBAP
{
unsigned char transaction_id1;
unsigned char transaction_id2;
unsigned char protocol_id1;
unsigned char protocol_id2;
unsigned char leght_fld1;
unsigned char leght_fld2;
unsigned char unit_id;
} MBAP;
/* Dobbiamo riempire la struttura client ma prima
* ci occorrono alcune
* informazioni che ricaviamo appoggiandoci
* alla struttura hp
*/
hp = gethostbyname("192.168.0.101");
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(port);
client.sin_addr.s_addr =((struct in_addr*)(hp->h_addr))->s_addr;
/* Creiamo il socket */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
printf("Errore nella creazione del socket!\n");
else
printf("socket creato!\n");
/* connettiamoci all'host */
if (connect(sd, (struct sockaddr *)&client, sizeof(client)) < 0)
printf("Errore di connessione!\n");
/* Inviamo dei dati */
//provo a inviare questi dati per ora 010203040A060708
MBAP.transaction_id1=1;
MBAP.transaction_id2=2;
MBAP.protocol_id1=3;
MBAP.protocol_id2=4;
MBAP.leght_fld1=10;
MBAP.leght_fld2=6;
MBAP.unit_id=7;
func_code=8;
buff[0]=MBAP.transaction_id1;
buff[1]=MBAP.transaction_id2;
buff[2]=MBAP.protocol_id1;
buff[3]=MBAP.protocol_id2;
buff[4]=MBAP.leght_fld1;
buff[5]=MBAP.leght_fld2;
buff[6]=MBAP.unit_id;
buff[7]=func_code;
send(sd, buff,8 , 0);
/*riceviamo la risposta */
recv(sd, buff,10, 0);
printf("Risposta del server: %s\n", buff);
close(sd);
return EXIT_SUCCESS;
}
sono ancora in una prima fase di debug. Come si puo' vedere dal codice,
il client invia 010203040A05060708.
il risultato che visualizzo sullo schermo dove gira il server  č
questo:
scrivo i dati ricevuti :
transaction= 12
protocol= 34
leght= 106
unit= 7
function code= 8
quindi i dati arrivano correttamente, ma l'esecuzione non va avanti,
indipendentemente da quale istruzione inserisco di seguito.
Ho provato ad inserire dopo l'ultima stringa visualizzata una scrittura
semplice del tipo
printf("ciao"); che nel codice sopra č commentata,
ma non viene visualizzata nemmeno questa.
Qualcuno sa aiutarmi?
Grazie e ciao
-- 
sandro76
------------------------------------------------------------------------
sandro76's Profile: 
http://www.linuxforum.it/member.php?userid=1097
View this thread: 
http://www.linuxforum.it/showthread.php?t=19666

ho risolto utilizzando un server concorrente al posto di un server
iterativo
usando sempre come modello i sorgenti trovati su
Imparare il C di  Marco Latini - Paolo Lulli
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#define Max 8
int main(void) {
char buff[Max];
struct sockaddr_in server;
struct sockaddr_in client;
int sd, temp_sd;
int address_size;
unsigned short port = 502;
pid_t pid; /* varibile utilizzata per identificare il processo */
unsigned char func_code;
int len;
struct s_MBAP
{
unsigned char transaction_id1;
unsigned char transaction_id2;
unsigned char protocol_id1;
unsigned char protocol_id2;
unsigned char leght_fld1;
unsigned char leght_fld2;
unsigned char unit_id;
} MBAP;
/****************************************
* QUESTA PARTE E’ UGUALE NEI DUE SERVER*
* **************************************/
/* Creiamo il socket e riempiamo i campi della struttura
* server
*/
if ( (sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
printf("Errore nella craazione del server!\n");
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
/* assegnamo al socket un processo tramite la funzione BIND */
if (bind(sd, (struct sockaddr *)&server, sizeof(server)) < 0)
printf("Errore nella chiamata di sistema BIND!\n");
/* Mettiamolo in ascolto */
listen (sd, 20);
/***************************************
* ORA COMINCIA LA GESTIONE CONCORRENTE*
* *************************************/
while(1) {
if ((temp_sd= accept(sd, (struct sockaddr *)&client,
&address_size))
< 0) {
perror("Errore nella chiamata ACCEPT\n");
exit(-1);
}
if ((pid = fork()) < 0) {
perror(" fork error\n");
exit(-1);
}
if (pid == 0) { /* sono nel figlio */
close(sd);
/*Riceviaimo i dati dal client */
recv(temp_sd, buff, sizeof(buff), 0);
MBAP.transaction_id1=buff[0];
MBAP.transaction_id2=buff[1];
MBAP.protocol_id1=buff[2];
MBAP.protocol_id2=buff[3];
MBAP.leght_fld1=buff[4];
MBAP.leght_fld2=buff[5];
MBAP.unit_id=buff[6];
func_code=buff[7];
//debug
printf("scrivo i dati ricevuti :\n " );
printf("transaction= %u%u \n"
,MBAP.transaction_id1,MBAP.transaction_id2);
printf("protocol= %u%u \n" ,MBAP.protocol_id1,MBAP.protocol_id2);
printf("leght= %u%u \n" ,MBAP.leght_fld1, MBAP.leght_fld2);
printf("unit= %u \n" ,MBAP.unit_id);
printf("function code= %u \n" ,func_code);
printf("ciao");
len=(int)MBAP.leght_fld1*256+(int)MBAP.leght_fld2;
printf("len= %i" ,len);
/* Spediamo qualcosa */
strcpy(buff, "Tutto OK!");
send(temp_sd, buff, strlen(buff), 0);
close(temp_sd);
exit(0);
}
else { /* sono nel padre */
close(temp_sd);
}
}
exit(0);
}
sembra produrre il risultato voluto.
Avevo capito che la differenza tra i due fosse solo che il secondo
accettava connessioni multiple, mentre nel primo caso in caso di due
connessioni la seconda arrivata avrebbe trovato il server occupato (cosa
che non mi preoccupava molto nella applicazione che volevo realizzare).
qualcuno sa darmi la motivazione del mancato funzionamento del primo?


ho notato che se invio una seconda volta il processo client allora il
processo finisce ad inviare i dati:
dal pc 1 lancio il client:
./client
sul secondo pc visualizzo:
scrivo i dati ricevuti :
transaction= 12
protocol= 34
leght= 106
unit= 7
function code= 8
e qui si blocca.
rilancio un altra volta il processo ./client dal pc1
e sul secondo pc scrive
ciaolen= 2566scrivo i dati ricevuti :
transaction= 12
protocol= 34
leght= 106
unit= 7
function code= 8
e si blocca di nuovo.
dove
ciaolen= 2566
erano i dati che mi aspettavo dalla prima chiamata.


 processo finisce ad inviare i dati:
Sarà una questione di buffering dello stdout. Avrai dimenticato di mettere
lo "\n" finale in qualche printf.
Max


emmm..
fatta la prova, ho inserito /n sull'ultima stringa inviata e
naturalmente tutto funziona :p
grazie Max



emmm..
fatta la prova, ho inserito \n sull'ultima stringa inviata e
naturalmente tutto funziona :p
grazie Max
