summaryrefslogtreecommitdiff
path: root/docs/tutorials/008/combine.shar
blob: 3ff0c16dcb6e1333f97634e8795e0cdae3a8f81c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1999-09-21 22:49 EDT by <jcej@chiroptera.tragus.org>.
# Source directory was `/home/jcej/projects/ACE_wrappers/docs/tutorials/008'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    515 -rw-rw-r-- hdr
#     59 -rw-rw-r-- bodies
#   2769 -rw-rw-r-- page01.pre
#    416 -rw-rw-r-- page02.pre
#    345 -rw-rw-r-- page03.pre
#    481 -rw-rw-r-- page04.pre
#    578 -rw-rw-r-- page05.pre
#    952 -rw-rw-r-- page02.pst
#    367 -rw-rw-r-- page03.pst
#   1173 -rw-rw-r-- page04.pst
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh04873; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= hdr ==============
if test -f 'hdr' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'hdr' '(file already exists)'
else
  $echo 'x -' extracting 'hdr' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'hdr' &&
<HTML>
<HEAD>
X   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
X   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
X   <META NAME="Author" CONTENT="James CE Johnson">
X   <TITLE>ACE Tutorial 008</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
X
<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>
X
<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>
X
X
<P>
<HR WIDTH="100%">
X
SHAR_EOF
  $shar_touch -am 0121153899 'hdr' &&
  chmod 0664 'hdr' ||
  $echo 'restore of' 'hdr' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'hdr:' 'MD5 check failed'
e74ecd3335da844c263f961a8ba5f867  hdr
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`"
    test 515 -eq "$shar_count" ||
    $echo 'hdr:' 'original size' '515,' 'current size' "$shar_count!"
  fi
fi
# ============= bodies ==============
if test -f 'bodies' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'bodies' '(file already exists)'
else
  $echo 'x -' extracting 'bodies' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'bodies' &&
PAGE=2
server.cpp
directed_client.cpp
broadcast_client.cpp
SHAR_EOF
  $shar_touch -am 0121153799 'bodies' &&
  chmod 0664 'bodies' ||
  $echo 'restore of' 'bodies' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'bodies:' 'MD5 check failed'
707d1735ca25694e2b5fddc1f6e7e124  bodies
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`"
    test 59 -eq "$shar_count" ||
    $echo 'bodies:' 'original size' '59,' 'current size' "$shar_count!"
  fi
fi
# ============= page01.pre ==============
if test -f 'page01.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page01.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page01.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' &&
<P>In a lot of IPC&nbsp;programming, the clients know where the servers
are.&nbsp; A mail client, for instance, has a configuration file that says
where the mail host is.&nbsp; Your web browser has a "location" field that
you type into to give it a destination.
X
<P>What if you have written a server application and then you execute it
on several systems in your network?&nbsp; All of the instances are probably
more or less equal to the client's point of view, so you don't want to
"configure"&nbsp;the clients to a single server each.&nbsp; Likewise, you
want the ability to add and remove servers at any time so you can't just
give the clients a list to choose from.
X
<P>So... how do the clients know where the servers are?
X
<P>Let 'em ask!
X
<P>Datagrams are great for this.&nbsp; You can toss a datagram out onto
the network and any servers listening at the correct port will* hear it.&nbsp;
Like ACE_SOCK_Stream that we've seen before, you can get the peer address
from a datagram.&nbsp; With that, the server can&nbsp; send a response
back to the client.&nbsp; The client, in turn, can pull the peer address
out and know exactly where the server lives.
X
<P>In this tutorial we'll develop three applications:&nbsp; a server listening
for datagrams, a client that can send to a known host and a client that
can send to the entire (sub)network.&nbsp; In the next tutorial, we'll
expand on this to make the server a bit more prudish.
<P>
Kirthika's abstract:
<UL>
Here, we play with datagram sockets and use it for server discovery by
the client. Datagrams are used by UDP, which  is an unreliable and
connectionless protocol. Datagrams packets are generally very small in
size and aren't designed to be used to handle serious communication
between the server and the client.
<P>
The server waits for datagrams to arrive at a fixed port.
The client either sends to a datagram to the server at a known host,
which is not really the case generally, as the client needs to discover
the server and so it needs to broadcast its datagram request in its
subnet. Then, all servers listening at that interface receive it. The
appropriate server will then handle the request. Remember that
no solid connection is made. On the recv() itself the server obtains the
address of the remote client and then communicates with it.
<P>
Thus, we get a fair glimpse of using another means of communication via
datagrams.  
</UL>
<P><FONT SIZE=-1>*&nbsp;Actually, the servers <I>might</I> hear the datagram.&nbsp;
Datagrams are rather unreliable.&nbsp; (Sort of like some operating systems
I know.)&nbsp; Still, if the network traffic isn't too bad, they generally
get through.&nbsp; Your clients can always send out more queries if there
aren't any responses in a timely fashion.</FONT>
X
SHAR_EOF
  $shar_touch -am 0121155099 'page01.pre' &&
  chmod 0664 'page01.pre' ||
  $echo 'restore of' 'page01.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page01.pre:' 'MD5 check failed'
