com_tcp.pl
来自「SRI international 发布的OAA框架软件」· PL 代码 · 共 1,050 行 · 第 1/3 页
PL
1,050 行
%*****************************************************************************
% File : libcom_tcp.pl
% Primary Authors : Adam Cheyer, David Martin
% Purpose : TCP instantiation of lowlevel communication primitives for OAA
% Updated : 01/98
%
% ------------------------------------------------------------------------
% The contents of this file are subject to the OAA Community Research
% License Version 2.0 (the "License"); you may not use this file except
% in compliance with the License. You may obtain a copy of the License
% at http://www.ai.sri.com/~oaa/. Software distributed under the License
% is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
% express or implied. See the License for the specific language governing
% rights and limitations under the License. Portions of the software are
% Copyright (c) SRI International, 1999. All rights reserved.
% "OAA" is a registered trademark, and "Open Agent Architecture" is a
% trademark, of SRI International, a California nonprofit public benefit
% corporation.
% ------------------------------------------------------------------------
%
%
%*****************************************************************************
%* RCS Header and internal version
%*****************************************************************************
:- module(com,
[com_StandardizeAddress/2,
com_Connect/3,
com_Connect/4,
com_Disconnect/1,
com_ShutdownAll/0,
com_Connected/4,
com_ReportConnections/1,
com_ListenAt/4,
com_SendData/2,
com_SelectEvent/2,
com_AddInfo/2,
com_GetInfo/2,
% The following are for backwards compatibility only:
com_ListenAt/3,
% The following are called from other OAA2 distribution
% files, but are currently unsupported and undocumented:
com_write_term/1
]).
% rcs version number
rcsid(libcom_tcp, '$Header: /home/zuma1/OAA/CVSRepository/oaa2/src/oaalib/prolog/com_tcp.pl,v 1.36 2005/02/08 03:43:20 martin Exp $').
%# The set of library modules to be loaded depends on the Prolog.
:- ( prolog_flag(source_info, _) ->
% sicstus
use_module(library(lists)),
use_module(library(charsio)), % for sprintf and with_output_to_chars
use_module(library(terms)),
use_module(library(sockets)),
use_module(library(system)),
use_module(spcompat)
|
% quintus
use_module(library(sets)),
use_module(library(basics)),
use_module(library(lists)),
use_module(library(environ)), % read environment vars
use_module(library(charsio)), % for sprintf and with_output_to_chars
use_module(library(ask)), % for ask_oneof
use_module(library(files)), % can_open_file
use_module(library(strings)) % for concat
).
% Hack: On UNIX load regular tcp library and new tcp_extra module.
% On PC, we have modified the tcp library to add the function in tcp_extra
% so we load the local version, not the one in the library directory.
% One day, we should create a tcp_extra module for PC, but couldn't get
% it to compile right for some reason.
:- ( prolog_flag(source_info, _) ->
% Sicstus: tcp_inet_addr defined in spcompat.pl
true
| prolog_flag(host_type, ix86) ->
% Quintus / PC
use_module(tcp)
| otherwise ->
% Quintus / Unix
use_module(tcp_extra), % for tcp_inet_addr()
use_module(library(tcp))
).
:- dynamic
% id, commtype, client/server/child/peer, commInfo, status
com_connection_info/5,
% Maximum number of connections that can be open at once.
max_connections/1.
% declaration needed per Quintus documentation:
:- multifile portray/1.
% Default value. (Quintus usually accepts connections numbered 5 - 63 before
% an exception is raised, under Solaris.)
max_connections(58).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name: com_StandardizeAddress(+Address, -Standardized)
% purpose: Given a com address supported by this library, such as
% tcp(Host, Port), returns its standardized form.
% remarks: The standardized form expresses the host as an IP number.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_StandardizeAddress(tcp(Host, Port), tcp(IPNum, Port)) :-
tcp_inet_addr(Host, IPNum).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name: com_Connect(+ConnectionId, +Params, ?ConnectAddress, -ActualAddress)
% purpose: Given a connection ID and an address, initiates a client connection
% remarks:
% - if Address is a variable, instantiates the Address by using
% oaa_ResolveVariables, which looks in a setup file, command line, and
% environment variables for the required info.
% * Unless Params include resolve_vars(false)
% - ActualAddress may differ from ConnectAddress, because certain parameters
% can cause a different port to be used.
% - stores the connection info for connection ID in com_connection_info/5.
% - fails if connection can't be made
% - 6 June, 2002 (DLM): We now distinguish between the address connected to,
% and the primary address of the other agent. The primary address
% serves as a unique identifier for the other agent (but this could
% change in the future; see comments for oaa:oaa_PrimaryAddress).
% By default they are the same, but a different primary
% address can be specified in Params.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This clause is for backwards compatibility:
com_Connect(ConnectionId, Params, tcp(Host,Port)) :-
format('~w: com_Connect/3 is obsolete; use com_Connect/4~n', ['WARNING']),
com_Connect(ConnectionId, Params, tcp(Host,Port), _Actual).
com_Connect(ConnectionId, Params, tcp(Host,Port), tcp(ActualHost, ActualPort)) :-
com_Connect(ConnectionId, Params, tcp(Host,Port), 0, tcp(ActualHost, ActualPort)).
com_Connect(ConnectionId, Params, tcp(Host,Port), NumAttempts, ActualAddress) :-
ground(ConnectionId),
( memberchk(resolve_vars(false), Params) ->
true
% if variable address, look it up...
| ((var(Host) ; var(Port)) ->
oaa:oaa_ResolveVariables([
[cmd('-oaa_connect',tcp(Host,Port))],
[env('OAA_CONNECT',tcp(Host,Port))],
[setup(_, default_facilitator, tcp(Host,Port))]
])
| true)
),
repeat,
( on_exception(E,
tcp_connect(address(Port, Host), RootConnection),
Exception = E) ->
true
| otherwise ->
Exception = tcp_connect_failed
),
( var(Exception) ->
tcp_inet_addr(Host, IPNum),
ActualAddress = tcp(Host, Port),
FormalActualAddress = addr(tcp(IPNum, Port)),
( memberchk(other_address(Primary), Params) ->
true
| otherwise ->
Primary = FormalActualAddress
),
% Various important info elements, such as oaa_address, get
% filled in later, in oaa.pl.
assert(com_connection_info(ConnectionId, tcp, client,
[other_address(Primary),
connect_address(FormalActualAddress),
connection(RootConnection)],
connected)),
!
| oaa:oaa_ResolveVariables([
[cmd('-on_connect_exception', Response)],
[env('ON_CONNECT_EXCEPTION', Response)],
[setup(_, on_connect_exception, Response)]
]) ->
NewParams = [resolve_vars(false) | Params],
format('Currently unable to connect to ~w port ~w.~n',
[Host, Port]),
( Response == try_again ->
format('Will try again after 5 seconds ...~n', []),
com_sleep(5),
fail
| Response = try_again(NumSeconds) ->
format('Will try again after ~w seconds ...~n', [NumSeconds]),
com_sleep(NumSeconds),
fail
| Response == next_highest ->
NewNumAttempts is NumAttempts + 1,
( NewNumAttempts > 100 ->
halt
| otherwise ->
NewPort is Port + 1,
com_Connect(ConnectionId, Params, tcp(Host,NewPort), NewNumAttempts, tcp(ActualHost, ActualPort))
),
!
| Response = next_highest(MaxAttempts) ->
NewNumAttempts is NumAttempts + 1,
( NewNumAttempts > MaxAttempts ->
halt
| otherwise ->
NewPort is Port + 1,
com_Connect(ConnectionId, Params, tcp(Host,NewPort), NewNumAttempts, tcp(ActualHost, ActualPort))
),
!
| Response == change_port ->
com_get_new_port(Port, NewPort),
com_Connect(ConnectionId, Params, tcp(Host,NewPort), tcp(ActualHost, ActualPort)),
!
| otherwise ->
format('Exiting~n', []),
halt
)
| otherwise ->
NewParams = [resolve_vars(false) | Params],
com_ask_about_connect_exception(Exception, Port, Host, Response),
( Response == try_again ->
fail
| Response == next_highest ->
NewPort is Port + 1,
com_Connect(ConnectionId, Params, tcp(Host,NewPort), tcp(ActualHost, ActualPort)),
!
| Response == change_port ->
com_get_new_port(Port, NewPort),
com_Connect(ConnectionId, Params, tcp(Host,NewPort), tcp(ActualHost, ActualPort)),
!
| otherwise ->
halt
)
).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name: com_Connected(?ConnectionId, ?Protocol, ?Type, ?Status)
% purpose: Reports on current connections
% remarks:
% - BACKTRACKS over database of current connections
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_Connected(ConnectionId, Protocol, Type, Status) :-
com_connection_info(ConnectionId, Protocol, Type, _InfoList, Status).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name: com_Disconnect(+ConnectionId)
% purpose: Given a connection ID of type 'client', shuts down the connection.
% remarks:
% - Succeeds silently if there is not an open connection having the
% given id.
% - ConnectionId may be either the symbolic name (e.g. parent) or the numeric
% connection Identifier.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_Disconnect(Id) :-
ground(Id),
((com_connection_info(Id, tcp, client, _Info, connected),
ConnectionId = Id)
;
(com_connection_info(ConnectionId, tcp, client, _Info, connected),
Connection = Id)
),
com_GetInfo(ConnectionId, connection(Connection)),
tcp_shutdown(Connection),
retract(com_connection_info(ConnectionId,tcp,client,_Info,connected)),
!.
com_Disconnect(_ConnectionId).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name: com_ShutdownAll
% purpose: Shut down all connections. Normally called just before an
% agent is going to halt.
% remarks:
% - Succeeds silently, regardless of how many connections there are.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_ShutdownAll :-
findall(
ConnectionId,
( com_connection_info(ConnectionId, _, Type, _, _),
Type \== server ),
NonServerIds),
shutdown_each(NonServerIds),
findall(
ConnectionId,
com_connection_info(ConnectionId, _, server, _, _),
ServerIds),
destroy_each(ServerIds).
shutdown_each([]).
shutdown_each([Id | Rest]) :-
( com_GetInfo(Id, connection(Connection)) ->
( tcp_shutdown(Connection) -> true ; true )
| otherwise ->
true
),
retract(com_connection_info(Id,_,_,__,_)),
shutdown_each(Rest).
destroy_each([]).
destroy_each([Id | Rest]) :-
( com_GetInfo(Id, connection(Connection)) ->
( tcp_destroy_listener(Connection) -> true ; true )
| otherwise ->
true
),
retract(com_connection_info(Id,_,_,__,_)),
destroy_each(Rest).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name: com_ReportConnections(+FilePath)
% purpose: Write info about all current connections into the given file.
% remarks:
% - Succeeds silently if there is not an open connection having the
% given id.
% - ConnectionId may be either the symbolic name (e.g. parent) or the numeric
% connection Identifier.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_ReportConnections(File) :-
telling(CurrentOut),
on_exception(_, tell(File), fail),
com_write_connection_info,
told,
tell(CurrentOut),
!.
com_ReportConnections(File) :-
format('~w: Unable to write connection info to file: ~w~n',
['WARNING', File]).
com_write_connection_info :-
com_connection_info(ConnectionId, Protocol, Type, InfoList, Status),
( Type = server, memberchk(oaa_address(A), InfoList) ->
Address = A
| memberchk(other_address(A), InfoList) ->
Address = A
| otherwise ->
% This shouldn't ever happen
Address = unknown
),
portray_clause(connection(ConnectionId,Protocol,Type,Address,Status)),
fail.
com_write_connection_info.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?