Sophie

Sophie

distrib > Mandriva > 2007.0 > i586 > by-pkgid > ad1ba1135a9c9eeffc2e538163e00373 > files > 611

libCommonC++2_1.4-devel-1.4.1-1mdv2007.0.i586.rpm

\section{Sample\-Socket\-Port.cpp}


\footnotesize\begin{verbatim}1 
48 #include "SampleSocketPort.h"
49 
50 SampleSocketPort::SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket) : 
51                                 SocketPort(pService, tcpSocket)
52 {
53         tpport_t port;
54         InetHostAddress ia = getPeer( & port );
55         cerr << "connecting from " << ia.getHostname() << ":" << port << endl;
56 
57         // Set up non-blocking reads
58         setCompletion( false );
59 
60         //1.9.3 THIS LINE DOES NOT SEEM TO BE REQUIRED ANYMORE!
61         //This sorts out a bug which prevents connections after a disconnect
62         //setDetectOutput(true);
63 
64         m_bOpen = true;
65         m_bDoDisconnect = false;
66         m_bTimedOut = false;
67         m_bReceptionStarted = false;
68         m_nLastBytesAvail = 0;
69         m_pBuf = new char[MAX_RXBUF];
70 }
71 
72 
73 SampleSocketPort::~SampleSocketPort()
74 {
75         endSocket();
76         delete [] m_pBuf;
77 }
78 
79 void SampleSocketPort::pending(void)
80 {
81 //cerr << "Pending called " << endl;
82         if(!m_bOpen)
83                 return;
84 
85         // Read all available bytes into our buffer
86         int nBytesAvail = peek(m_pBuf, MAX_RXBUF);
87 //cerr << "Pending .. " << nBytesAvail << endl;
88 
89         if(!m_bReceptionStarted)
90         {       //Start the receive timer
91                 ResetReadTimeout(MAX_RXTIMEOUT);        //Got 'n' seconds to get all the data else we timeout
92                 m_bReceptionStarted = true;
93         }
94         else
95         {
96                 if(m_bTimedOut) //The receive timer has expired...this is a timeout condition
97                 {
98                         ResetReadTimeout(MAX_RXTIMEOUT); //Clear the timeout flag
99                         m_nLastBytesAvail = 0;          //Reset the flags
100                         m_bReceptionStarted = false;
101                         OnRxTimeout();  //Do whatever 'we' do for a timeout (probably a flush or disconnect)...
102                         return;
103                 }
104         }
105 
106         if(m_nLastBytesAvail == nBytesAvail)    //Check if any more data has been received since last time
107         {                                                                               //No point in parsing unless this has changed!
108                 //Maybe yield in here!
109                 //Thread::yield();
110                 if(nBytesAvail == 0)            //If we have been called with 0 bytes available (twice now)
111                 {                                                       //a disconnection has occurred
112                         if(!m_bDoDisconnect)
113                         {
114                                 CloseSocket();  //Force the close
115                         }
116                 }
117                 return;
118         }
119 
120         //Depending on your application you may want to attempt to process the extra data 
121         //(or change your MAX_RXBUF).
122         //
123         //Here I just flush the whole lot, because I assume a 'legal' client wont send more than
124         //we can receive....maybe someone is trying to flood / overrun us!
125         if(nBytesAvail > MAX_RXBUF)     
126         {
127                 cerr << "TCP/IP overflow..." << endl;
128                 FlushRxData();
129                 m_nLastBytesAvail = 0;
130                 m_bReceptionStarted = false;
131                 return;
132         }
133         m_nLastBytesAvail = nBytesAvail;
134 
135         //In this loop you may parse the received data to determine whether a whole
136         //'packet' has arrived. What you do in here depends on what data you are sending.
137         //Here we will just look for a /r/n terminator sequence.
138         for(int i=0; i < nBytesAvail; i++)
139         {
140 
141 /***************************SHOULD BE CUSTOMISED*******************/
142 
143                 if(m_pBuf[i] == '\r')
144                 {
145                         if(i+1 < nBytesAvail)
146                         {
147                                 if(m_pBuf[i+1] == '\n')
148                                 {       //Terminator sequence found
149 
150                                         /**************************************************************/
151                                         // COMPULSORY ... Clear the flag and count..
152                                         // do this when you have received a good packet
153                                         m_nLastBytesAvail = 0;
154                                         m_bReceptionStarted = false;
155                                         /**************************************************************/
156 
157                                         // Now receive the data into a buffer and call our receive function
158                                         int nLen = i+2;
159                                         char *pszRxData = new char[nLen+1];     //Allow space for terminator
160                                         receive(pszRxData, nLen);               //Receive the data
161                                         pszRxData[nLen] = '\0';         //Terminate it
162                                         OnDataReceived(pszRxData, nLen);
163                                         delete [] pszRxData;
164                                         return;
165                                 }
166                         }
167                 }
168 /***************************END CUSTOMISATION*******************/
169 
170         }
171 }
172 
173 void SampleSocketPort::disconnect(void)
174 {
175         if(m_bOpen)
176         {
177                 m_bDoDisconnect = true;
178                 CloseSocket();
179         }
180 }
181 
182 void SampleSocketPort::expired(void)
183 {
184         if(m_bDoDisconnect && m_bOpen)
185         {
186                 CloseSocket();
187         }
188         else if(m_bOpen && m_bReceptionStarted)
189         {
190                 //Timer must have expired because the rx data has not all been received
191                 m_bTimedOut = true;
192         }
193 }
194 
195 
196 bool SampleSocketPort::CloseSocket(void)
197 {
198         if(m_bOpen && m_bDoDisconnect)
199         {                                                                       //This is where the disconnection really occurs
200                 m_bOpen = false;                                //If m_bDoDisconnect == true we know this has been called 
201                 OnConnectionClosed();                   //through the timer, so 'delete this' is safe!
202                 delete this;
203         }
204         else if(m_bOpen)
205         {
206                 m_bDoDisconnect = true;                 //Just set the timer and the flag so we can 
207                 setTimer(DISCONNECT_MS);                //disconnect safely, in DISCONNECT_MS
208         }
209         return(true);
210 }
211 
212 
213 ssize_t SampleSocketPort::DoSend(void *buf, size_t len)
214 {
215         //If we are disconnecting, just pretend all the bytes were sent
216         if(m_bDoDisconnect)
217                 return((ssize_t)len);
218 
219         ssize_t nSent = send(buf, len);
220         while(!isPending(Socket::pendingOutput, 0))             //Wait for output to complete
221         {
222                 if(m_bDoDisconnect || !m_bOpen)
223                 {
224                         //If we are disconnecting, just pretend all the bytes were sent
225                         return((ssize_t)len);
226                 }
227                 //I like to yield whenever waiting for things...
228                 //this is optional and may not suit your implementation!
229                 Thread::yield();
230         }
231         return(nSent);
232 }
233 
234 bool SampleSocketPort::WriteData(const char *szTxData, const size_t nByteCount)
235 {
236         //First calculate how many bytes we are to send
237         ssize_t nLen = nByteCount;
238 
239         if(nLen == -1)
240                 nLen = (ssize_t)strlen(szTxData);
241 
242         size_t nBytesToSend = nLen;
243 
244         while(m_bOpen && nLen)
245         {
246                 nLen -= DoSend((void *)&(szTxData[nBytesToSend - nLen]), nLen);
247         }
248 
249 //      If we are sending a terminator.....uncomment the following lines
250 //      char chTerminator = '\n';
251 //      while(DoSend((void *)&chTerminator, 1) != 1);
252 
253         return(true);
254 }
255 
256 
257 
258 #define WITH_EXAMPLE
259 
260 #ifdef WITH_EXAMPLE
261 
262 
263 /************ THE FOLLOWING CODE DEMONSTRATES THE USE OF THE ABOVE CLASS ********************
264  ****
265  ****   To test it, compile with:
266  ****           
267  ****   g++ SampleSocketPort.cpp -lccgnu -lpthread -ldl -oSampleSocketPort -ggdb -I/usr/local/include/cc++/
268  ****   Run the program.
269  ****   
270  ****   From another terminal telnet to port 3999 of the server
271  ****   
272  ****           'telnet localhost 3999'
273  ****           
274  ****   Anything you type should be sent back to you in reverse!
275  ****   
276  ****   To test the corrupt data detection, send a control code (like ^D),
277  ****   if the terminating charcters are not detected within the specified time
278  ****   the receive timeout will occur.
279  ****   
280  ****/
281 
282 
283 //define the following to include the example classes and functions
284 
285 int g_nOpenPorts = 0;                   //Dirty global to allow us to quit simply
286 
287 class ReverserPort : public SampleSocketPort
288 {
289 public:
290         ReverserPort(SocketService *pService, TCPSocket & tcpSocket) : 
291                         SampleSocketPort(pService, tcpSocket)
292         {
293                 g_nOpenPorts++;
294         }
295         virtual ~ReverserPort()
296         {
297                 g_nOpenPorts--;
298         }
299         virtual void OnConnectionClosed(void)
300         { cerr << "Connection Closed!" << endl; }
301 
306         virtual void OnDataReceived(char *pszData, unsigned int nByteCount)
307         {
308                 //Reverse the data and send it back
309 
310                 size_t nLen = strlen(pszData);
311                 char *szToSend = new char[nLen+1];
312                 
313                 //No need to reverse the \r\n or \0
314                 size_t nIndex = nLen-3;
315 
316                 size_t i;
317                 for(i=0; i < nLen - 2; i++)
318                 {
319                         szToSend[i] = pszData[nIndex - i];
320                 }
321                 szToSend[i++] = '\r';
322                 szToSend[i++] = '\n';
323                 szToSend[nLen] = '\0';
324 
325                 WriteData(szToSend, nLen);
326                 delete [] szToSend;
327         }
328 
329 };
330 
331 class ReverserServer : public SampleSocketServiceServer
332 {
333 public:
334         ReverserServer(InetHostAddress & machine, int port) : 
335         TCPSocket(machine, port), Thread(), SampleSocketServiceServer(machine, port)
336         {
337         }
338         virtual ~ReverserServer()
339         {
340         }
341         virtual SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket)
342         {
343                 return(new ReverserPort(pService, Socket));
344         }
345 };
346 
347 
348 int main(void)
349 {
350         InetHostAddress LocalHost;
351         LocalHost = htonl(INADDR_ANY);
352         ReverserServer *Server = NULL;
353         try
354         {
355                 Server = new ReverserServer(LocalHost, 3999);
356                 Server->StartServer();
357         }
358         catch(...)
359         {
360                 cerr << "Failed to start server" << endl;
361                 return(false);
362         }
363         cerr << "Waiting for connections...type \"quit\" to exit." << endl;
364 
365         char cmd[255];
366  
367         cin.getline(cmd, 255);
368 
369 
370         while(strcmp(cmd, "quit") != 0)
371         {
372                 cin.getline(cmd, 255);
373         }
374  
375         Server->StopServer();
376         delete Server;
377         return 0;       
378 }
379 
380 #endif  //WITH_EXAMPLE
381 
\end{verbatim}
\normalsize