Oppure

Loading
17/12/08 20:32
trenta3
Premetto che sono da poco entrato nelmondo della programmazione.
Avrei un problema:
Ho il codice di un banale server e di un banale client che si scambiano messaggi tra loro.
Il problema sorge quando vorrei fare in modo che il server supporti la connessioni anche di più client contemporaneamente come in una chat.
Ho cercato su internet ed ho scoperto che servirebbe un programma multiprocesso ma non riesco a capire come fare:
Il mio compilatore, Dev-c++, mi da errore quando metto il comando fork().

Grazie in anticipo a chi risponderà.(Mi basterebbe una guida ,possibilmente in Italiano ma va bene anche in Francese e in Inglese, che spieghi per bene il fork e i programmi multiprocesso.)
Metto per comodità i codici(senza fork):

Server.c

/****************************
Sorgenti della guida
www.fabrixosft.altervista.org
www.pierotofy.it
***************************/

#include <stdio.h>
#include <winsock.h>
main(){
      
//INIZIALIZZAZIONE WINSOCK
WSADATA wsadata;
int Versione= WSAStartup(MAKEWORD(2,2),&wsadata);
//Gestione dell'errore
if(Versione!=NO_ERROR){ //o anche if(Versione != 0){
printf("Errore nell'inizializzazione delle socket");
}
//***************************************



//DICHIARAZIONE E CREAZIONE DELLA SOCKET
//Dichiariamo la SOCKET che verrà chiamata server
SOCKET server;
//Associamo alla socket "AF_INET", ovvero internet adress family (il più usato), "SOCK_STREAM", per far girare la socket sul protocollo TCP(esiste anche il tipo "SOCK_DGRAM" per usare la socket su un protocollo UDP),IPPROTO_TCP , ovvero la socket userà il protocollo TCP
server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//gestione dell'errore
if(server==INVALID_SOCKET){
printf("Errore: Socket non valida");
//Liberiamo le risorse della socket
WSACleanup();
}//*************************************

//STRUTTURA SOCKADDR_IN E ASSEGNAZIONE DI PARAMETRI AL SERVER
SOCKADDR_IN  parametri_server;
//Come detto prima passiamo la internet address family
parametri_server.sin_family=AF_INET;
//ora diciamo su che indirizzo IP il server deve attivarsi, in questo caso 127.0.0.1 ovvero l'host locale
parametri_server.sin_addr.s_addr = INADDR_ANY; //In questo modo faremo collegare da remoto il clien altrimenti mettere "inet_addr("127.0.0.1");"
//Ora passiamo al server la porta di connessione, in questo caso la 1000
parametri_server.sin_port=htons(1000);
//************************************************************

//FUNZIONE BIND
int funzione_bind;
funzione_bind=bind( server, (SOCKADDR*) ¶metri_server, sizeof(parametri_server));
if(funzione_bind ==SOCKET_ERROR ){
/*if(bind!=0){
printf("Funzione bind non riuscita\n");*/
//Chiudiamo correttamente la socket
printf("Errore\n");
closesocket(server);
WSACleanup();
}
//****************************************************


//FUNZIONE LISTEN(); RIMANE IN ASCOLTO
int funzione_listen;
funzione_listen=listen(server,1);
if(funzione_listen ==SOCKET_ERROR)
//Gestione dell'errore
printf("Errore nella funzione listen \n");
//************************************


//FUNZIONE ACCEPT(); ACCETTA LA CONNESSIONE
//Creiamo un elemento di tipo SOCKET
SOCKET Accetta_connessioni;
//ciclo infinito che attende la connessione
printf("Attendo la connesione d un client\n");
while(1){
//dichiariamo la SOCKET Accetta_connessioni come errore ...
Accetta_connessioni=ERROR;
//in modo da innestare un altro ciclo while che si interrompe solo quando la SOCKET Accetta_connessioni non è più  ERROR, ovvero finchè non avviene la connessione con un client.
while(Accetta_connessioni==ERROR){
//La struttura della accept deve prendere 3 parametri, l primo obbligatorio e gli altri opzionali, a noi interessa solo il primo parametro(ovvero SOCKET server) e in questa guida non spiegherò a cosa servono gli altri 2 che setteremo a NULL
Accetta_connessioni=accept(server,NULL,NULL);
}
//Se il ciclo si interrompe significa che un client si è connesso
printf("Un client ha effettuato una connessione!");
//Assegnamo alla SOCKET server la socket Accetta_connessioni.
server=Accetta_connessioni;
//con un break; usciamo dal ciclo infinito
break;
}
//********************************


//FUNZIONE RECV PER LA RICEZIONE DEI DATI
//Dichiariamo il buffer contenente i dati ricevuti
int ricevuto;
char ricezione_dati[100];
do{
//Funzione recv per ricevere i dati
recv(server,ricezione_dati,100,0);
//Outputiamo i dati ricevuti
printf("\nHo ricevuto >>> %s ",ricezione_dati);
//Il ciclo continua finchè non viene digitato "Chiuditi"
}while(strcmp(ricezione_dati,"Chiuditi")!=0);
getchar();
//*************************************

} 