829e35e4a7b8e8c75e38abf492033395  page01.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`"
    test 2769 -eq "$shar_count" ||
    $echo 'page01.pre:' 'original size' '2769,' 'current size' "$shar_count!"
  fi
fi
# ============= page02.pre ==============
if test -f 'page02.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page02.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page02.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' &&
X
<P>The first thing we want to look at is <A HREF="server.cpp">server.cpp</A>.&nbsp;
This is a pretty simple application that listens for datagrams at a known
port and sends back a response.&nbsp; In order to implement a true "discovery"&nbsp;
mechanism, the server will have to be a little bit more picky about who
it responds to.&nbsp; We'll tackle that issue in the next tutorial though...
X
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0121153899 'page02.pre' &&
  chmod 0664 'page02.pre' ||
  $echo 'restore of' 'page02.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page02.pre:' 'MD5 check failed'
6b27ef52d53a13d2d9e5a5ad16e9be4d  page02.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`"
    test 416 -eq "$shar_count" ||
    $echo 'page02.pre:' 'original size' '416,' 'current size' "$shar_count!"
  fi
fi
# ============= page03.pre ==============
if test -f 'page03.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page03.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page03.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' &&
X
<P>In <A HREF="directed_client.cpp">directed_client.cpp</A> we create a
client that knows how to send a datagram to a server on a known host.&nbsp;
This is a good thing if you know where the server lives and want to have
a conversation.&nbsp;&nbsp; The Unix <I>talk</I> utilitiy, for instance,
could be written this way.
X
<P>
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0121153899 'page03.pre' &&
  chmod 0664 'page03.pre' ||
  $echo 'restore of' 'page03.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page03.pre:' 'MD5 check failed'
aa0724ca0a09f5b5e6c7e3f355646111  page03.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`"
    test 345 -eq "$shar_count" ||
    $echo 'page03.pre:' 'original size' '345,' 'current size' "$shar_count!"
  fi
fi
# ============= page04.pre ==============
if test -f 'page04.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page04.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page04.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' &&
In <A HREF="broadcast_client.cpp">broadcast_client.cpp</A> we
find out how to send a single datagram to every host on our (sub)network.&nbsp;
I have to say <I>(sub)network</I> because broadcast datagrams typically
are not passed through routers.&nbsp; So, if your network admin has divided
up your network into subnets, your broadcasts will likey stay on the
subnet you're a part of.
X
<P>I've only commented the parts that are different from the directed_client.
<HR WIDTH="100%">
SHAR_EOF
  $shar_touch -am 0124144899 'page04.pre' &&
  chmod 0664 'page04.pre' ||
  $echo 'restore of' 'page04.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page04.pre:' 'MD5 check failed'
8811bded669a7a7be85a4878d5076190  page04.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`"
    test 481 -eq "$shar_count" ||
    $echo 'page04.pre:' 'original size' '481,' 'current size' "$shar_count!"
  fi
fi
# ============= page05.pre ==============
if test -f 'page05.pre' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page05.pre' '(file already exists)'
else
  $echo 'x -' extracting 'page05.pre' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' &&
<BR>That's it for this tutorial.&nbsp; In the next one we'll add some intelligence
to the data put into the datagrams.&nbsp; By doing so, we'll be able to
classify our clients and servers into groups.&nbsp; By combining the data
content and the server's port we can get fairly fine-grained control over
who talks to who.
X
<P>For you convenience:
<UL>
<LI>
<A HREF="server.cpp">server.cpp</A></LI>
X
<LI>
<A HREF="directed_client.cpp">directed_client.cpp</A></LI>
X
<LI>
<A HREF="broadcast_client.cpp">broadcast_client.cpp</A></LI>
X
<LI>
<A HREF="Makefile">Makefile</A></LI>
</UL>
SHAR_EOF
  $shar_touch -am 0121153799 'page05.pre' &&
  chmod 0664 'page05.pre' ||
  $echo 'restore of' 'page05.pre' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page05.pre:' 'MD5 check failed'
