summaryrefslogtreecommitdiff
path: root/docs/tutorials/008/page04.html
blob: 5960fe8a27e5a0a7a4150f8b004e5f70a7623748 (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
<!-- $Id$ -->
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
   <META NAME="Author" CONTENT="James CE Johnson">
   <TITLE>ACE Tutorial 008</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>

<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>


<P>
<HR WIDTH="100%">

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.

<P>I've only commented the parts that are different from the directed_client.
<HR WIDTH="100%">
<PRE>
<font color=red>// $Id$</font>

<font color=blue>#include</font> "<A HREF="../../../ace/SOCK_Dgram_Bcast.h">ace/SOCK_Dgram_Bcast.h</A>"
<font color=blue>#include</font> "<A HREF="../../../ace/INET_Addr.h">ace/INET_Addr.h</A>"

static const u_short PORT = ACE_DEFAULT_SERVER_PORT;

int
main (int argc,char *argv[])
{
  ACE_UNUSED_ARG(argc);
  ACE_UNUSED_ARG(argv);

  ACE_INET_Addr local ((u_short) 0);

  <font color=red>/* Instead of creating the ACE_SOCK_Dgram we created last time,
    we'll create an ACE_SOCK_Dgram_Bcast.  "<font color=green>Bcast</font>" means, of course,
    "<font color=green>Broadcast</font>".  This ACE object is clever enough to go out to the OS
    and find all of the network interfaces.  When you send() on a
    Dgram_Bcast, it will send the datagram out on all of those
    interfaces.  This is quiet handy if you do it on a multi-homed
    host that plays router...  */</font>
  ACE_SOCK_Dgram_Bcast dgram;

  if (dgram.open (local) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "<font color=green>%p\n</font>",
                       "<font color=green>datagram open</font>"),
                      -1);

  char buf[BUFSIZ];

  sprintf (buf, "<font color=green>Hello World!</font>");

  <font color=red>/* The only other difference between us and the directed client is
    that we don't specify a host to receive the datagram.  Instead, we
    use the magic value "<font color=green>INADDR_BROADCAST</font>".  All hosts are obliged to
    respond to datagrams directed to this address the same as they
    would to datagrams sent to their hostname.

    Remember, the Dgram_Bcast will send a datagram to all interfaces
    on the host.  That's true even if the address is for a specific
    host (and the host address makes sense for the interface).  The
    real power is in using an INADDR_BROADCAST addressed datagram
    against all interfaces.  */</font>

  ACE_INET_Addr remote (PORT,
                        INADDR_BROADCAST);

  ACE_DEBUG ((LM_DEBUG,
              "<font color=green>(%P|%t) Sending (%s) to the server.\n</font>",
              buf));

  if (dgram.send (buf,
                  <font color=#008888>ACE_OS::strlen</font> (buf) + 1,
                  remote) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "<font color=green>%p\n</font>",
                       "<font color=green>send</font>"),
                      -1);

  if (dgram.recv (buf,
                  sizeof (buf),
                  remote) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "<font color=green>%p\n</font>",
                       "<font color=green>recv</font>"),
                      -1);

  ACE_DEBUG ((LM_DEBUG,
              "<font color=green>(%P|%t) The server said:  %s\n</font>",
              buf));

  <font color=red>/* Using the "<font color=green>remote</font>" object instance, find out where the server
    lives.  We could then save this address and use directed datagrams
    to chat with the server for a while.  */</font>
  ACE_DEBUG ((LM_DEBUG,
              "<font color=green>(%P|%t) The server can be found at:  (%s:%d)\n</font>",
              remote.get_host_name(),
              PORT));

  return 0;
}
</PRE>
<HR WIDTH="100%">

<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>

<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>