Client.c

/****************
Sorgenti della guida
www.fabrixsoft.altervista.org
www.pierotofy.it
****************/
#include <stdio.h>
#include <winsock.h>

char IP[20];

main(){
//Richiediamo all'utente l'IP e lo memorizziamo
printf("Digita l'IP di connessione >>>");
scanf("%s",IP);

//Inizializziamo il Winsock
WSADATA wsadata;
int Valore;
Valore = WSAStartup( MAKEWORD(2,2), &wsadata );
if ( Valore != NO_ERROR )
printf("Errore nell'inizializzazione\n");
//************************

//Creiamo la socket
SOCKET client;
client= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
//Gestione dell'errore
if ( client== INVALID_SOCKET ) {
printf("Errore nella creazione della socket\n");
//Liberiamo le risorse del winsock
WSACleanup();
}
//****************************    
    
    
//ASSEGNAMO DEI PARAMETRI AL CLIENT
SOCKADDR_IN parametri_client;
//internet adress family
parametri_client.sin_family = AF_INET;
//Mettiamo come IP di connessione quello immesso dall' utente
parametri_client.sin_addr.s_addr = inet_addr( IP );
//porta numero 1000
parametri_client.sin_port = htons( 1000);
//**********************************

//FUNZIONE CONNECT();
//Dichiaro una variabile int connessione
int connessione;
//assegno a connessione la funzione connect();
connessione=connect(client,(SOCKADDR*) ¶metri_client,sizeof(parametri_client));
//Gestione dell'errore
if( connessione == SOCKET_ERROR){
printf("Connessione fallita \n");
//Chiudo la scoket
closesocket(client);
WSACleanup();
}
//*****************************


//Dichiaro un buffer dove salverò il messaggio che verrà digitato dall'utente
char invio_dati[100];
do{
printf("Digita il messaggio da inviare al server >>> ");
//Prendo il messaggio
fflush(stdin);
_sleep(100);
gets(invio_dati);
//Invio il messaggio
send(client,invio_dati,100,0);
//Il ciclo si ripete finche non viene digitato "Chiuditi"
}while(strcmp(invio_dati,"Chiuditi")!=0);
//Aspetto la pressionde di un tasto e chiudo il programma
getchar();
return 0;
} 
Ultima modifica effettuata da trenta3 17/12/08 20:34
aaa
18/12/08 1:24
mc
La fork non esiste in windows.
Oltretutto ti consiglio qualcosa di meglio di DevC++, magari Code::Block.
Secondo il tuo codice è tutto appicicato, oltretutto tra commenti, e ci sono degli errori.
Il primo che ho visto è che scrivi main, al posto di int main(void).
Poi per gli altri errori vedremo quando avrai reso il codice più leggibile.
Grazie.
:-|
aaa
18/12/08 11:37
eddiewrc
@Code::Block (si scrive così?) gira su linux?

@33: windows non supporta la programmazione multiprocesso, e soprettutto fork(), exec..() e tutte le altre sono system call specifiche dei sistemi unix, quindi non è il compilatore che è marcio, semplicemente win non possiede quelle sys call.

ti basta passare a linux o scaricare una virtual machine (quella della sun è free) e installarci qualche distro del pinguino, così puoi rimanere in win e programmare cmq processi concorrenti!

ah dimenticavo... ovviamente in linux il codice per utilizzare le socket è diverso.. infatti in questo programma usi delle api di win, mentre col pinguino devi usare le sue system call.

ciao

