summaryrefslogtreecommitdiff
path: root/docs/tutorials/015/page15.html
blob: be4d3e464a038cb0432b0e3a43b5799b7b8a7604 (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
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="James CE Johnson">
   <TITLE>ACE Tutorial 015</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

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

<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER>

<P>
<HR WIDTH="100%">
Recv is the sibling to Xmit.  Again, they could be combined into a
single object if you want.
<P>
An ACE_Stream is designed to handle downstream traffic very
well.  You put() data into it and it flows along towards the tail.
However, there doesn't seem to be a way to put data in such that it
will travel upstream.  To get around that, I've added a get() method
to Recv that will trigger a read on the socket.  Recv will then put
the data to the next upstream module and we're on our way.  As noted
earlier, that data will eventually show up either in the <i>reader</i> 
(if installed on the stream open()) or the stream head reader task's
message queue.
<HR>
<PRE>

<font color=red>// $Id$</font>

<font color=blue>#include</font> "<font color=green>Xmit.h</font>"
<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>"

<font color=red>/* Construct the object with the peer connection and choose not to
   activate ourselves into a dedicated thread.  You might get some
   performance gain by activating but if you really want a
   multi-threaded apprroach you should handle that as a separate
   issue.  Attempting to force threading at this level will likely
   cause more trouble than you want to deal with.
*/</font>
<font color=#008888>Xmit::Xmit</font>( ACE_SOCK_Stream & _peer )
        : Protocol_Task(0), peer_(_peer)
{
}

<font color=#008888>Xmit::~Xmit</font>(void)
{
}

<font color=red>/* Check to see if we're being closed by the stream (flags != 0) or if
   we're responding to the exit of our svc() method.
*/</font>
int <font color=#008888>Xmit::close</font>(u_long flags)
{
     <font color=red>// Take care of the baseclass closure.</font>
    int rval = <font color=#008888>inherited::close</font>(flags);

     <font color=red>// Only if we're being called at the stream shutdown do we close</font>
     <font color=red>// the peer connection.  If, for some reason, we were activated</font>
     <font color=red>// into one or more threads we wouldn't want to close the pipe</font>
     <font color=red>// before all threads had a chance to flush their data.</font>
    if( flags )
    {
        peer().close();
    }

    return( rval );
}

<font color=red>/* Our overload of send() will take care of sending the data to the
   peer.
*/</font>
int <font color=#008888>Xmit::send</font>(ACE_Message_Block *message, ACE_Time_Value *timeout)
{
    int rval;
    
    ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Xmit::send</font>() sending (%s)(%d)\n</font>", message->rd_ptr(), message->length() ));

     <font color=red>/* Since we're going to be sending data that may have been
        compressed and encrypted it's probably important for the
        receiver to get an entire "<font color=green>block</font>" instead of having a
        partial read.

        For that reason, we'll send the length of the message block 
        (in clear-text) to the peer so that it can then recv_n()
        the entire block contents in one read operation.
     */</font>
    char msize[32];
    sprintf(msize,"<font color=green>%d</font>",message->length());

     <font color=red>// Be sure we send the end-of-string NULL so that Recv will</font>
     <font color=red>// know when to stop assembling the length.</font>
    rval = this->peer().send_n( msize, strlen(msize)+1, 0, timeout );

    if( rval == -1 )
    {
        ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Xmit::send</font>() Failed to send message size.</font>"), -1);
    }

     <font color=red>/* Now we send the actual data.  If you're worried about
        network efficiency then you may choose to create one buffer 
        containing msize and the message data and send it all at
        once.
     */</font>
    rval = this->peer().send_n( message->rd_ptr(), message->length(), 0, timeout );

     <font color=red>// Release the message block since we're done with it.</font>
    message->release();

    return( rval );
}
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page16.html">Continue This Tutorial</A>]</CENTER>