Newsgroup: it.comp.lang.c++
Titolo: Io ci riprovo...

Scusate, qualcuno ha letto il mio messaggio sulla classe wrapper per
comunicazioni su socket ?
Avrei bisogno se possibile di almeno dei piccoli consigli, perché non ho le
idee per niente chiare.
Per chi non l'avesse letto, ripeto che nonostante il titolo che può essere
fuorviante non è relativo a uno specifico OS, ma a come realizzare una
classe che faccia determinate cose basandosi sulle API di sistema.
Massimo

 classe che faccia determinate cose basandosi sulle API di sistema.
Cosa vuole dire? Fai una classe e le sue funzioni membro utilizzano le API di sistema.
Qual'è il punto?

 Qual'è il punto?
Il messaggio era lungo perché esponevo una serie di questioni relative a
come utilizzare la libreria standard C++ all'interno di una classe che
vorrei realizzare; le API da usare per il lavoro di "basso livello" sono,
appunto, un dettaglio irrilevante.
Ma se leggessi i messaggi invece di sputare sentenze forse lo sapresti...
Massimo

 Ma se leggessi i messaggi invece di sputare sentenze forse lo sapresti...
Non t'incazzare con me.
L'unica "sentenza che ho sputato" è che il messaggio era troppo lungo (e
incasinato, adesso l'ho letto) che più che una sentenza era una opinione.
Ma se vuoi una sentenza, ti condanno a due camomille e un riposino.
--
"I bambini che ancora non sanno, nel loro Eden, il prezzo altissimo che un Dio ingeneroso stabilirà per ogni singola mela: il prezzo della fatica e del dolore."

 Ma se vuoi una sentenza, ti condanno a due camomille e un riposino.
E questo sarebbe il genere di aiuto che ci si può aspettare in questo
newsgroup ponendo una domanda perfettamente in topic ?
Devo dire che me lo ricordavo diverso, forse qualche mese fa c'era gente un
po' più disponibile di te.
Grazie mille e addio.
Massimo

 classe che faccia determinate cose basandosi sulle API di sistema.
Le questioni che poni non sono rispondibili in tre righe. Ergo abbi pazienza.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 Le questioni che poni non sono rispondibili in tre righe. Ergo abbi
pazienza.
Ma sě, e chi dice nulla ?
Semplicemente, non vedendo alcuna risposta, mi chiedevo se qualcuno l'avesse
letto... anche un "l'ho letto ma ci metterň un po' a rispondere" come il tuo
va benissimo :-)
Massimo

 Grazie mille e addio.
Sapete cosa causa tutto questo? La grande mole di messaggi off-topic
(compreso questo, purtroppo...). Siamo talmente stufi (noi frequentatori
abituali, almeno) di doverci scorrere decine di messaggi non inerenti (e
che quindi non ci interessano) che ce la prendiamo a volte anche con chi
non c'entra.
EMG

 (compreso questo, purtroppo...). Siamo talmente stufi (noi frequentatori
Se parli del messaggio originale .. non era OT.


 Se parli del messaggio originale .. non era OT.
No, parlavo del mio. :-)
EMG

classe che faccia determinate cose basandosi sulle API di sistema.
le quali API di sistema sono relative ad uno specifico OS. Non male
come circolo vizioso ;-)
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

 come circolo vizioso ;-)
astrazione, mon amour....

 come circolo vizioso ;-)
Intendevo: non sto chiedendo come usare le API, quelle me le vedo io; sto
chiedendo come realizzare la classe...
Uff, ma quant'è difficile farsi capire :-)
Massimo

Uff, ma quant'è difficile farsi capire :-)
hai perfettamente ragione, avevo capito male il senso della frase


 ha scritto nel messaggio
news:9c725t$7o1$1...@news.mclink.it...

C'è una cosa di fondo che non sono riuscito a capire nel tuo
precedente messaggio.
Che tipo di dati devi leggere dallo stream?
Sono solo comandi (ossia stringhe terminate da '\n') o anche altro?
Per la parte di output la soluzione più semplice è costruire uno
streambuf.
C'è un'altra cosa che non ho chiara.
Per ogni client del gioco c'è un istream dal lato server
che gestisce il suo input?
Manlio Perillo

 che gestisce il suo input?