Ultima modifica effettuata da eddiewrc 18/12/08 11:39
aaa
18/12/08 13:22
pierotofy
Windows non supporta le fork, come ti hanno giustamente detto, ma puoi ottenere il risultato desiderato utilizzando i threads. Dai uno sguardo sull'MSDN per le relative API.
Il mio blog: piero.dev
18/12/08 14:13
Bond93
Si si scrive Code::Block ( XD molto C++ XD ) gira fantasticamente su linux supporta già di default le maggiri librerie grafiche ( SDL OGL GTK+ <ecc )
Te lo consiglio veramente è ottimo!!
aaa
18/12/08 14:22
eddiewrc
non vorrei andare OT ma grazie, lo guarderò! devo fare un progettone e nn riesco a trovare un ide nn complichi le cose + di quel che le ha complicate il prof..;)
aaa
18/12/08 15:13
trenta3
Grazie per tutte le risposte.
Ho capito che mi devo rassegnare, vedo su MSDN per le API su Windows.

Il codice è stato preso da una guida alla programmazione client server su questo sito e ho appiccicato quella perchè quella con fork aveva una confusione tale che non riuscivo a capire quali parti togliere e quindi l' ho buttata via.
Fortuna che fork() su win non si può usare alrimenti starei a rodermi il fegato XD

Grazie ancora per le risposte, mi faccio risentire quando ho letto MSDN.
aaa
20/12/08 16:04
trenta3
Vi volevo segnalare che ho trovato un ottimo tutorial sui thread <questo> e ho fatto questo programma come server:

Il problema è che, nel thread chiamato thread1 quando c'è il comando recv il programma non riconosce server(1° parametro) perchè sta nell'altra funzione(main), come posso fare?
#include <stdio.h> 
#include <winsock.h> 
#include <windows.h>

long WINAPI Thread1(LPWORD ret); 

int cl= 100;

int main (){
    HANDLE hThread[1];
    DWORD dwID[1]; 
    int count=0;
    int d;
    
     
     WSADATA wsadata; 
     int Versione= WSAStartup(MAKEWORD(2,2),&wsadata); 
     
     if(Versione!=NO_ERROR){ 
     printf("Errore nell'inizializzazione delle socket\n"); 
     return 1;
     } 
 


     
     SOCKET server; 
    
     server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    
     if(server==INVALID_SOCKET){ 
     printf("Errore: Socket non valida\n");
     return 1;
     }

     SOCKADDR_IN  parametri_server; 
    
     parametri_server.sin_family=AF_INET; 
   
     parametri_server.sin_addr.s_addr = INADDR_ANY;
   
     parametri_server.sin_port=htons(1000); 
  
     int funzione_bind; 
     funzione_bind=bind( server, (SOCKADDR*) &parametri_server, sizeof(parametri_server));
      if(funzione_bind ==SOCKET_ERROR ){
      printf("Funzione bind non riuscita\n");
 
      closesocket(server); 
      WSACleanup(); 
      return 1;
      } 
      
     int funzione_listen;
     funzione_listen=listen(server,1); 
     if(funzione_listen ==SOCKET_ERROR){ 

     printf("Errore nella funzione listen \n");
     closesocket(server); 
     WSACleanup(); 
     return 1;
     }

     SOCKET Accetta_connessioni; 
   
     printf("Attendo la connesione di un client\n"); 
     while(1){ 
    
     Accetta_connessioni=ERROR; 
     
     while(Accetta_connessioni==ERROR){ 
     
     Accetta_connessioni=accept(server,NULL,NULL); 
     } 
   
     printf("Un client ha effettuato una connessione!\n"); 
      count ++;
      cl ++;
      printf("N. client: %d\n", cl);
      printf("Client connessi: %d\n\n", count);
    hThread[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread1,NULL,0,&dwID[0]); 
      
     } 

}  
     
 
   
   
   
   long WINAPI Thread1(LPWORD ret) 
{ 
    int ricevuto; 
     char ricezione_dati[256]; 
     do{ 
    
     recv(server,ricezione_dati,256,0); 
     printf("\nHo ricevuto dal client%d>>> %s ",cl,ricezione_dati); 

     }
     while(strcmp(ricezione_dati,"Chiuditi")!=0); 
     getchar(); 
    
     closesocket(server); 
     WSACleanup(); 
     return 0;
    
} 
aaa