Client's functionality Sending and getting requests to the &SCSCP; server(s), the client operates with processes. Process is an abstraction which in other words may be also called a remote task. It encapsulates an input/output TCP stream (see ) from the client to the server and the process ID of the CAS running as a server (deduced from the connection initiation message; may be unassigned, if the server CAS did not communicate it).

There are two ways to create processes. One of them is to specify the hostname and port where the &SCSCP; server is running; in this case a new input/output TCP stream will be created. Another way is first to establish the connection with the &SCSCP; server using and then keep it alive across multiple remote procedure calls, thus saving time on the DNS lookup and connection initiation. This may give a good speedup in computations with an intensive message exchange. Note that as long as such connection is open, other &SCSCP; clients will not be able to get through, so if several clients are interchanging with the &SCSCP; server at the same time, they should not block each other with long-lasting connections.
&SCSCP; connections <#Include Label="IsSCSCPconnection"/> <#Include Label="NewSCSCPconnection"/> <#Include Label="CloseSCSCPconnection"/>
Processes <#Include Label="IsProcess"/> <#Include Label="NewProcess"/> <#Include Label="CompleteProcess"/> <#Include Label="TerminateProcess"/>
All-in-one tool: sending request and getting result <#Include Label="EvaluateBySCSCP"/> Now we demonstrate the procedure GroupIdentificationService, also given in the previous chapter:
gap> G:=SymmetricGroup(4); Sym( [ 1 .. 4 ] ) gap> gens:=GeneratorsOfGroup(G); [ (1,2,3,4), (1,2) ] gap> EvaluateBySCSCP( "GroupIdentificationService", [ gens ], > "localhost", 26133 : debuglevel:=3 ); rec( attributes := [ [ "call_id", "localhost:26133:2442:xOilXtnw" ], [ "info_runtime", 4 ], [ "info_memory", 2596114432 ], [ "info_message", "Memory usage for the result is 48 bytes" ] ], object := [ 24, 12 ] )
Service provider may suggest to the client to use a counterpart function
gap> IdGroupWS := function( G ) > local H, result; > if not IsPermGroup(G) then > H:= Image( IsomorphismPermGroup( G ) ); > else > H := G; > fi; > result := EvaluateBySCSCP ( "GroupIdentificationService", > [ GeneratorsOfGroup(H) ], "localhost", 26133 ); > return result.object; > end;;
which works exactly like :
gap> G:=DihedralGroup(64); <pc group of size 64 with 6 generators> gap> IdGroupWS(G); [ 64, 52 ]
Switching between Binary and XML &OpenMath; Encodings <#Include Label="SwitchSCSCPmodeToBinary"/> For example, let us create a vector over GF(3):
gap> x := [ Z(3)^0, Z(3), 0*Z(3) ]; [ Z(3)^0, Z(3), 0*Z(3) ]
The XML &OpenMath; encoding of such objects is quite bulky:
gap> OMPrint( x ); <OMOBJ xmlns="http://www.openmath.org/OpenMath" version="2.0"> <OMA> <OMS cd="list1" name="list"/> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>1</OMI> </OMA> <OMA> <OMS cd="arith1" name="times"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> </OMA> </OMOBJ> gap> Length( OMString(x) ); 507
We call the &SCSCP; procedure Identity just to test how this object may be sent back and forth. The total length of the procedure call message is 969 symbols: gap> SetInfoLevel(InfoSCSCP,3); gap> EvaluateBySCSCP("Identity",[x],"localhost",26133); #I Creating a socket ... #I Connecting to a remote socket via TCP/IP ... #I Got connection initiation message #I <?scscp service_name="GAP" service_version="4.dev" service_id="localhost:2\ 6133:42448" scscp_versions="1.0 1.1 1.2 1.3" ?> #I Requesting version 1.3 from the server ... #I Server confirmed version 1.3 to the client ... #I Composing procedure_call message: <?scscp start ?> <OMOBJ xmlns="http://www.openmath.org/OpenMath" version="2.0"> <OMATTR> <OMATP> <OMS cd="scscp1" name="call_id"/> <OMSTR>localhost:26133:42448:IOs9ZkBU</OMSTR> <OMS cd="scscp1" name="option_return_object"/> <OMSTR></OMSTR> </OMATP> <OMA> <OMS cd="scscp1" name="procedure_call"/> <OMA> <OMS cd="scscp_transient_1" name="Identity"/> <OMA> <OMS cd="list1" name="list"/> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> <OMA> <OMS cd="arith1" name="power"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>1</OMI> </OMA> <OMA> <OMS cd="arith1" name="times"/> <OMA> <OMS cd="finfield1" name="primitive_element"/> <OMI>3</OMI> </OMA> <OMI>0</OMI> </OMA> </OMA> </OMA> </OMA> </OMATTR> </OMOBJ> <?scscp end ?> #I Total length 969 characters ... rec( attributes := [ [ "call_id", "localhost:26133:42448:IOs9ZkBU" ] ], object := [ Z(3)^0, Z(3), 0*Z(3) ] ) Now we switch to binary mode: gap> SwitchSCSCPmodeToBinary(); gap> EvaluateBySCSCP("Identity",[x],"localhost",26133); #I Creating a socket ... #I Connecting to a remote socket via TCP/IP ... #I Got connection initiation message #I <?scscp service_name="GAP" service_version="4.dev" service_id="localhost:2\ 6133:42448" scscp_versions="1.0 1.1 1.2 1.3" ?> #I Requesting version 1.3 from the server ... #I Server confirmed version 1.3 to the client ... #I Composing procedure_call message: 3C3F7363736370207374617274203F3E0A18121408060773637363703163616C6C5F6964061E6C\ 6F63616C686F73743A32363133333A34323434383A3256675A5562755A0806147363736370316F\ 7074696F6E5F72657475726E5F6F626A6563740600151008060E73637363703170726F63656475\ 72655F63616C6C1008110873637363705F7472616E7369656E745F314964656E74697479100805\ 046C697374316C69737410080605617269746831706F7765721008091166696E6669656C643170\ 72696D69746976655F656C656D656E7401031101001110080605617269746831706F7765721008\ 091166696E6669656C64317072696D69746976655F656C656D656E740103110101111008060561\ 726974683174696D65731008091166696E6669656C64317072696D69746976655F656C656D656E\ 7401031101001111111113193C3F736373637020656E64203F3E0A #I Total length 339 bytes #I Request sent ... #I Waiting for reply ... #I <?scscp start ?> #I Got back: object [ Z(3)^0, Z(3), 0*Z(3) ] with attributes [ [ "call_id", "localhost:26133:42448:2VgZUbuZ" ] ] rec( attributes := [ [ "call_id", "localhost:26133:42448:2VgZUbuZ" ] ], object := [ Z(3)^0, Z(3), 0*Z(3) ] ) gap> SetInfoLevel(InfoSCSCP,3); As we can see, the size of the message is almost three times shorter, and this is not the limit. Switching to binary &OpenMath; encoding in combination with pickling and unpickling from &IO; package (see in the last Chapter) and special methods for pickling compressed vectors implemented in the `Cvec` available in &GAP; 4.5 allow to dramatically reduce the overhead for vectors and matrices over finite fields, making a roundtrip up to a thousand times faster.
Remote objects The &SCSCP; package introduces new kind of objects - remote objects. They provide an opportunity to manipulate with objects on remote services without their actual transmitting over the network. Remote objects store the information that allows to access the original object: the server name and the port number through which the object can be accessed, and the variable name under which it is stored in the remote system. Two remote objects are equal if and only if all these three parameters coincide.