Esattamente. Ogni client ha un suo socket distinto.
Massimo

 >
Ti riporto una implementazione di uno streambuf che dovrebbe
rispiecchiare le tue richieste.
L'idea è di avere un buffer formato da vari chunks che vengono
allocati e deallocati all'occorrenza.
La mia implementazione usa come destinazione 'reale' uno streambuf per
semplicità e per far vedere come funziona.
E' abbastanza lungo, mi scuso se causa problemi a qualcuno.
#include <streambuf>
#include <stdexcept>
class chunkbuf: public std::streambuf
{
   public:
      // types
      typedef char                         char_type;
      typedef std::char_traits<char_type>  traits_type;
      typedef traits_type::int_type        int_type;
      typedef traits_type::off_type        off_type;
      typedef traits_type::pos_type        pos_type;
      typedef std::streamsize              streamsize;
   protected:
      static const streamsize chunk_size = 5; // 512;
      static const streamsize max_chunks = 5; // 32;
      int current_chunk;
      char_type* chunk_buf[max_chunks];
      std::streambuf* destination;
   public:
      // numero massimo di caratteri inviabili
      static streamsize max_size() { return chunk_size * max_chunks; }
   public:
      chunkbuf(std::streambuf* s)
      : current_chunk(0), destination(s)
      {
         // alloca il primo chunk
         chunk_buf[current_chunk] = new char_type[chunk_size];
         setp(chunk_buf[current_chunk],
              chunk_buf[current_chunk] + chunk_size);
      }
      // numero di caratteri immagazzinati nel buffer
      streamsize pcount() const
      {
         return current_chunk * chunk_size + (pptr() - pbase());
      }
      // numero di chunks usati
      int chunks() const { return current_chunk + 1; }
      ~chunkbuf()
      {
         sync();
         // dealloca i chunks usati
         for(int i = 0; i <= current_chunk; ++i)
            delete[] chunk_buf[i];
      }
   protected:
      int_type overflow(int_type c = traits_type::eof())
      {
         if(!(current_chunk + 1 < max_chunks))
            return traits_type::eof();  // overflow
         // alloca un nuovo chunk
         ++current_chunk;
         chunk_buf[current_chunk] = new char_type[chunk_size];
         setp(chunk_buf[current_chunk],
              chunk_buf[current_chunk] + chunk_size);
         if(c != traits_type::eof())
         {
            *chunk_buf[current_chunk] = traits_type::to_char_type(c);
            pbump(1);
         }
         return traits_type::not_eof(c);
      }
      int sync()
      {
         // invia i caratteri presenti nel buffer a destinazione
         for(int i = 0; i < current_chunk; ++i)
         {
            if(destination->sputn(chunk_buf[i], chunk_size) !=
               chunk_size) return -1;
            destination->pubsync();
         }
         streamsize remain = pptr() - pbase();
         if(destination->sputn(pbase(), remain) != remain) return -1;
         destination->pubsync();
         // dealloca i chunks usati (tranne il primo ovviamente)
         for(int i = 1; i <= current_chunk; ++i)
            delete[] chunk_buf[i];
         current_chunk = 0;
         setp(chunk_buf[current_chunk],
              chunk_buf[current_chunk] + chunk_size);
         return 0;
      }
};
class chunkstream: public std::ostream
{
   public:
      // types
      typedef char                         char_type;
      typedef std::char_traits<char_type>  traits_type;
      typedef traits_type::int_type        int_type;
      typedef traits_type::off_type        off_type;
      typedef traits_type::pos_type        pos_type;
      typedef std::streamsize      streamsize;
   private:
      chunkbuf buf;
   public:
      chunkstream(std::streambuf* s)
      : std::ostream(0), buf(s)
      {
         init(&buf);
      }
      chunkbuf* rdbuf() const { return const_cast<chunkbuf*>(&buf); }
      streamsize pcount() const { return buf.pcount(); }
};
///////////////////////////////////////////////
Esempio
#include <iostream>
int main()
{
   chunkstream out(std::cout.rdbuf());
   out << "hello" << " word";
   out << 3.434 << 23123 << "bye\n\n";// << "overflow";
   std::cout << "pcount = " << out.rdbuf()->pcount() << '\n';
   std::cout << "chunks = " << out.rdbuf()->chunks() << '\n';
   std::cout << "contenuto del buffer:\n";
   int r = out.rdbuf()->pubsync();
   std::cout << "\nsync = " << r << '\n';
   if(!out)
   {
      std::cerr << "errore nello stream\n";
      return 1;
   }
}
///////////////////////////////////////////////
Come si vede il *lavoro* viene fatto da sync().
In una implementazione con i socket ciò porta dei vantaggi perchè
si può testare se sync ha avuto successo ed usare così lo stream
in modo normale (senza che una richiesta di lettura blocchi
il sistema - ho visto una implementazione GNU di un socketbuf
in cui la lettura dal socket avviene in overflow -).
Ho comunque una domanda sui socket (che non conosco molto bene).
Hai scritto che con select() si può testare se un socket è pronto
a spedire dati. Ma quanti dati? 1 byte, 100 byte 10.000 byte?
E' possibile che, dato un max_size, il socket non sia mai in grado
di mandarlo tutto assieme?
Comunque se anche questa problematica si dovesse presentare, l'uso
dei chunks per il buffer risolve il problema.
Basta che sync spedisca solo i chunks che il socket è in grado di
spedire (ossia senza bloccare il sistema).
Quindi sync potrebbe restituire tre diversi valori rapprentanti
lo stato raggiunto:
 0:  tutti i chunks del buffer sono stati spediti
 -1: è occorso un errore nel socket ......
 1:  non tutti i chunks sono stati spediti (non è comunque un stato di
     errore).
