View Full Version : [C\C++] static socket?
Salve a tutti,
probabilmente faccio una domanda più stupida del solito ma siete il modo più veloce per sapere la risposta..
È possibile dichiarare static un socket (usando la Winsock)?
Se lo faccio in una funzione il socket resta aperto dopo la return o viene chiuso?
mi servirebbe che venisse aperto solo alla prima chiamata..
Questo è il codice che ho scritto.
void importExt(int val, double* a,double* b,double* c)
{
static WORD wVersionRequested = MAKEWORD(2,2);
static WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);
static SOCKET sock;
static SOCKADDR_IN addr;
static int is_initialized = 0;
if (!is_initialized)
{
sock=socket(AF_INET, SOCK_STREAM, 0);
crea_addr(&addr,10503,"127.0.0.1");
if(connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr))==0);
is_initialized = 1;
send(sock,"\0",sizeof("\0"),0);
}
if(is_initialized)
{
char buf[40]={0};
int n;
n=recv(sock, buf, sizeof(buf),0);
if(n == SOCKET_ERROR)
{
cout<<"Socket error\n";
*a=0;
*b=0;
*c=0;
}
else
{
buf[n]=0;
cout<< buf<<" \n";
*a=0;
*b=0;
*c=0;
send(sock,"\0",sizeof("\0"),0);
}
return ;
}
return;
}
Questo socket viene chiuso comunque alla return?
Con la Winsock non c'è una funzione tipo la isOpen() delle QT, giusto?
Per questo volevo usare la recv() per controllare se fosse aperto o meno ma con questa flag pare aspetti all'infinito.
sapete dirmi come faccio a dire alla recv() di aspettare un po' e poi ritornare errore?
Grazie mille,
Francesco
Teo@Unix
21-10-2010, 21:09
ma guarda non ho mai visto farlo di mettere static un socket, se vuoi impostare un timeout su recv() io ti consiglio di utilizzare la funzione select() (Linux però), ci dovrebbe essere anche per windows. Guarda su MSDN...
La funzione select() assieme alle sue macro ti consente di scrivere server e client asincroni.
Esiste anche per windows..grazie..
il problema è che quella che ho postato è una funzione esterna chiamata da un simulatore (openModelica, mi hai già dato una mano altre volte a proposito) e se riconnetto il socket ad ogni chiamata i risultati mi arrivano con troppo ritardo.
Questo simulatore gestisce altri socket.
Il problema che ho è: praticamente la funzione viene chiamata più volte e riesce a ricevere (il socket è aperto quindi) ma quando il simulatore deve inviarmi i risultati sull'altro socket mi si blocca tutto.
Ho pensato (ma magari è una stupidaggine) che poiché la mia funzione non è in un altro thread..si blocca tutto tra dati da leggere e da inviare. È possibile?
Anche se credo di aver risolto il problema riconnetendo il socket solo ogni TOT chiamate ( almeno così pare) mi piacerebbe capire perchè non va (la procedura che ho usato mi è stata suggerita dagli sviluppatori)..
Mi rendo conto che la domanda è astrusa e campata in aria (e forse pure posta male)..ma magari è un problema noto nella comunicazione tramite socket ed allora potreste aiutarmi..
In caso contrario ingnoratemi pure :D
Ciao e grazie comunque!
Teo@Unix
21-10-2010, 22:59
a ora ricordo è vero.... no allora le dichiarazioni static, compresi i socket che io sappia non si chiudono dopo la return, ma solo se chiami close o il programma termina.... se non mi sbaglio, credo che il problema stia nel fatto che la recv(), essendo bloccante, blocca il programma, voglio dire che una volta chiamata recv() questa non ritorna finchè non ha ricevuto dati... perchè è così lei, la funzione non ci sono thread.
Una soluzione che potresti trovare in giro è l'impostazione di recv() non-bloccante, utilizzando ioctl() mi sembra... ma non credo che funzionerà, sarà talmente veloce che ritornerà a mani vuote...
può essere che nella tua simulazione venga chiamata recv() anche quando non è detto che vi siano dati in arrivo?
Io credo che veramente potresti risolvere inserendo prima di send() e recv() select(), si tratta di fare un pò di menate in più ma se il problema è questo ti evita il mal di testa....
per un esempio sull'uso di select() per linux, ma con qualche accorgimento diventa per windows, (l'iniziazione con le macro WSADATA e quelle balle lì su win è diverso)
http://www.lilik.it/~mirko/gapil/gapilsu252.html
la recv() è sempre dopo la send() (o dopo la connect nell'ultima versione)..
nell'applicazione server l'invio dei dati è in uono slot collegato col segnale readyread ( newconnection nella nuova), quindi dovrebbero eserci sempre dati in arrivo., me la studio un po' tutto e poi provo con la select() o con ioctlsocket() (la ioctl credo sia per gli streams, forse) e ti faccio sapere..
Avevi ragione..la ioctlsocket() non-blocking è troppo rapida.
Ma mi ha aiutato a pensare perchè se metto il socket in blocking-mode riceve un tot di volte.
Dato che il server invia i dati di sicuro allora posso dedurre che il socket è stato chiuso (dal simulatore?), quindi anche con select non risolverei nulla, o mi sbaglio?:help:
Ah e poi, (so che sono OT ma è una cosa veloce), il destructor di una QApplication è chiamato quando chiudo la finestra console? perchè se metto un break point là nin mi ci passa:confused:
Teo@Unix
22-10-2010, 10:19
Dato che il server invia i dati di sicuro allora posso dedurre che il socket è stato chiuso (dal simulatore?), quindi anche con select non risolverei nulla, o mi sbaglio?:help:
Bisognerebbe capire che cosa fa il simulatore, in quanto lui potrebbe aprire un socket inviare e chiuderlo subito dopo, oppure il socket viene aperto all'inizio e poi chiuso solo alla fine, quindi tutte le recv() e send() sono su quel socket.
Quando chiami connect() dall'altro lato ci deve essere una accept() in attesa per effettuare l'handshake di TCP... dove vengono scambiati 3 pacchetti in totale....
per capire come si comporta il simulatore puoi usare un analizzatore di protocollo come wireshark.
Fai conto,
- lato server ciene aperto un socket e dopo le dovute menate arriva a fermarsi su accept()
- lato client viene aperto un socket questo arriverà a connect()
A questo punto avviene la connessione. Se uno dei due capi chiude la connessione basta, finiti i giochi occorre ricominciare da capo, non si può chiudere un lato e continuare ad utilizzare la connessione mezza aperta, che comunque non rimane aperta perchè il lato che chiude la connessione invia un pacchetto RST (reset) che indica di chiudere...
- Quando la connessione è stabilita gestirai tutti gli invia ricevi da entrambi i lati con il metodo che viene mostrato nell'esempio, (tutto il ciclo con select())
- Alla fine uno chiude e tanti saluti....
Però se il server apre una connessione per ogni "sessione" diciamo e poi chiude, occorre rivedere questo metodo...
prova a verificare in effetti come si comporta....
io non ho ben presente il tuo simulatore e cosa deve fare, non so se sono riuscito ad aiutarti nel modo corretto...
Ah e poi, (so che sono OT ma è una cosa veloce), il destructor di una QApplication è chiamato quando chiudo la finestra console? perchè se metto un break point là nin mi ci passa
Il distruttore è associato alla classe di cui fa parte, viene chiamato quando un oggetto viene deallocato, infatti è lui che va liberare la memoria...
ad esempio se creo un oggetto classe msgbox, il distruttore viene chiamato quando io chiudo la dialog.
Direi che il distruttore di QApplication viene chiamato al termine dl tuo prgramma, cosa vuoi intercettare con il tuo break-point?
cerco di riassumere brevemente..
OpenModelica funziona per conto suo..Dispone di un'interactive mode che, durante la simulazione, apre tre socket (un server e due client). Il server riceve i comandi di start, stop e cambio di qualche parametro; i due client servono uno per inviare risposte agli ordini ricevutiun o, e per l'invio di una stringa con i risultati l'altro.
Quest'ultimo invia risultati sempre, ogni tot millisecondi.
Ho scritto un'applicazione con il client ed i due server per comunicare e questa parte funziona bene.
Il simulatore mette poi a disposizione un'interfaccia per chiamare una funzione qualsiasi scritta in c\c++.
In una prima versione questa funzione leggeva direttamente gli input (usavo il mouse con la windows.h) che usava come variabili di simulazione.
Ora mi serve leggere l'input dal BUS (quello fisico del pc, ho a disposizione delle classi in JNI che funzionano, testè); solo che non posso farlo direttamente dalla funzione esterna c++ che usavo prima.
Così ho pensato di creare un'altra linea di comunicazione, ovvero leggere i dati nella mia applicazione ed inviarli traimite un server al client della funzione c++ esterna di OpenModelica.
Qui sono sorti i problemi che non riesco a capire perché credo dipendano da come OpenModelica compila ed esegue la mia funzione esterna, e da come gestisca le sue di comunicazioni.
Da quel che vedo:
1- se connetto ad ogni chiamate senza dichiarare nulla di static funziona tutto ma è molto lento (mi serve una simulazione real-time), praticamente mi arriva una stringa di risultati ogni 30-40 (non so) scambi tra funzione ed applicazione.
2- se dichiaro il socket come static in modo da connettermi solo alla prima chiamata della funzione avvengono un numero limitati di scambi (quindi evidentemente la funzione viene chiamata più volte senza che il socket sia chiuso) e poi si blocca tutto alla recv(), e comunque senza che io abbia ricevuto ancora nessun risultato. Quindi mi viene il dubbio che il simulatore funzioni a step, cioè acquisisce dati, simula invia risultati, stacca tutto e ricomincia da capo (risultato: socket chiuso).
3-se connetto il server ogni tot (per esempio 100) chiamate di funzione ottengo i risultati in modo sufficientemente veloce.
Ora magari tutto sto sproloquio non ti serve però, vabbè..
Diciamo che per ora mi va bene la versione tre, con la quale però capisci che rischio di perdere qualche info; se dici che valga la pena provare con select() allora ci perdo un po' di tempo.
La seconda domanda era perché vorrei inviare gli ordini di stop e disconnessione quando chiudo la console, perciò li avevo inseriti nel distruttore, ma non ci entra!
Teo@Unix
22-10-2010, 11:26
Se hai un blocco su recv() si probabilmente viene chiamata non sempre al momento giusto, ed in questa occasione si blocca.
Ti consiglio di usare wireshark per capire il problema, l'uso è molto sempice, una volta avviato vai a scegliere l'interfaccia di rete, poi inizia l'aquisizione, come filtro da inserire nella barra in alto puoi usare "tcp and ip.addr==<tuo ip>".
Questo unito al debug dell'applicazione credo ti possa aiutare. A meno che hai timeout molto brevi dall'altra parte...
per quanto riguarda select(), questa ti eviterebbe che la recv() si blocchi, perchè verrebbe chiamata solo quando ci sono effettivamente dati da ricevere, altrimenti select non ritorna. In più hai possibilità di impostare un timeout su questa, che è poi il modo per uscirne.
Ok, diciamo che funziona..ti ringrazio, anche se resta il problema che mi rallenta la simulazione e che in effetti il socket viene chiuso dal simulatore..
winshark non riesco a farlo funzionare..scelgo remote, inserisco host e porta, ma poi non risponde..forse per i timeout?
Teo@Unix
22-10-2010, 14:37
ok, per wireshark, devi scegliere l'interfaccia locale. tuo indirizzo. La porta non serve, è sotto il menù capture -> interface....
ma alla fine se per i tuoi scopi va bene direi che sei a posto, d'altronde ti occupi di meccanica giusto? Se non ricordo male.. non di informatica :)
Seh, dovrei!...sono in stage al fraunhofer IGD e qua fanno informatica..
Ma, a parte i crash e le eccezioni che spuntano ogni tanto (devo risolvere quella faccenda del distruttore:confused: ), mi serve una simulazione in tempo reale e con questa velocità di risposta non vado da nessuna parte :stordita: ..
mo ci perdo un'altro po' di tempo poi torno alla soluzione precedente..
Winshark nulla..ho avviato la simulazione, avvio il capture ma non c'è nessuna riga che riporti l'indirizzo socket che ho scelto per l'applicazione..
Ti ringrazio ancora!
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.