There are two types of remote object which differ by their lifetime: temporary remote objects which exist only within a single session; persistent remote objects which stay alive across multiple sessions. First we show the example of the temporary remote object in a session. The procedure PointImages returns the set of images of a point i under the generators of the group G. First we create the symmetric group S_3 on the client and store it remotely on the server (call 1), then we compute set of images for i=1,2 (calls 2,3) and finally demonstrate that we may retrieve the group from the server (call 4):
gap> stream:=InputOutputTCPStream( "localhost", 26133 ); < input/output TCP stream to localhost:26133 > gap> StartSCSCPsession(stream); "localhost:26133:6184" gap> OMPutProcedureCall( stream, "store_session", > rec( object := [ SymmetricGroup(3) ], > attributes := [ [ "call_id", "1" ], > ["option_return_cookie"] ] ) ); true gap> SCSCPwait( stream ); gap> G:=OMGetObjectWithAttributes( stream ).object; < remote object scscp://localhost:26133/TEMPVarSCSCPo3Bc8J75 > gap> OMPutProcedureCall( stream, "PointImages", > rec( object := [ G, 1 ], > attributes := [ [ "call_id", "2" ] ] ) ); true gap> SCSCPwait( stream ); gap> OMGetObjectWithAttributes( stream ); rec( attributes := [ [ "call_id", "2" ] ], object := [ 2 ] ) gap> OMPutProcedureCall( stream, "PointImages", > rec( object := [ G, 2 ], > attributes := [ [ "call_id", "3" ] ] ) ); true gap> SCSCPwait( stream ); gap> OMGetObjectWithAttributes( stream ); rec( attributes := [ [ "call_id", "3" ] ], object := [ 1, 3 ] ) gap> OMPutProcedureCall( stream, "retrieve", > rec( object := [ G ], > attributes := [ [ "call_id", "4" ] ] ) ); true gap> SCSCPwait( stream ); gap> OMGetObjectWithAttributes( stream ); rec( attributes := [ [ "call_id", "4" ] ], object := Group([ (1,2,3), (1,2) ]) ) gap> CloseStream(stream);
After the stream is closed, it is no longer possible to retrieve the group G again or use it as an argument.