Nota che se si usa std::ostream::flush (che a sua volta richiama
streambuf::pubsync()), un valore diverso da zero viene interpretato
come errore e pone lo stream in uno bad state, bisogna quindi
prestare atenzione.
Nota anche che un socket pronto per l'invio di dati deve poter spedire
almeno chunk_size caratteri.
Concludendo, una implemetazione di sync potremme controllare (tramite
select) se il socket è pronto per spedire dati, e spedire i chuncks
che si possono spedire (controllando i codici di ritorno per l'errore
EWOULDBLOCK).
Quindi nel tuo programma basta chiamare pubsync ad intervalli
regolari.
L'implementazione di uno streambuf per la lettura è più complessa,
ma non di molto. Se ho tempo posto come implementerei la cosa.
Spero di essere stato chiaro (è comunque evidente che dovresti
studiare un reference sui streambuf e sull'iostream in generale).
Ciao   Manlio Perillo

 studiare un reference sui streambuf e sull'iostream in generale).
Eh, lo so, lo so benissimo :-)
Vedrò che posso fare... al momento non ho (più) molto tempo per programmare,
come capita sempre quando si decide di iniziare a scrivere un programma per
hobby :-/
Massimo

 di mandarlo tutto assieme?
Si`, e` possibile,  ma non te ne devi  preoccupare. Per ogni interfaccia
di rete  e` definito  di un  MTU (Maximum  Transmit Unit)  e di  una MRU
(Maximum Receive Unit). Quando  passi i dati al socket,  l'OS provvede a
dividerli in modo che dimesione  pacchetto IP (header+payload) < MTU. Se
poi l'host ricevente non e` in grado di leggere questi pacchetti perche`
troppo  grossi inviera`  un imcp-fragmentation-needed. Il  nostro OS  si
preoccupera`  quindi di  frammentare  ulteriormente il  pacchetto. Tutto
questo pero` avviene  ad un livello piu` basso  delle chiamate send/recv
e,  a  meno che  tu  non  stia riscrivendo  lo  stack,  non te  ne  devi
preoccupare
ciao
Kronos 
-- 
Home: 
http://kronoz.cjb.net
"Another Brick in the Wall part 2"
We don't need no pull-down-menus
We don't need no rescaled fonts
No dark icons in the corner
Hackers, leave those Macs alone.
Hey! Hackers! Leave them Macs alone!
All in all it's just another WIMP up for sale
All in all you're just another WIMP up for the sale.