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
|
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>nevrax.org : docs</TITLE>
<LINK REL=stylesheet TYPE="text/css" HREF="/inc/css/nevrax.css">
<link href="doxygen.css" rel="stylesheet" type="text/css">
</HEAD>
<BODY MARGINHEIGHT="0" MARGINWIDTH="0">
<!-- uplinks -->
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0>
<TR>
<TD WIDTH=16><IMG SRC="/inc/img/pixel.gif" WIDTH="16" HEIGHT="16" BORDER=0 ALT=""></TD>
<TD WIDTH=140 BGCOLOR=#dddddd><IMG SRC="/inc/img/pixel.gif" WIDTH="140" HEIGHT="16" BORDER=0 ALT=""></TD>
<TD WIDTH=16><IMG SRC="/inc/img/pixel.gif" WIDTH="16" HEIGHT="16" BORDER=0 ALT=""></TD>
<TD><IMG width=6 height=14 SRC="/inc/img/reddots.gif" ALT="#" VSPACE=2 HSPACE=2 BORDER=0 ></TD><TD VALIGN=middle> <A CLASS=uplinks HREF='/'><b>Home</B></FONT></A> </TD>
<TD><IMG width=6 height=14 SRC="/inc/img/reddots.gif" ALT="#" VSPACE=2 HSPACE=2 BORDER=0 ></TD><TD VALIGN=middle> <A CLASS=uplinks HREF='/'><b>nevrax.com</B></FONT></A> </TD>
</TR>
</TABLE>
<!-- banner Nevrax -->
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%>
<TR><TD BGCOLOR="#000000" BACKGROUND="/inc/img/black_banner.jpg"><A HREF=""><IMG SRC="/inc/img/nevrax.gif" WIDTH="170" HEIGHT="45" BORDER=0 ALT="Nevrax" ></A></TD></TR>
</TABLE>
<!-- main table -->
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 height=100%>
<TR>
<TD WIDTH=16><IMG SRC="/inc/img/pixel.gif" WIDTH="16" HEIGHT="10" BORDER=0 ALT=""></TD>
<TD WIDTH=140 BGCOLOR=#dddddd VALIGN=TOP ALIGN=middle><IMG SRC="/inc/img/pixel.gif" WIDTH="140" HEIGHT="10" BORDER=0 ALT="">
<!------ Begin Box ------>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 BGCOLOR=black><TR><TD><TABLE border=0 cellspacing=2 cellpadding=0 width=120><tr><TD ALIGN=middle bgcolor=black>
<FONT COLOR=white FACE="sans-serif"><B>Nevrax.org</B></FONT></TD></TR><tr><td colspan=2 bgcolor=#FFFFFF>
<TABLE cellspacing=0 cellpadding=1 border=0>
<tr><td ALIGN=middle><a class='linkbox' href="/news/" TITLE="Rubrique news"><img width=13 height=15 hspace=5 border=0 src=/inc/img/picto-news.gif ALT=#></A></td><td><a class='linkbox' href="/news/" TITLE="News">News</a></td></tr>
<tr><td ALIGN=middle><a class='linkbox' href="/mail/" TITLE="Rubrique mail"><img width=15 height=11 hspace=5 border=0 src=/inc/img/picto-mail.gif ALT=#></A></td><td><a class='linkbox' href="/mail/" TITLE="Mailing list archive">Mailing-list</a></td></tr>
<tr><td ALIGN=middle><a class='linkbox' href="/docs/" TITLE="Rubrique docs"><img width=14 height=16 hspace=5 border=0 src=/inc/img/picto-docs.gif ALT=#></A></td><td><a class='linkbox' href="/docs/" TITLE="Documentation">Documentation</a></td></tr>
<tr><td ALIGN=middle><a class='linkbox' href="/cvs/" TITLE="Rubrique cvs"><img width=13 height=17 hspace=5 border=0 src=/inc/img/picto-cvs.gif ALT=#></A></td><td><a class='linkbox' href="/cvs/" TITLE="CVS Web">CVS</a></td></tr>
<tr><td ALIGN=middle><a class='linkbox' href="/bugs/" TITLE="Rubrique bugs"><img width=20 height=16 hspace=5 border=0 src=/inc/img/picto-bugs.gif ALT=#></A></td><td><a class='linkbox' href="/bugs/" TITLE="Bugtracking">Bugs</a></td></tr>
<tr><td ALIGN=middle><a class='linkbox' href="/GPL.php3" TITLE="Rubrique license"><img width=18 height=12 hspace=5 border=0 src=/inc/img/picto-gpl.gif ALT=#></A></td><td><a class='linkbox' href="/GPL.php3" TITLE="License">License</a></td></tr>
</TABLE>
</TD></TR></TABLE></TD></TR></TABLE>
<!------ End Box ------>
</TD>
<TD WIDTH=15><IMG SRC="/inc/img/pixel.gif" WIDTH="16" HEIGHT="16" BORDER=0 ALT=""></TD>
<TD ALIGN=left valign=top><IMG SRC="/inc/img/pixel.gif" WIDTH="140" HEIGHT="10" BORDER=0 ALT="">
<!-- title -->
<TABLE background="/inc/img/redline.gif" CELLSPACING=0 CELLPADDING=0 BORDER=0 width=100%><tr><td>
<A HREF="/docs/"><img src="/inc/img/t_docs.gif" ALT="Docs" HEIGHT=20 BORDER=0></A>
</td><td><IMG SRC="/inc/img/pixel.gif" WIDTH="1" HEIGHT="1" BORDER=0 ALT="">
</td></tr></table>
<!-- block -->
<TABLE bgcolor="#dddddd" CELLSPACING=0 CELLPADDING=0 BORDER=0 width=100%><tr><td width=1% valign=middle><img width=6 height=14 hspace=2 vspace=2 src="/inc/img/reddots.gif"></TD>
<TD><B>Documentation</B></TD>
<TD ALIGN=RIGHT> </td>
</tr></table>
<!-- Generated by Doxygen 1.2.14 -->
<center>
<a class="qindex" href="index.html">Main Page</a> <a class="qindex" href="namespaces.html">Namespace List</a> <a class="qindex" href="hierarchy.html">Class Hierarchy</a> <a class="qindex" href="classes.html">Alphabetical List</a> <a class="qindex" href="annotated.html">Compound List</a> <a class="qindex" href="files.html">File List</a> <a class="qindex" href="namespacemembers.html">Namespace Members</a> <a class="qindex" href="functions.html">Compound Members</a> <a class="qindex" href="globals.html">File Members</a> <a class="qindex" href="pages.html">Related Pages</a> <a class="qindexRef" doxygen="_cgi:/cgi-bin/nel-search.cgi" href="/cgi-bin/nel-search.cgi">Search</a> </center>
<hr><a name="network"><h2>Network engine (until May 1, 2001)</h2></a>
<dl compact><dt><b>
Author: </b><dd>
Olivier Cado</dl>Warning: this document describes the network engine as it was available in the NeL CVS tree until May 1, 2001. The updated documentation is available at <a href="/docs/nelnet.php3">/docs/nelnet.php3</a>
<p>
<a name="networkintro"><h2>Introduction</h2></a>
<p>
Conceptually, the network subsystem is divided into layers :<ol>
<li>Layer 1 is the socket layer : it allows to send/receive any data synchronously using a network, either reliably or not.<li>Layer 2 is the message transfer layer : it allows to send/receive messages synchronously.<li>Layer 3 is the message handling layer : it allows to listen for messages and to call event-driven callback functions.<li>The recipient of a connection need not be an Internet address. It can be pointed to as a specific service using a Naming Service.<li>Any object can be serialized to/from a message.<li>Server software are called services and have a common interface.</ol>
Here is the implementation point of view :<ol>
<li>Layer 1 is implemented by NLNET::CBaseSocket.<li>Layer 2 is implemented by NLNET::CSocket.<li>Layer 3 is implemented by NLNET::CMsgSocket.<li>The class <a class="el" href="classNLNET_1_1CNamingClient.html">NLNET::CNamingClient</a> allows using the Naming Service. It is used by NLNET::CMsgSocket for service lookup. The addresses are implemented by <a class="el" href="classNLNET_1_1CInetAddress.html">NLNET::CInetAddress</a>. <li>The class <a class="el" href="classNLNET_1_1CMessage.html">NLNET::CMessage</a> inherits from <a class="el" href="classNLMISC_1_1IStream.html">NLMISC::IStream</a>.<li>All services inherit from <a class="el" href="classNLNET_1_1IService.html">NLNET::IService</a>. It provides the basic functionnalities such as registration to the Naming Service, server start-up and shutdown (see new_service_howto).</ol>
To use the layer 3, you need to include "nel/net/msg_socket.h".
<p>
<a name="networkusing"><h2>Using the network engine</h2></a>
<p>
Example : I want to ask the "family service" (let's call it "FMLS") the age of Toto. Let's say the family service understands a message of type "AGEREQ" and answers back a message of type "AGE" :
<p>
<ul>
<li>How to send a synchronous request to a host, using CSocket (layer 2) ?</ul>
<div class="fragment"><pre><font class="preprocessor"> #include "nel/net/socket.h"</font>
<font class="preprocessor"> #include "<a class="code" href="naming__client_8h.html">nel/net/naming_client.h</a>"</font>
(...)
<a class="code" href="types__nl_8h.html#a8">uint16</a> validitytime;
CSocket client;
<font class="comment">// Connect to the family service</font>
<font class="keywordflow">if</font> ( CNamingClient::lookupAndConnect( <font class="stringliteral">"FMLS"</font>, client, validitytime ) )
{
<font class="comment">// Send request</font>
CMessage msgout( <font class="stringliteral">"AGEREQ"</font> );
msgout.serial( Toto.name() );
client.send( msgout );
<font class="comment">// Receive answer</font>
<a class="code" href="types__nl_8h.html#a8">uint16</a> age;
CMessage msgin( <font class="stringliteral">""</font>, <font class="keyword">true</font> );
client.receive( msgin );
msgin.serial( age );
Toto.setAge( age );
}
</pre></div>
<p>
<ul>
<li>How to send an asynchronous request to a host, using CMsgSocket, the message handling system (layer 3) ?</ul>
<div class="fragment"><pre><font class="preprocessor"> #include "nel/net/msg_socket.h"</font>
(...)
<font class="comment">// Callback to process the answer</font>
<font class="keywordtype">void</font> cbProcessAge( CMessage& msgin, TSenderId idfrom )
{
<a class="code" href="types__nl_8h.html#a8">uint16</a> age;
msgin.serial( age );
Toto.setAge( age );
}
<font class="comment">// Callback array</font>
TCallbackItem ClientCallbacks [] =
{
{ <font class="stringliteral">"AGE"</font>, cbProcessAge }
};
<font class="keywordtype">void</font> main()
{
<font class="comment">// Connect to the family service</font>
CMsgSocket client ( ClientCallbacks, <font class="keyword">sizeof</font>(ClientCallbacks)/<font class="keyword">sizeof</font>(TCallbackItem), <font class="stringliteral">"FMLS"</font> );
<font class="comment">// Send request</font>
CMessage msgout ( <font class="stringliteral">"AGEREQ"</font> ); <font class="comment">// The server should have a callback associated to "AGEREQ"</font>
msgout.serial( Toto.name() );
client.send( msgout );
<font class="keywordflow">while</font> ( true )
{
client.update(); <font class="comment">// tests if a message has been received, and if the associated callback is called back</font>
<font class="comment">// Same as CMsgSocket::update()</font>
}
}
</pre></div>
<p>
<ul>
<li>How to send a container or an object ?</ul>
Symply serialize your container or your object in a message.
<p>
Example : <div class="fragment"><pre> vector<CMyClass> myvector;
CMessage msgout ( <font class="keyword">false</font> );
msgout.serialCont( myvector );
client.send( msgout );
</pre></div> This code serializes all objects contained in <em>myvector</em>. For this to work, you need to provide a method serial() in your class CMyClass. This is explained in <a class="el" href="classNLMISC_1_1IStream.html">NLMISC::IStream</a>. For a map or a multimap, use serialMap() instead of serialCont().
<p>
<a name="netenginev1"><h2>Features and implementation</h2></a>
<p>
<a name="msgtypebinding"><h3>Message type binding</h3></a>
<p>
Let's study a communication between two machines, A and B, where A sends several messages, of the same type, to B. In the following, we explain the 4 steps. Steps (1) and (4) correspond to the sending of the messages from A to B.
<p>
<ul>
<li>Step 1: The first time a type of message is sent by A, its header contains its "message name" (or message type as string).<li>Step 2: The remote machine B, when it receives it, sends back a binding message with the index of its associated callback, i.e. the binded "message number" (or message type as number). <li>Step 3: A processes the binding message by remembering the binding "message name" -> "message number" for this connection.<li>Step 4: Next time A sents this type of message, the header contains the message number.</ul>
The data structures need to implement this protocol are listed below.
<p>
<a name="netlayers"><h3>Network layers</h3></a>
<p>
<ol>
<li>Socket Layer:</ol>
<ul>
<li>CBaseSocket<li>Allows to send/receive any data (uint8*) synchronously over the network, either reliably or not (TCP streams or UDP datagrams)</ol>
<ol>
<li>Message Transfer Layer:</ol>
<ul>
<li>CSocket<li>Allows to send/receive messages (CMessage objects, in which you can serialize data) synchronously. TCP/UDP (not fully tested with UDP)<li>Implements the encoding/decoding of message headers<li>Implementation:<ul>
<li>Contains a set (_MsgsToBind : CMsgBindSet) that knows which messages have not been binded on the other side yet (when this set is empty, it means all bind messages have been set to the remote host (see step 2))<li>Contains a map (_BindMapForSends : CMsgMap) that saves the message type bindings understood by the remote connection (see step 3),</ul>
</ol>
<ol>
<li>Message Handling Layer:</ol>
<ul>
<li>CMsgSocket<li>Allows to listen for messages and to call event-driven callback functions.<li>Initializing:<ul>
<li>A CMsgSocket object can be a server object or a client object. There is at most one server object by process, but there can be several client objects.<li>When creating a server object, a passive listening socket is created, waiting for incoming connection requests.<li>A client object connects to a server which is specified either by its address or by its service name. In the latter the Naming Service is asked for the service address.<li>Anyone who creates a CMsgSocket object is required to define some callbacks and a callback array of the following form (its contents is only a sample): <div class="fragment"><pre>TCallbackItem MyCallbackArray [] =
{
{ <font class="stringliteral">"CHAT"</font>, cbDisplayChatMsg },
{ <font class="stringliteral">"PING"</font>, cbPing },
{ <font class="stringliteral">"PONG"</font>, cbPong },
{ <font class="stringliteral">"D"</font>, cbHandleDisconnection }
};
</pre></div><li>A method (addCallbackArray()) is provided for appending another callback array to the one specified at the beginning. Consequently you can provide callbacks in different modules of your program.</ul>
</ol>
<ul>
<li>Receiving messages and handling connections:<ul>
<li>When a message is received, the callback corresponding to its message name (if any) is called. Sample: <div class="fragment"><pre><font class="keywordtype">void</font> cbDisplayChatMsg( CMessage& inputmsg, TSenderId connectionid )
{
string line;
inputmsg.serial( line );
ChatOutput.addLine( line );
}
</pre></div><li>Two special message names are reserved : "C" and "D". C is called when a new connection is accepted by a server CMsgSocket object, and D is called when a connection is closed (either gracefully closed or broken). In both cases, an input message containing the address (CInetAddress) of the concerned remote host is passed to the callback (use serial() to get the address).<li>The user can deliberately close a connection by calling close().<li>Each connection is handled by a CSocket object. The list of connections is static, so that only one select() is performed for all connections, in the static method CMsgSocket::update(). This method receives only one message per socket at most.</ul>
</ul>
<ul>
<li>Sending messages:<ul>
<li>To send a message to a particular host, call clientsocket->send( outputmsg ) if you are a client of the remote host (i.e. you have created a client object) or call CMsgSocket::send( outputmsg, connectionid ).<li>To send a message to all connected hosts, call sendToAll( outputmsg ) or sendToAllExceptHost( outputmsg, excludedhostid ) or even sendToAllExceptHosts( outputmsg, excludedhostidset ) if you want to exclude one host or more from the destination list.</ul>
</ul>
<ul>
<li>Controlling access:<ul>
<li>The class provides basic features for allowing/disallowing a specified host to access to the callbacks. In the "C" callback (called when a connection is accepted), you can call authorizeOnly( authcallback, hostid ) so that the specified host cannot call any callback but authcallback. If this host tries to call another callback (i.e. it sends a message with a wrong message type), it will be disconnected. In authcallback you can then allow the client to access the other callbacks, calling authorizeAll( hostid ).</ul>
</ul>
<ul>
<li>Gathering statistics:<ul>
<li>There are several methods used to gather statistic about the network traffic. The static ones (bytesSent(), bytesReceived(), newBytesSent(), newBytesReceived()) give the total amount of input/output transferred data. The others (the same, with the suffix -FromHost()) are relative to one particular host.</ul>
</ul>
<ul>
<li>Misc:<ul>
<li>To know about the other methods, read the Doxygen documentation of CMsgSocket or the header file.</ul>
</ul>
<ul>
<li>Implementation:<ul>
<li>Contains a static set (_SearchSet: CSearchSet) and one set (_ClientSearchSet) per client object, allowing a fast search in the callback array. This set is optimized by not storing the message names but the pointers to the items in the callback array, even sorting by comparing the names.</ul>
</ul>
<a name="theservices"><h3>Services</h3></a>
<p>
You can use the class CMsgSocket directly, as in the Snowballs client, but a framework is provided for building server applications (see the class IService and the Doxygen related page "How to create a new service").
<p>
<a name="dtcs"><h3>Distributed Components Toolkit System (DTC System)</h3></a>
<p>
A set of services are available:<ul>
<li>The Naming Service (NS) locates a service by name/service identifier. It can also allocate port numbers. In NeL, the class CNamingClient allows the programmer to use the NS without writing network operations.<li>The Log Service (LOGS) is a centralized logger for all services (client class: CNetDisplayer used by CLog, and CNetLog that logs to the Network Viewer tool)<li>The Time Service (TS) is a centralized time reference manager (client class: CUniTime).<li>The Login Service (LS) is a centralized user account manager for all shards. It is the only service that does not connect to the NS because it is not part of a shard.<li>The Admin Executor Service (AES) collects stats about a physical machine.<li>The Agent Service (AS) routes messages for inter-agent communication over several machines.</ul>
In CVS:/code/server you will find another service, the Moves Service (DRServer) which is the main server for Snowballs.
<p>
<a name="deadreck"><h3>Dead Reckoning</h3></a>
<p>
<a class="el" href="namespaceNLNET.html">NLNET</a> contains a framework to handle networked virtual environments containing moving entities physically controlled on different computers. In the future, this framework may be removed from NeL and put somewhere else.
<p>
Here are the involved classes:<ul>
<li>IMovingEntity:<ul>
<li>CLocalEntity: a locally-controlled entity<li>CReplica: an entity not controlled directly:<ul>
<li>CRemoteEntity: an remote-controlled replica, with convergency</ul>
</ul>
</ul>
<ul>
<li>IEntityInterpolator: base class for convergency:<ul>
<li>LinearEntityInterpolator<li>CubicEntityInterpolator: B�zier interpolation</ul>
</ul>
<ul>
<li>CLocalArea: a local entity and a list of remote entities. Call update() to update the position of the entities using dead reckoning.</ul>
A good example of usage can be found in the Snowballs source code (client.cpp and move_listener.cpp).
<p>
<!-- footer -->
<BR><FONT Size=+5> </FONT>
</TD>
<TD WIDTH=15><IMG SRC=/inc/img/pixel.gif WIDTH=15 HEIGHT=15 BORDER=0 ALT=""></TD>
</TR>
</TABLE>
</BODY>
</HTML>
|