Thus, the usage of remote objects existing during a session reduces the network traffic, since we pass only references instead of actual &OpenMath; representation of an object. Also, the remote object on the server may accumulate certain information in its properties and attributes, which may not be included in it default &OpenMath; representation.

Now we show remote objects which remain alive after the session is closed. Such remote objects may be accessed later, for example, by: subsequent procedure calls from the same instance of &GAP; or another system; other instances of &GAP; or another systems (if the identifier of an object is known) another &SCSCP; servers which obtained a reference to such object as an argument of a procedure call. <#Include Label="StoreAsRemoteObject"/> Internally, the remote object carries all the information which is required to get access to the original object: its identifier, server and port:
gap> s![1]; "TEMPVarSCSCPLvIUUtL3" gap> s![2]; "localhost" gap> s![3]; 26133
When the remote object is printed in the &OpenMath; format, we use symbols @ and : to combine these parameters in the &OpenMath; reference:
gap> OMPrint(s); <OMOBJ> <OMR href="scscp://localhost:26133/TEMPVarSCSCPLvIUUtL3" /> </OMOBJ>
This allows substitution of remote object as arguments into procedure calls in the same manner like we do this with usual objects:
gap> EvaluateBySCSCP("WS_IdGroup",[s],"localhost",26133); rec( attributes := [ [ "call_id", "localhost:26133:52918:Viq6EWBP" ] ], object := [ 6, 1 ] )
<#Include Label="IsRemoteObject"/> <#Include Label="RemoteObjectsFamily"/> <#Include Label="RetrieveRemoteObject"/> <#Include Label="UnbindRemoteObject"/> Finally, we show an example when first we create a group on the service running on port 26133, and then identify it on the service running on port 26134:
gap> s:=StoreAsRemoteObject( SymmetricGroup(3), "localhost", 26133 ); < remote object scscp://localhost:26133/TEMPVarSCSCPNqc8Bkan > gap> EvaluateBySCSCP( "WS_IdGroup", [ s ], "localhost", 26134 ); rec( object := [ 6, 1 ], attributes := [ [ "call_id", "localhost:26134:7414" ] ] )
Instead of transmitting the group to the client and then sending it as an argument to the second service, the latter service directly retrieves the group from the first service:
gap> EvaluateBySCSCP("WS_IdGroup",[s],"localhost",26133 : output:="cookie" ); rec( attributes := [ [ "call_id", "localhost:26133:52918:mRU6w471" ] ], object := < remote object scscp://localhost:26133/TEMPVarSCSCPS9SVe9PZ > )