Topic: APLX Help : System Classes : List of Classes : Socket
[ Previous | Next | Contents | Index | APL Home ]

www.microapl.co.uk

Socket


Description

The Socket class allows you to use the low-level networking facilities provided by BSD or Windows sockets, for client-server applications. (See also the GetMail, SendMail and HTTPClient classes, which provide a higher-level interface for mail and HTTP protocols, and which are much easier to use.) It allows your APLX applications to exchange data with other processes, either on the local machine or over a network.

Usually, you will use Socket objects to allow APLX applications to communicate with non-APL processes. You can also use them to allow APLX applications to communicate with each other across a network.

For more details on using sockets, consult any of the standard documents on BSD or Windows socket programming.

Creating and using a socket as a client

The steps you need to carry out at the client end of the connection are as follows:

  1. Create a Socket object, as a top-level object.
  2. If necessary, set the family and protocol properties to specify the type of socket you want.
  3. Call the Open method to establish the connection with the server. This takes two arguments. The first is the network address of the server, as a character string; for example, this might be 'localhost' (your own machine), or '192.100.200.1' (an internet address) or 'www.microapl.co.uk' (an internet domain name). The second argument is the port number. Port numbers are usually associated with specific type of network protocol, for example port 80 is used for HTTP (web access). The Open method returns a status code indicating whether it succeeded: 0 = OK, 1 = Could not find host, 2 = Authentication error, 3 = Other error. If the connection was established successfully, you can now exchange data with the server.
  4. To send data to the server, call the Send method. This takes a character vector argument. The data is sent exactly as it, without any character translation (i.e. the character vector is treated as a sequence of raw bytes). The return code is 0 for success, or 3 if an error occurs (see the description of the status property below).
  5. To receive data from the server, call the Receive method. This takes no arguments. It returns a character vector, which is the data received (as an untranslated sequence of raw bytes). The APL task will block until the data has been received, or the time specified in the timeout property has elapsed. Note: If you do not want the task to be blocked waiting for data, use the onReceive event to ensure that Receive is called only when there is data already waiting.
  6. To end the session, call the Close method. This takes no arguments.

Creating and using a socket as a server

At the server end of a connection, things are usually a little more complex. This is because a server typically needs to be able to handle multiple client connections simultaneously, and must not get blocked communicating with one client when other clients are also trying to access the service. One way of handling this is to use multiple APLX tasks, with one task per client connection, plus one master task which waits for clients to connect. Another way is to use a single APLX task for everything, and use events to ensure that the task never gets blocked waiting for a response from a client.

The task which is waiting for clients to connect starts up first. It does the following:

  1. Create a Socket object, as a top-level object.
  2. Set the port property, to specify which port to listen to. If necessary, set the family and protocol properties to specify the type of socket you want.
  3. Call the Listen method. This sets up the socket so that it is associated with the port.
  4. You can now do one of two things. If the server task does not need to do anything until a client tries to connect, you can simply call the Accept method. The task will block, waiting for the next connection (or until the time specified by the timeout property has elapsed). Alternatively, you can set up an onConnectRequest callback, and call the Accept method only when a client tries to establish a connection.
  5. If an request from a client to establish a new connection is successful, the Accept method returns a non-zero positive integer. This is the internal handle for a new underlying operating-system socket, which can be used to exchange data with the client. The Accept method will return 0 if it timed out, or ¯1 if it could not establish the connection.
  6. The server now needs to create a new Socket object (as a top-level object), which will be used to exchange data with the client which has just connected. The internal handle returned by the Accept method should be written to the handle property of the new Socket object. It will often be convenient to create this new socket in a new APLX task (see the description of the APL object), although this is not essential. Data exchange takes place using the Send and Receive methods, as already described for the client end of the connection. When the connection is no longer needed, it should be closed using the Close method, and deleted.
  7. Meanwhile, the server loops back to step 4 and calls Accept again to wait for a new client connection, or waits for an onConnectRequest event.

Key properties of the Socket object

family: An integer scalar which specifies the address family of the socket. The default is 2, AF_INET, the address family used for the internet. It should be specified before calling the Open or Listen methods.

type: An integer scalar which specifies the socket type. It defaults to 1, SOCK_STREAM. It should be specified before calling the Open or Listen methods.

protocol: An integer scalar which specifies the protocol. It defaults to 0, the default for the address family.

port: An integer scalar which specifes the port number.

timeout: An integer scalar which sets the timeout (in milliseconds) before the Accept or Receive methods will return if no connection request or data is received. A value of ¯1 means 'wait for ever'. A value of 0 means 'return immediately'.

status: Read-only Returns the connection status as a two-element vector. The first element is 1 if the socket is connected, else 0. The second element is the latest error number from the underlying operating-system socket.

handle: An integer scalar, which is the handle of the underlying operating-system handle. You can use this, in conjunction with ⎕NA, to access socket functions not supported by the Socket object. You also need to write the result of the Accept method to this value at the server end, when you have created a new socket to accept an incoming client connection.

Key methods of the Socket object

