1 //=============================================================================
3 * @file IOStream_Test.cpp
5 * This is a simple test of the IOStream class that illustrates
6 * how to use iostream operations on almost arbitrary I/O classes.
8 * @author James CE Johnson <jcej@lads.com>
10 //=============================================================================
13 #include "test_config.h"
14 #include "ace/Thread.h"
15 #include "ace/Acceptor.h"
16 #include "ace/SOCK_Connector.h"
17 #include "ace/SOCK_Acceptor.h"
18 #include "ace/IOStream.h"
19 #include "ace/OS_NS_sys_wait.h"
21 #if !defined (ACE_LACKS_ACE_IOSTREAM)
22 # include "ace/OS_NS_unistd.h"
23 # include "ace/OS_NS_ctype.h" // Needed for isspace() function
25 typedef ACE_IOStream
<ACE_SOCK_Stream
> ACE_SOCK_IOStream
;
27 /* The biggest drawback to an iostream is that it generally
28 eats up whitespace when performing a get (>>) operation.
30 That may be good if you're reading non-textual data but
31 if you're trying to read a stream of words with embedded
32 whitespace, it isn't going to be pleasant.
34 If you've been blessed with the GNU String class, I've
35 already provided a derived class, QuotedString, that
36 makes dealing with strings very easy.
38 If you're stuck with an array of characters then you
39 will probably need somthing like I have below.
41 On the other hand, one of the biggest advantages to an
42 iostream is that it eats up whitespace :-)
44 If you put (<<) your non-textual data to the iostream
45 with any number of whitespace between the data then
46 you can easily get (>>) the data from the iostream
47 without having to worry about delimeters and such.
49 The main thing to keep in mind when using an iostream
50 between peers is that you MUST keep the data "fields"
51 in sync. That is, if the "putter" puts an int followed
52 by a float followed by a double, you must make sure
53 that the "getter" will be attempting to get an int
54 then a float then a double.
57 // Since I can't rely on GNU's String class being everywhere (yet),
58 // here's a simple class that will work with quoted strings. Use at
59 // your own risk! It is very incomplete!
64 qchar () { c_
= '\0'; }
66 qchar (char c
) : c_ (c
) { };
68 operator char () const { return c_
; }
70 qchar
operator= (char c
) { return c_
= c
; }
72 bool operator== (char c
) { return c_
== c
; }
74 friend ACE_SOCK_IOStream
&operator>> (ACE_SOCK_IOStream
& stream
, qchar
* buf
);
75 friend ACE_SOCK_IOStream
&operator<< (ACE_SOCK_IOStream
& stream
, qchar
* buf
);
76 friend ostream
&operator<< (ostream
& stream
, qchar
* buf
);
82 // This is taken almost directly from the QuotedString object that has
83 // been derived from GNU's String class. The advantage to using
84 // QuotedString is that it is MUCH more robust than qchar will every
88 operator>> (ACE_SOCK_IOStream
& stream
, qchar
*buf
)
92 *buf
= '\0'; // Initialize the string
96 if (!stream
) // eat space up to the first char
99 // if we don't have a quote, append until we see space
102 (void *) stream
.get (c
) && !ACE_OS::ace_isspace (c
);
106 for (; (void *) stream
.get (c
) && c
!= '"'; *buf
++ = c
)
120 operator<< (ACE_SOCK_IOStream
&stream
, qchar
*buf
)
129 stream
.put ((char) *buf
++);
138 operator<< (ostream
&stream
, qchar
*buf
)
141 stream
.put ((char) *buf
++);
146 // Our client thread will initiate the test by sending some data to
150 client (void *arg
= 0)
152 ACE_UNUSED_ARG (arg
);
154 // We don't _need_ to dynamically allocate the ACE_SOCK_IOStream.
155 // But if we don't, it doesn't get destroyed on some platforms,
156 // If we manage the storage ourselves, we _will_ destroy it at
157 // the end of this function.
158 ACE_SOCK_IOStream server
;
160 ACE_INET_Addr
*remote_addr
= (ACE_INET_Addr
*) arg
;
161 ACE_INET_Addr
addr (remote_addr
->get_port_number (),
162 ACE_DEFAULT_SERVER_HOST
);
163 ACE_SOCK_Connector connector
;
165 if (connector
.connect (server
, addr
) == -1)
166 ACE_ERROR_RETURN ((LM_ERROR
,
167 ACE_TEXT (" (%t) %p\n"),
168 ACE_TEXT ("Failed to connect to server thread")),
171 // Send a string to the server which it can interpret as a qchar[]
172 const char *str
= "\"This is a test string.\"";
173 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) Client Sending: (%C)\n"),
175 server
<< str
<< endl
;
177 // Allow the server to get the string and echo it to the user. (The
178 // iostream doesn't need this, but humans do :)
181 // Send another string but this time the server will read it as a
182 // char[]. Notice how the server's output doesn't include all of
183 // the spaces sent by the client.
185 str
= "\"THIS IS A TEST STRING.\"";
186 ACE_DEBUG ((LM_DEBUG
,
187 ACE_TEXT (" (%P|%t) Client Sending: (%s)\n"),
189 server
<< str
<< endl
;
191 // Again, give the server time to display the happenings to the
195 // Read from the server an int, float, long, float double. The
196 // iostream will pull them out by using the whitespace provided by
199 ACE_DEBUG ((LM_DEBUG
,
200 ACE_TEXT (" (%P|%t) Client Receiving\n")));
202 ACE_Time_Value
timeout (2);
203 ACE_Time_Value
*timeoutp
= &timeout
;
212 while (! (server
>> i
))
214 int eof
= server
.eof ();
217 ACE_DEBUG ((LM_DEBUG
,
218 ACE_TEXT (" (%P|%t) Unrecoverable stream error/eof\n")));
223 ACE_DEBUG ((LM_DEBUG
,
224 ACE_TEXT (" (%P|%t) Recoverable stream error/timed out)\n")));
234 ACE_DEBUG ((LM_DEBUG
,
235 ACE_TEXT (" (%P|%t) Client Received: int %d float %f long %d float %f double %f\n"),
242 // Check for proper received values.
243 ACE_TEST_ASSERT (i
== 1 && (f1
>= 0.123420 && f1
<= 0.123422)
244 && l
== 666555444 && (f2
>= 23.44 && f2
<= 23.46)
245 && (d
>= -47.1e+9 && d
<= -45.9e+9));
246 // Reset the precision to limit ourselves to two significant digits.
247 server
.precision (2);
249 // Now, make a little change & send 'em back.
250 i
*= -1; server
<< i
<< " ";
251 f1
*= -1.0; server
<< f1
<< " ";
252 l
*= -1; server
<< l
<< " ";
253 f2
*= -1.0; server
<< f2
<< " ";
254 d
*= -1; server
<< d
<< " ";
257 // Shut down the test.
263 // Test the server's ability to receive data from the client and then
264 // begin a two-way conversation.
267 server (void *arg
= 0)
269 // We don't _need_ to dynamically allocate the ACE_SOCK_IOStream.
270 // But if we don't, it doesn't get destroyed on some platforms,
271 // If we manage the storage ourselves, we _will_ destroy it at
272 // the end of this function.
273 ACE_SOCK_IOStream client_handler
;
275 ACE_INET_Addr server_addr
;
276 ACE_SOCK_Acceptor
*acceptor
=
277 reinterpret_cast<ACE_SOCK_Acceptor
*> (arg
);
279 if (acceptor
->get_local_addr (server_addr
) == -1)
280 ACE_ERROR_RETURN ((LM_ERROR
,
282 ACE_TEXT ("get_local_addr")),
285 #if defined (ACE_HAS_THREADS)
286 if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (client
),
287 (void *) &server_addr
,
288 THR_NEW_LWP
| THR_DETACHED
) == -1)
289 ACE_ERROR_RETURN ((LM_ERROR
,
290 ACE_TEXT (" (%t) %p\n"),
291 ACE_TEXT ("spawing client thread")),
293 #endif /* ACE_HAS_THREADS */
295 if (acceptor
->accept (client_handler
) == -1)
296 ACE_ERROR_RETURN ((LM_ERROR
,
297 ACE_TEXT (" (%P|%t) Failed to accept new client_handler")),
300 // Read a qbuf[] from the client. Notice that all of the client's
301 // whitespace is preserved.
303 ACE_OS::memset (qbuf
, 0, sizeof qbuf
);
304 client_handler
>> qbuf
;
306 ACE_DEBUG ((LM_DEBUG
,
307 ACE_TEXT (" (%P|%t) Server Received: (\"%C\")\n"),
310 // Give the client time to announce the next test to the user.
313 // Now we try to use a char[] to get a string from the client.
314 // Compared to the method above, this is quite messy. Notice also
315 // that whitespace is lost.
317 ACE_IOStream_String buf
;
318 ACE_DEBUG ((LM_DEBUG
,
319 " (%P|%t) Server Received: ("));
321 while (client_handler
&&
322 (buf
.length () == 0 || buf
[buf
.length () - 1] != '"'))
324 if (! (client_handler
>> buf
))
327 if (buf
.length () > 0)
328 ACE_DEBUG ((LM_DEBUG
,
333 ACE_DEBUG ((LM_DEBUG
,
336 // Send some non-textual data to the client. We use a single
337 // character to separate the fields but we could have used any valid
338 // whitespace. The data will be sent if the iostream's buffer gets
339 // filled or when we flush it with an explicit client.sync ()
340 // command or the implicit <<endl.
342 ACE_DEBUG ((LM_DEBUG
,
343 ACE_TEXT (" (%P|%t) Server sleeping\n")));
346 ACE_DEBUG ((LM_DEBUG
,
347 ACE_TEXT (" (%P|%t) Server Sending: 1 .12342134 666555444 23.45 -46.5e9\n")));
348 client_handler
<< 1 << " ";
349 client_handler
<< .12342134 << " ";
350 client_handler
<< 666555444 << " ";
351 client_handler
<< 23.45 << " ";
352 client_handler
<< -46.5e9
<< " ";
353 client_handler
<< endl
;
355 // The client will have changed the sign of each data field and sent
356 // 'em all back to us. At the same time, the client used the
357 // precision () function to change the significant digits for
358 // non-integer values.
363 client_handler
>> i
>> f1
>> l
>> f2
>> d
;
365 ACE_DEBUG ((LM_DEBUG
,
366 ACE_TEXT (" (%P|%t) Server Received: int %d float %f long %d float %f double %f\n"),
373 // check for proper received values
374 ACE_TEST_ASSERT (i
== -1 && (f1
>= -0.13 && f1
<= -0.11)
375 && l
== -666555444 && (f2
>= -24.0 && f2
<= -22.0)
376 && (d
>= 45e+9 && d
<= 47e+9));
378 client_handler
.close ();
387 ACE_SOCK_Acceptor acceptor
;
389 if (acceptor
.open (ACE_sap_any_cast (const ACE_INET_Addr
&)) == -1)
390 ACE_ERROR_RETURN ((LM_ERROR
,
391 ACE_TEXT (" (%P|%t) %p\n"),
394 #if defined (ACE_HAS_THREADS)
395 else if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (server
),
397 THR_NEW_LWP
| THR_DETACHED
) == -1)
398 ACE_ERROR_RETURN ((LM_ERROR
,
400 ACE_TEXT ("spawning server thread")),
403 // Wait for the client and server thread to exit.
404 ACE_Thread_Manager::instance ()->wait ();
406 #elif !defined (ACE_LACKS_FORK)
408 switch (ACE_OS::fork ("child"))
411 ACE_ERROR ((LM_ERROR
,
413 ACE_TEXT ("fork failed")));
417 ACE_APPEND_LOG ("IOStream_Test-children");
418 ACE_INET_Addr server_addr
;
420 if (acceptor
.get_local_addr (server_addr
) == -1)
421 ACE_ERROR ((LM_ERROR
,
423 ACE_TEXT ("get_local_addr")));
425 client ((void *) &server_addr
);
429 default: // In parent
432 // Allow the client to exit, then remove the Process_Mutex.
437 ACE_ERROR_RETURN ((LM_INFO
,
438 ACE_TEXT ("threads *and* processes not supported on this platform\n")),
440 #endif /* ACE_HAS_THREADS */
446 #endif /* !ACE_LACKS_ACE_IOSTREAM */
449 run_main (int, ACE_TCHAR
*[])
451 ACE_START_TEST (ACE_TEXT ("IOStream_Test"));
453 #if !defined (ACE_LACKS_ACE_IOSTREAM)
454 ACE_INIT_LOG (ACE_TEXT ("IOStream_Test-children"));
458 ACE_TEXT ("ACE_IOSTREAM not supported on this platform\n")));
459 #endif /* !ACE_LACKS_ACE_IOSTREAM */