b05fdac8c7eb81813c74eb99525cf601  page05.pre
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`"
    test 578 -eq "$shar_count" ||
    $echo 'page05.pre:' 'original size' '578,' 'current size' "$shar_count!"
  fi
fi
# ============= page02.pst ==============
if test -f 'page02.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page02.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page02.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page02.pst' &&
<HR WIDTH="100%">
X
<P>And that's really all there is to it.&nbsp; Obviously there is some
room for improvement.&nbsp; The most blatant is the somewhat small buffer
size for receiving the datagram.&nbsp; I've never been able to get a solid
answer on datagram sizes.&nbsp; The theoretical limit is just under 64k
but you have to deal with fragmentation.&nbsp; Some readings indicate that
8k is a reasonable size, others go much smaller.&nbsp; My general rule
of thumb is to keep datagrams relatively small (eg -- under 8k or so) and
test a lot.&nbsp; If you find that your routers are fragmenting your larger
datagrams, back off to something smaller.&nbsp; Of course, if you must
send 100k and can only do so 1k at a time, you'll have to worry about retransmissions
&amp; reordering.&nbsp; At that point, you might consider going to TCP.&nbsp;
Remember:&nbsp; datagrams are unreliable!&nbsp; Don't try to make 'em do
something they werent' designed for!
SHAR_EOF
  $shar_touch -am 0121153899 'page02.pst' &&
  chmod 0664 'page02.pst' ||
  $echo 'restore of' 'page02.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page02.pst:' 'MD5 check failed'
3cb7da5f75a40616f6cc498a731f4a16  page02.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pst'`"
    test 952 -eq "$shar_count" ||
    $echo 'page02.pst:' 'original size' '952,' 'current size' "$shar_count!"
  fi
fi
# ============= page03.pst ==============
if test -f 'page03.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page03.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page03.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page03.pst' &&
<HR WIDTH="100%">
X
<P>That's all neat and good but the point of what we're doing here is not
to talk to a server we know about but to discover servers we don't know
about.&nbsp; Now, you could send a directed datagram to every possible
host address on your network but that's not a very nice thing to do.&nbsp;
On the next page, we'll find out the right approach...
X
SHAR_EOF
  $shar_touch -am 0121153899 'page03.pst' &&
  chmod 0664 'page03.pst' ||
  $echo 'restore of' 'page03.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page03.pst:' 'MD5 check failed'
0fcbc10be47175a0d42590fb4adab43b  page03.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pst'`"
    test 367 -eq "$shar_count" ||
    $echo 'page03.pst:' 'original size' '367,' 'current size' "$shar_count!"
  fi
fi
# ============= page04.pst ==============
if test -f 'page04.pst' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'page04.pst' '(file already exists)'
else
  $echo 'x -' extracting 'page04.pst' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'page04.pst' &&
<HR WIDTH="100%">
X
<P>&nbsp;About that subnet thing:
<BLOCKQUOTE>If you run this client on a host that has multiple network
interfaces, the broadcast will go to all of those (sub)networks.&nbsp;
What do you do, though, if you need to get past a router?&nbsp; My advice
is to write a server that will run on hosts on both sides of your router.&nbsp;
When a server on one side of the router receives a broadcast, it would
send a directed datagram to it's counterpart on the other side of the router.&nbsp;
The counterpart would then re-broadcast the original datagram on that sub-net.&nbsp;
Cheap, simple and effective.</BLOCKQUOTE>
One final word of warning:
<BLOCKQUOTE>When creating your broadcast datagrams you may see something
like this:&nbsp; <I>ACE_SOCK_Dgram_Bcast::mk_broadcast: Broadcast is not
enable for this interface.: Unknown error</I>.&nbsp; There are some interfaces
(ppp, slip) that don't support broadcast datagrams.&nbsp; That's what you're
seeing here.</BLOCKQUOTE>
Ok, one more warning:
<blockquote>If you happen to have multiple servers running on your
network when you invoke this client, the response could come from any
one of them.
</blockquote>
X
SHAR_EOF
  $shar_touch -am 0126194899 'page04.pst' &&
  chmod 0664 'page04.pst' ||
  $echo 'restore of' 'page04.pst' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'page04.pst:' 'MD5 check failed'
2e01fc6b6638dfa77ed629c0e3e77e21  page04.pst
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pst'`"
    test 1173 -eq "$shar_count" ||
    $echo 'page04.pst:' 'original size' '1173,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh04873
exit 0