Open: Open a new connection. (This method should be called from the client end of the connection only.) It takes two arguments. The first is the address of the server (usually an internet domain name or address, or 'localhost' for your own machine). The second is the port number to connect on. The result is a status code indicating whether the connection succeeded: 0 = OK, 1 = Could not find host, 2 = Authentication error, 3 = Other error. (More details of any error are available from the status property).

Listen: Establish the socket as a server listener. This method takes no arguments. (It should be called on the server end of the connection only.). It returns the same error code as Open.

Accept: Wait for a client to try to connect. This method takes no arguments. (It should be called on the server end of the connection only.). It causes the task to block until a connection request is made, or the timeout value is reached. It returns the handle to use for the client connection, or 0 if it timed out or ¯1 if it could not establish the connection.

Receive: Receive some data from the socket. This method takes no arguments. It causes the task to block until data is available, or the timeout value is reached. It returns a character vector which is the data received from the socket, as a raw sequence of bytes with no character translation. It returns an empty vector if it times out or an error occurs.

Send: Send some data to the socket. This method takes as an argument a character vector, which is the raw data to send to the other end of the connection. It returns 0 on success, else 3 if an error occurred.

Close: Disconnect and close the socket. This method takes no arguments. You always ensure the connection is closed cleanly by calling this method when the session is complete.

Callbacks of the Socket object

onConnectRequest: This event occurs on the server end, when you have called Listen and a client tries to connect. It indicates that you should now call the Accept method to accept the connection.

onReceive: This event occurs both on clients and servers. It indicates that the other end has sent some data, which you can now read using the Receive method.

onDisconnect: This event occurs both on clients and servers. It indicates that the other end has closed the connection. You should now call Close, and delete the socket.

Example

     ∇DEMO_Socket;x;count;handle;cmd;errcode;ServerSock;Client1;Client2;SendSock
[1]   ⍝ Show how to use the Socket object. For this demo, we set up a
[2]   ⍝ Server and two client APL tasks, all on the local machine
[3]   ⍝ using port 10000 (which hopefully won't clash with anything)
[4]   Client1←'⎕' ⎕NEW 'APL' ⋄ Client1.wssize←100000 ⋄ Client1.where←0 0 10 20
[5]   Client2←'⎕' ⎕NEW 'APL' ⋄ Client2.wssize←100000 ⋄ Client2.where←0 35 10 20
[6]   Client1.Open
[7]   Client2.Open
[8]   ⍝
[9]   ⍝ Create sockets in each client APL task
[10]  Client1.Execute "MySock←'⎕' ⎕NEW 'Socket'"
[11]  Client2.Execute "MySock←'⎕' ⎕NEW 'Socket'"
[12]  ⍝
[13]  ⍝ Create a socket for the server, in our main task
[14]  ServerSock←'⎕' ⎕NEW 'Socket'
[15]  ServerSock.port←10000
[16]  errcode←ServerSock.Listen
[17]  :If errcode≠0
[18]    ⍝ Oops, something went wrong
[19]    'An error occurred in Listen, error code ',⍕¯1↑ServerSock.status
[20]    :Return
[21]  :EndIf
[22]  ⍝
[23]  ⍝ After a few seconds, get the clients to try to connect, and await data
[24]  x←⎕DL 3
[25]  cmd←"x←MySock.Open 'localhost' 10000 ⋄ 'Server sent: ',MySock.Receive"
[26]  Client1.Execute("x←⎕DL 3 ⋄ 'Connecting..' ⋄ ",cmd)
[27]  Client2.Execute("x←⎕DL 6 ⋄ 'Connecting..' ⋄ ",cmd)
[28]  ⍝
[29]  ⍝ Meanwhile, loop round accepting connections
[30]  count←0
[31]  'Waiting for clients to connect...' ⋄ ⎕CC ' '
[32]  :Repeat
[33]    handle←ServerSock.Accept
[34]    :If handle>0
[35]      ⍝ A client is trying to connect
[36]      ⍝ Establish new socket to talk to the client.
[37]      ⍝ We'll just transfer one packet, then close the connection
[38]      'Got connection request.' ⋄ ⎕CC ' '
[39]      count←count+1
[40]      SendSock←'⎕' ⎕NEW 'Socket'
[41]      SendSock.handle←handle
[42]      errcode←SendSock.Send('Hello, client task ',⍕count)
[43]      SendSock.Close
[44]      SendSock.Delete
[45]    :ElseIf handle=¯1
[46]      ⍝ Oops, something went wrong
[47]      'An error occurred in Accept, error code ',⍕¯1↑ServerSock.status
[48]      :Leave
[49]    :EndIf
[50]  :Until count=2
[51]  ⍝
[52]  ⍝ Wait, then kill the child tasks (this will also delete their sockets)
[53]  x←⎕DL 4
[54]  Client1.Close ⋄ Client2.Close
[55]  ⍝
[56]  ⍝ Clean up this end as well
[57]  ServerSock.Close
     ∇

Properties

children class data events family handle methods name opened port properties protocol self status tie timeout type

Methods

Accept Close Create Delete Listen New Open Receive Send Set Trigger

Callbacks

onClose onConnectRequest onDestroy onDisconnect onOpen onReceive onSend


Topic: APLX Help : System Classes : List of Classes : Socket
[ Previous | Next | Contents | Index | APL Home ]