I assume each incoming message spawns a process_message, up
to MAX_THREADS threads (including other running callbacks),
but what happens when this is exceeded?
No this is not the case in fact. None of the AFC agents use threading.
If they do use threading then this is because the compiler will
choose threading libraries but this can be turned of as well.
Deciding not to use a threading model was done on purpose for a number
of reasons. First of all not all platforms support threading (PalmOS).
Second, as you already noticed an agent might run into operating system
boundaries, which are not necessarily realistic. I chose to apply an
event based mechanism, whereby ultimately the operating system is
responsible for the workload of buffering data. Each open socket
contains an incoming message queue (an outgoing queue can be configured
but is disabled for now I believe) This incoming message queue is set to
store 100 messages by default but can be adjusted in real time in case
of high traffic. If you want to change the size of the queue for all
agents by compiling in a new value then add: "set_queue_size (200);"
within the constructor of the CClientBase class. File: "c_client.cpp".
There is no ordering of messages as they come in. In that respect
each AFC agent is truly asynchronous. The Communicator or agent
shell could be easily rigged to oversee ordering of messages however.
Each message is already assigned a parser when it comes in. You can
therefor already make certain inferences about it's content and use
that to either internally route the message or apply ordering.
The Communicator can also be used to monitor traffic load. It has
access to all the sockets and can evaluate how many of the queues are
reaching maximum capability:
(N Sockets * N Messages) / (N Sockets * 100) = Load %
There is a global timer or hearbeat that is present in all agents.
This heartbeat is as of yet not propagated to the Communicator but
can be by adding a call within the agent container "c_container.cpp".
A timer could periodically check the agent's message load. This
mechanism is already used to check connection integrity to such
infrastructure components as: MiddleAgents, Agent Name Servers and
I don't know if you guys use the agents I wrote for the PRET project
but a good start to see how an agent handles high load would be to
look at the SAFBroker.
Hope this helps, let me know if you need more information.
Question: Why not use the Standard C++ Library for agent classes?
I just downloaded the RETSINA AFC developer's guide. I saw the use of
plain char pointers and a home-grown list class. Why not use the
Standard C++ Library? It would be nice to program agents in C++ instead
of Java, because I am more familiar with it. But working with char*,
lots of new & delete and non-standard container classes scares me: it's
just too much work!
There are 4 reasons why we did not choose to use the standard
C++ datastructures such as STL:
1) They are not standard and differ from compiler to compiler
and platform to platform.
2) The second reason that we did not choose to use STL for our
datastructures was that the AFC needed to be compiled on a
variety of platforms that may not support some or all features
present in STL and other C++ libraries. For example, we have a
version that compiles under PalmOS and we even have a MicroAFC
edition that could easily fit on certain micro-controllers.
WindowsCE, PalmOS and Linux on StrongARM have no concept of
3) There is another reason why we did not go with STL. All of the
datastructures present in the AFC can be streamed into an ACL
string. This allows agent developers to move or share entire sets
of datastructures between two agents. If we had used pre-existing
implementations present in either C++ or any of the standard
libraries such as STL we would not have been able to do this.
For example, the CString class does not allow you to do:
CString a_string="Hello World";
The output in KQML would be:
:string (Hello World)
or in XML:
4) We have an experimental version of the AFC that breaks out to:
Java,Tcl/Tk,Guile and Python. One of the requirements we found
while doing this was that it would require a large amount of work
to bind the CString class to any other language since we would
have to write shadow versions in each of the languages. Instead
we could make direct mappings from a 'char *'
As you can see there are a lot of directions in which the development
of the AFC was pulled and which determined it's current implementation.
I hope this answers your question.
Question: How do I create a socket and a string packet?
How do I create a TCP/IP (or UDP) socket and write a string to the TCP/IP
packet and send it out. Does AFC have the class for this?
PS. Do you have any more document about AFC?
I prefer examples with documentation.
Answer:(more complete answer in AFC Users' Manual:
http://www-2.cs.cmu.edu/~softagents/afc/Manual_rev_8.PDF Part V, page 83):
There is defenately a UDP socket available through the AFC. The
discovery client uses it. Here is a small snippet on how to use it:
// include core AFC libraries --------------------------------------
// create the socket -----------------------------------------------
// the socket_handler variable is a CWnd pointer since you will want
// to have events be received when something arrives on the socket
// this will come into play when you use the code below to add custom
// sockets to AFC agents.
CDataGramSocket *m_unicast=new CDataGramSocket (sock_handler);
if (m_unicast->Create ()==FALSE)
AfxMessageBox ("Error creating socket");
// connect to remote system ----------------------------------------
BOOL response=m_unicast->Connect ("127.0.0.1",23); // telnet I think
AfxMessageBox ("Unable to connect to remote machine");
// send data through the socket ------------------------------------
int socket_ret=m_unicast->mfc_send ("Hello World");
AfxMessageBox ("Unablet to sebd data to remote machine");
// and we're done --------------------------------------------------
Question: How do I create a socket and a string packet? (cont'd)
Is mfc_send() a function in the MFC distribution or RETSINA? I could not
find this function anywhere. What could the "send" function for the UDP
or TCP socket?
The mfc_send method is part of the CClientSocket class and should be
available to all raw TCP/IP sockets derived from it. The name is
slightly deceptive since it suggests that it only works under windows.
The method itself is actually a generalized socket send call that takes
a string and will attempt to send it through the socket. The method
assumes the socket has been created and connected.
If you want to use the MFC socket calls for sending then I would suggest
you use the 'Send ()' method. This method takes 3 parameters. The first
one is a pointer to the actual string to be send. The second parameter
indicates the length of the data and the third parameter is one that
is mostly used for internal purposes and the AFC sets it to 0. In
fact, under Windows the AFC method mfc_send will make a call to Send.
Question: Why do I get an error when trying to send a message?
What could be the possibility of Segmentation Fault when one Agent trying
to send a message to another agent? Message format?
I add codes similar to Example One that came with the RETSINA
distribution. The example is that AgentA sends a mesage to AgentB when its
timer is expired.
Basically, my agent receives some data from a UDP socket and convert to
a string. Then, I put the string into a message and send it to another
agent. Whenever it tries to send a message, I got the Window Dialog
error box and the program is frozen. Please help.
In order to track down what is going wrong here I would like to
propose a number of steps. These steps will determine where the
problem lies roughly.
1) Find out if there are any AFC DLL's lying around from previous
versions. You can do this by comparing the timestamp of the DLL's
found in %RETSINA%/system/dll to the AFC DLL's you find in your
windows directory. Sometimes people find that they have previous
DLL's in their executable directory which are loaded instead of
the ones from the Windows directory.
2) In the code where you send the string, replace the point to that
string and send a static string like "Hello World" instead. If
your agent still crashes then it might be a problem with the AFC.
I would like to rule out any problems associated with pointers
being given to the Communicator.
3) Make sure that the last parameter you give to the 'send_message'
method is NULL. There is a situation where we actually give more
parameters than the standard ones we use for KQML. You need to use
NULL as the last parameter to indicate to the Communicator that
the last parameter was the content field.
If neither of these steps fixes the problem then let me know and I
will come over to see what the problem is.
Internal Site (Restricted Access)