Return to Smalltalk Networking
Return to P1 Systems Homepage

Sockets/V

Copyright 1995,1998 P1 Systems Incorporated. All Rights Reserved.

Sockets/V provides a high-level interface to the industry-standard Windows Sockets interface, allowing TCP/IP communications to take place between cooperating Visual Smalltalk applications or between a Visual Smalltalk application and another TCP/IP-speaking application. Sockets/V provides the recommended asynchronous interface to the TCP/IP stack, allowing other activities to take place both within the Visual Smalltalk application and within Windows while your program is waiting for response from the network.

Datagram- and Stream-type sockets are provided, corresponding to the standard TCP and UDP protocols, as well as a MessageSocket class which provides datagram service over a stream connection and an ObjectSocket class which allows passing objects over a stream connection.

Access to name services is provided using the standard Windows Sockets asynchronous interface.

All defined error codes together with English descriptions are provided in the WinSockErrorMessages dictionary, allowing applications to provide meaningful error messages with minimal effort.

The following classes are provided in Sockets/V: Socket, DatagramSocket, StreamSocket, LineAtATimeSocket, MessageSocket, StringSocket, ObjectSocket, and NetworkMessage.


Contents

Introduction to Sockets Communication
Sample Programs
Socket
DatagramSocket
StreamSocket
LineAtATimeSocket
MessageSocket
ObjectSocket
StringSocket
NetworkMessage
ErrorCodes
Development & Runtime Files
Ordering Information
License Agreement


Version Information

Sockets/V

Version 1.1

Copyright (c) 1995,1998 P1 Systems Incorporated.

All Rights Reserved.


Sample Programs

The sample programs MsgSocketTestApp, DgramSocketTestApp, and ObjSocketTestApp are included in your Sockets/V distribution. The applications can play the role of client or server, or both. MsgSocketTestApp uses MessageSocket connections to pass messages, while DgramSocketTestApp uses DatagramSockets, and ObjSocketTestApp uses ObjectSockets

Operation of the test programs is straightforward. The Startup button is pressed, followed by the Server button if the instance of the program is to be a server, otherwise the Client button is pressed. The Server should be initialized before the client. The Test button of the client causes the client to send the string 'Testing 1, 2, 3...' to the server. The server, upon receiving the string, echoes it back to the client. The Cleanup button should be pressed before terminating the applications. Network activity is displayed in the list box contained in the applications' windows.

Note that MsgSocketTestApp cannot communicate with DgramSocketTestApp or ObjSocketTestApp. The test applications can only communicate with other instances of themselves. Note also that a single instance of the application can act as both client and server simultaneously, sending messages to and receiving messages from itself.

The source code to the MsgSocketTestApp is presented below. (The methods have been re-ordered so that they are presented roughly in the order in which they would be executed.) MsgSocketTestApp is invoked with MsgSocketTestApp new open.

ViewManager subclass: #MsgSocketTestApp
    instanceVariableNames:' serverAddr skt0 skt1 serverHostName localHostName serverPort serviceName
    listBox' classVariableNames: ''
    poolDictionaries: ' ColorConstants WinConstants WinSockConstants'

The open method starts the application. It assigns the host and service names (actually the address and number, respectively, in this case) and goes through the process of setting up the application window.

open
    "Answer self. Create the app views."
    | btnStartup btnTest btnCleanup topPane |
    self addView: ((topPane := TopPane new)
        framingBlock: [ :box | 20 @ 20 corner: 500 @ 300
        ]; owner: self;
       labelWithoutPrefix: 'Stream Sockets Test';
        backColor: ClrLightgray;
        when: #close perform: #close:).

    topPane addSubpane: ((listBox := LoggingPane new)
        framingBlock: [ :box |
            box leftTop + ( 12 @ 12) corner: box rightBottom - (98 @ 12)
        ]; owner: self).
    topPane addSubpane: ((btnTest := Button new)
        contents: 'Startup';
        font: SysFont;
        framingBlock: [ :box |
            box rightTop - ( 92 @ (-12) ) corner:
            box rightTop - ( 12 @ (-40) )];
        owner: self;
        when: #clicked perform: #startup:).

    topPane addSubpane: ((btnTest := Button new)
        contents: 'Server';
        font: SysFont;
        framingBlock: [ :box |
            box rightTop - ( 92 @ (-46) ) corner:
            box rightTop - ( 12 @ (-74) )];
        owner: self;
        when: #clicked perform: #server:).

    topPane addSubpane: ((btnTest := Button new)
        contents: 'Client';
        font: SysFont;
        framingBlock: [ :box |
            box rightTop - ( 92 @ (-80) ) corner:
            box rightTop - ( 12 @ (-108) )];
        owner: self;
        when: #clicked perform: #client:).

    topPane addSubpane: ((btnCleanup := Button new)
        contents: 'Canleup';
        font: SysFont;
        framingBlock: [ :box |
            box rightTop - ( 92 @ (-114) ) corner:
            box rightTop - ( 12 @ (-142) )];
        owner: self;
        when: #clicked perform: #cleanup:).

    topPane addSubpane: ((btnCleanup := Button new)
        contents: 'Test';
        font: SysFont;
        framingBlock: [ :box |
            box rightTop - ( 92 @ (-148) ) corner:
            box rightTop - ( 12 @ (-176) )];
        owner: self;
        when: #clicked perform: #test:).

    self when: #close perform: #close:.
    self openWindow.
    ^self

The startup method is invoked by the Startup button. It displays the Windows Sockets vendor-supplied information string in a message box like the one shown here (via startupShowInfo) and translates the local host name to an address string.

startup: ignored

    Socket startupShowInfo.
    localHostName := Socket hostName.

    Socket
        onHostAddrFor: localHostName
        evaluate:
        [ :name :addr |
            listBox insertItem: 'Local host: ', localHostName, '(', addr,
        ')' ]
        error:
        [ :err |
            Socket
                errorBox: 'Error obtaining host address for ',localHostName,':
            ' socket: err
        ].
    ^self

The server method is invoked by the Server button. It solicits a port number to listen on from the user, creates a new MessageSocket and listens for connections, and for each connection it accepts, establishes a block for received messages which simply echoes the message back to the sender.

server: ignored
    "Answer self. Set up echo server."
    serverPort := Prompter
        prompt: 'Service port number to listen on'
        default: '6001'.
    serverPort = nil
    ifTrue: [ ^nil ].

    skt0 := MessageSocket new.
    skt0
        listenOn: serverPort
        onAcceptEvaluate:
        [ :skt |
            skt onNameEvaluate:
        [ :name |
            listBox insertItem: 'Server: connected to
            ',name,'.'. skt
                onReadEvaluate:
                [ :netMsg :skt |
                    listBox insertItem: 'Server: ',(netMsg at: 1). skt write: netMsg
                ]
                error: nil.
        ]
   ]
   error: nil.
   ^self

The client method is invoked when the Client button is pressed. A series of nested blocks performs the following steps after obtaining the host name (or address) and the service name (or port number) from the user: the host address is obtained., a MessageSocket is created and bound, the server port number is obtained, a connection is attempted with the server, and the clientRead:skt: message is established as the message to be sent upon receipt of a message. Error checking is performed for each step by the error: blocks.

client: ignored
    "Answer self. Set up client."
    serverHostName := Prompter
        prompt: 'Server Host Name (or address) to connect
        to' default: localHostName.
    serverHostName = nil
    ifTrue: [ ^nil ].

    serviceName := Prompter
        prompt: 'Service Name (or port number) to connect to'
        default: '6001'.
    serviceName = nil ifTrue: [ ^nil].
    serverAddr := nil.

    Socket
        onHostAddrFor: serverHostName
        evaluate:
	  [:name :addr |
            serverAddr := addr.
            skt1 := MessageSocket new.
            Socket
                onServicePortFor: serviceName
                evaluate:
                [ :name :port |
                    serverPort := port.
                    skt1
                        connect: serverAddr
                        port: serverPort
                        evaluate:
                        [ :skt |
                            skt
                                onNameEvaluate:
                                [ :name |
                                    listBox insertItem: 'Client: connected to ', name,'.'
                                ].
                            skt1
                                onReadSend: #clientRead:skt:
                                to: self
                                error: nil.
                        ]
                        error: nil
                ]
                error: nil
        ]
        error: nil.
    ^self

The clientRead:skt: method handles incoming messages. They are displayed in the listbox.

clientRead: netMsg skt: skt
    "Answer nil. Handle incoming reads."
    listBox insertItem: 'Client: ',(netMsg at: 1).
    ^nil

The test method, only functional for properly initialized clients, simply sends a test message on the connected socket.

test: aPane
    "The test event has been signaled."
    skt1
        write: (NetworkMessage with:
        (Prompter prompt: 'Text to send' default: 'Testing 1, 2, 3...')). ^nil

The cleanup method clears the listbox, closes all the sockets, and sends Socket>>cleanup.

cleanup: ignored
    "Cleanup the Windows Sockets session."
    | resultCode count |
    listBox deleteAll.
    Socket socketList do: [ :each |
        each close ].
    Socket cleanup.
    ^self

The close method simply invokes cleanup in case it hasn't been done yet.

close: ignored
    "Close down the
    application." | answer |
    Smalltalk isRunTime
    ifTrue:
    [
        (MessageBox confirm: 'Are you sure you want to exit?')
        ifTrue:
        [
            self cleanup: nil.
            self close.
            ^Smalltalk exit
        ]
        ifFalse:
        [
            ^self
        ]
    ].

    ^super close


Introduction to Sockets Communication

Basic Concepts

The basic building block for communication is the socket. A socket is an endpoint of communication to which a name may be bound. Each socket in use has a type and an associated process or program. Sockets exist within communication domains. A communication domain is an abstraction introduced to bundle common properties of threads communicating through sockets. Sockets normally exchange data only with sockets in the same domain (it may be possible to cross domain boundaries, but only if some translation process is performed). The Windows Sockets facilities support a single communication domain: the Internet domain, which is used by processes which communicate using the Internet Protocol Suite.

Two basic types of sockets are available to a user. A stream socket provides for the bi-directional, reliable, sequenced, and unduplicated flow of data without record boundaries. A datagram socket supports bi-directional flow of data which is not promised to be sequenced, reliable, or unduplicated. That is, a process receiving messages on a datagram socket may find messages duplicated, and possibly, in an order different from the order in which it was sent. An important characteristic of a datagram socket is that record boundaries in data are preserved. Datagram sockets closely model the facilities found in many contemporary packet switched networks such as Ethernet.

Instances of the MessageSocket class provided by Sockets/V support record-oriented communication over a stream connection, thus providing bi- directional, reliable, sequenced, and unduplicated data flow while preserving record boundaries. Message sockets also allow dispatching of received messages based on the contents of a particular element of the message.

The LineAtATimeSocket class provided by Sockets/V is specially designed to simplify processing of Internet protocols such as FTP (File Transfer Protocol), SMTP (Simple Mail Transfer Protocol), and POP3 (Post Office Protocol version 3). LineAtATimeSockets deliver records from a TCP Stream connection delimited by carriage returns or carriage return-line feed pairs.

The StringSocket class provided by Sockets/V is a specialization of MessageSocket which allows sending strings between Sockets/V applications.

The Objectsocket class provided by Sockets/V is a specialization of MessageSocket which allows sending Visual Smalltalk objects between Sockets/V applications.

Client-server Model

The most commonly used paradigm in constructing distributed applications today is the client/server model. In this scheme client applications request services from a server application. This implies an asymmetry in establishing communication between the client and the server. The client and the server require a well-known set of conventions before service may be rendered (and accepted). This set of conventions compromises a protocol which must be implemented at both ends of a connection. Depending on the situation, the protocol may be symmetric or asymmetric. In a symmetric protocol, either side may play the master or slave roles. In an asymmetric protocol, one side is immutably recognized as the master, with the other as the slave. An example of a symmetric protocol is the TELNET protocol used in the Internet for remote terminal emulation. An example of an asymmetric protocol is the Internet file transfer protocol, FTP. Regardless of whether the specific protocol used in obtaining a service is symmetric or asymmetric, when accessing a service there is a "client process" and a "server process".

A server application normally listens at a well-known address for service requests. that is, the server process remains dormant until a connection is requested by a client's connection to the server's address. At such a time the server process "wakes up" ands services the client, performing whatever appropriate actions the client requests of it. While connection-based services are the norm, some services are based on the use of datagram sockets.

Windows Sockets

The Windows Sockets specification defines a network programming interface for Microsoft Windows which is based on the "socket" paradigm popularized in the Berkeley Software Distribution (BSD) from the University of California at Berkeley. It encompasses both familiar Berkeley socket style routines and a set of Windows- specific extensions designed to allow the programmer to take advantage of the message-driven nature of Windows.

Windows Sockets operates asynchronously. Sockets/V classes' behavior reflects this aspect of the Windows Sockets interface protocols. Typically, messages sent to a Socket object do not return a useful result immediately. Instead, they send a request to Windows Sockets and evaluate a block or send a message to an object when Windows Sockets has responded. This allows your application (and Windows) to perform other work while your request is being processed (perhaps elsewhere in the network).

In order to communicate with another application via TCP/IP, both parties must have an Internet address. Internet addresses are usually represented as four decimal numbers separated with periods, for example: 124.3.12.2. Internet addresses usually have a hostname associated with them which is easier to remember than the four numbers. Internet addresses and hostnames are usually assigned by a central authority in an organization to prevent conflicts.

A TCP/IP-speaking system is allowed to maintain communications with multiple remote systems at once. In order to do this without getting confused, communications is said to be performed between ports on the communicating systems. Ports are designated by decimal numbers. Like hostnames for Internet addresses, ports can be assigned service names. Here is how Sockets/V objects would depict the service personnelDb on the host named hoochie.p2.com: hoochie.p2.com:personnelDb. Alternatively, the address or port number can be substituted for the names, perhaps resulting in a designation like: 124.3.12.2:6001. A TCP/IP connection is defined at either end by the local host:service pair (which is associated with a remote host:service pair).

Hostnames and service names are often maintained in files called hosts and services, respectively. For two applications to establish communications, one application must attempt to connect to the other by specifying a port (or service) on which the other is listening. If it cannot be determined which application might attempt to connect first, then both applications may listen on a port known to the other. It is up to you to decide what port (and associated service name) you will use for your communications.

Using Sockets/V

Sockets/V provides a high-level interface to Windows Sockets, hiding much of the complexity involved with handling asynchronous notification in Visual Smalltalk. Generally, applications do not need to subclass the Sockets/V classes, but simply create instances of them with which to communicate. The following sections describe setting up server and client applications using Sockets/V.

A Sockets/V Server Application

A Sockets/V server application is normally supplied with a service port name upon which to listen. Here are the steps a server application would normally perform:

  1. Startup a Sockets/V session with Socket>>startup.
  2. Create a socket (we'll assume a MessageSocket for this example) using MessageSocket>>new.
  3. Translate the server name to a server port number with Socket>>onServerPortEvaluate:error:.
  4. In the success block of 3, listen on the server port, using MessageSocket>>listenOn:onAcceptEvaluate:error:.
  5. In the success block of 4, which indicates the acceptance of new connection from a client, establish a received message handler with MessageSocket>>onReadEvaluate: and, optionally, a close handler with MessageSocket>>onCloseEvaluate:.
  6. Perform whatever processing is required when a message is received in the onReadEvaluate: block, perhaps using MessageSocket>>write:to reply to the client.
  7. When it is time to terminate, use MessageSocket>>close to close all open sockets (probably saved in a collection) and invoke Socket>>cleanup to terminate the Sockets/V session.

An alternative to using the nested evaluation of blocks as in the above is to use the send:to: form of the MessageSocket methods to invoke other application methods.

A Sockets/V Client Application

A Sockets/V client-side application normally performs the following steps after being supplied with the server hostname and service name:

  1. Startup a Sockets/V session with Socket>>startup.
  2. Translate the server hostname and service name with Socket>>onHostAddressFor:evaluate:error: and Socket>>onServicePortFor:evaluate:error:.
  3. Create a socket (we'll assume a MessageSocket for this example) using MessageSocket>>new.
  4. Connect to the server with MessageSocket>>connect:port:evaluate:error:, establishing a block to be evaluated when the connection is established.
  5. In the block established in 4 above, establish a received message handler with MessageSocket>>onRead:, and optionally, a close handler in case the server dies or the connection is lost with MessageSocket>>onClose: Begin communications with the server using MessageSocket>>write:.
  6. Perform processing of received replies in the block established in 5 above.
  7. When processing is complete, close the connection with MessageSocket>>close and close down the Sockets/V session with Socket>>cleanup.

An alternative to using the nested evaluation of blocks as in the above is to use the send:to: form of the MessageSocket methods to invoke other application methods. Note also that the MessageSocket>>onMessageElement:evaluate:method can be used to dispatch based on the contents of specific fields in received messages. Note that in the application startup method (usually NotificationManager>>startUpApplication), you should send the initialize message to the global object Network to perform one-time initialization of Sockets/V internal elements.


Socket

Socket is the base class for DatagramSocket, StreamSocket, and MessageSocket. Instance methods common to the three types of sockets are provided. Class methods are provided to perform network database operations for translating host names and addresses, translating service names and ports, obtaining the local host name and address, and obtaining information about the local host Windows Sockets implementation.

Inherits From:

Object

Inherited By:

DatagramSocket

StreamSocket

MessageSocket

Named Instance Variables:

(none)

Class Variables:

SocketList
Contains a dictionary where the keys are WinSock socket identifiers and the values are instances of Socket.

Pool Dictionaries:

WinSockConstants
Contains a dictionary of Windows Sockets constants. These constants are defined in the header file WINSOCK.H.

Class Methods:

cleanup
Deallocate data structures associated with this Windows Sockets session. This message should be sent once for every startup message which has been sent.
closeAllSockets
Close all open sockets. Use this method to clean up after abnormal terminations during program development.
errorBox: aString socket: aSocket
Display the last error incurred by the specified socket in a dialog box. The contents of the dialog box includes the error text and the error description. ASocket may be either a Socket object or an integer error code.
errorDescription: errorCode
Answers the long error description for errorCode. The long error descriptions are contained in the dictionary WinSockErrorDescriptions.
errorMessage: errorCode
Answers the error message, including line breaks, displayed by the errorBox:socket: method.
errorText: errorCode
Answers the one-word error text associated with the integer errorCode.
hostName
Answer the name of the local host.
hostPart: aNameOrAddressString
Answer the host part of aNameOrAddressString (i.e., the part before the colon). For example if aNameOr AddressString was '122.44.2.34:23', hostPart: would return '122.44.2.34'.
maxSockets
Answer the maximum number of sockets supported by the current TCP/IP implementation.
maxUdpDg
Answer the largest datagram size supported by the current TCP/IP implementation.
netInfo
Answer the information string identifying the current TCP/IP implementation provided by the Windows Sockets vendor.
onHostAddrFor: aHostname evaluate: aTwoArgumentBlock error: aOneArgumentBlock
Obtain the IP address for aHostname. Evaluate aTwoArgumentBlock if successful, passing the host name and address (in dotted string form) as arguments. If unsuccessful, evaluate aOneArgumentBlock passing the error code as the argument. If aOneArgumentBlock is nil, a default error handler is invoked which displays an error description in a dialog box.
onHostAddrFor: aHostname send: aTwoArgumentSelector to: anObject error: aOneArgumentSelector
Obtain the IP address for aHostname. Send aTwoArgumentSelector to anObject if successful, passing the hostname and address as arguments. If unsuccessful, send aOneArgumentSelector to anObject passing the error code as the argument. If aOneArgumentSelector is nil, a default error handler is invoked which displays an error description in a dialog box.
onHostNameFor: anAddressString evaluate: aTwoArgumentBlock error: aOneArgumentBlock
Obtain the hostname string for the IP address anAddressString. Evaluate aTwoArgumentBlock if successful, passing the host name and address (in dotted string form) as arguments. If unsuccessful, evaluate aOneArgumentBlock passing the error code as the argument. If aOneArgumentBlock is nil, a default error handler is invoked which displays an error description in a dialog box.
onHostNameFor: anAddressString send: aTwoArgumentSelector to: anObject error: aOneArgumentSelector
Obtain the hostname string for the IP address anAddressString. Send aTwoArgumentSelector to anObject if successful, passing the host name and address (in dotted string form) as arguments. If unsuccessful, send aOneArgumentSelector to anObject passing the error code as the argument. If aOneArgumentSelector is nil, a default error handler is invoked which displays an error description in a dialog box.
onServiceNameFor: aPortNumber evaluate: aTwoArgumentBlock error: aOneArgumentBlock
Obtain the service name string for aPortNumber. Evaluate aTwoArgumentBlock if successful, passing the service name and port number as arguments. If unsuccessful, evaluate aOneArgumentBlock passing the error code as the argument. If aOneArgumentBlock is nil, a default error handler is invoked which displays an error description in a dialog box.
onServiceNameFor: aPortNumber send: aTwoArgumentSelector to: anObject error: aOneArgumentSelector
Obtain the service name string for aPortNumber. Send aTwoArgumentSelector to anObject if successful, passing the service name and port number as arguments. If unsuccessful, send aOneArgumentSelector to anObject passing the error code as the argument. If aOneArgumentSelector is nil, a default error handler is invoked which displays an error description in a dialog box.
onServicePortFor: aServiceName evaluate: aTwoArgumentBlock error: aOneArgumentBlock
Obtain the port number for aServiceName. Evaluate aTwoArgumentBlock if successful, passing the service name and port number as arguments. If unsuccessful, evaluate aOneArgumentBlock passing the error code as the argument. If aOneArgumentBlock is nil, a default error handler is invoked which displays an error description in a dialog box.
onServicePortFor: aServiceName send: aTwoArgumentSelector to: anObject error: aOneArgumentSelector
Obtain the port number for aServiceName. Send aTwoArgumentSelector to anObject if successful, passing the service name and port number as arguments. If unsuccessful, send aOneArgumentSelector to anObject passing the error code as the argument. If aOneArgumentSelector is nil, a default error handler is invoked which displays an error description in a dialog box.
servicePart: aNameOrAddressString
Answer the service part of aNameOrAddressString (i.e., the part after the colon). For example, if aNameOrAddressString was 'hoochie:ftp', servicePart: would return 'ftp'.
startup
Initiate a Windows Sockets session. This message or startupShowInfo must be sent before any other interaction can take place.
startupShowInfo
Initiate a Windows Sockets session and display in a MessageBox the netInfo string. This message or startup must be sent before any other interaction can take place.

Instance Methods:

addrString
Answer the address string of the remote host and port in the form address:port. For example: 121.2.14.5:6002.
close
Close the socket. No further requests of the socket will be honored.
context
Answer the contents of the context instance variable. The context instance variable is available to an application to retain socket-specific information.
context: anObject
Set the value of the context instance variable.
displayErrors
Answer true if errors are automatically displayed in dialog boxes when nil is passed as the error block.
displayErrors: aBoolean
Turn error display on or off. If aBoolean is true, error display is turned on. Error display should always be turned off when an application is running unattended on a server system, as the error dialogs require keyboard input to allow execution to continue. During development and for client applications, errorDisplay is useful for detecting unhandled errors (i.e., when you pass nil for an error block).
errorCode
Answer the last generated error code.
nameString
Answer the name string of the remote host in the form hostname:service. If the remote host address cannot be resolved to a hostname or if the remote port number cannot be resolved to a service name, the address or port number is used instead.
onNameEvaluate: aOneArgumentBlock
Obtain the hostname and service name of the connected remote host in the form hostname:service. AOneArgumentBlock is evaluated with the argument passed being the name string. If either the host address or service port cannot be translated, the address or number is used in place of the hostname or service name. For example if the remote host address of 121.22.22.45 could not be resolved to a hostname, but the remote service port 23 was successfully translated to 'ftp', the name string passed to aOneArgumentBlock would be '121.22.22.45:ftp'.
type
Answer the type of the socket. One of SockDgram or SockStream (defined in the WinSockConstants dictionary). Note that it is not possible to determine whether a Stream socket is in actuality a Stream class socket of one of the StreamSocket subclasses (e.g., MessageSocket, StringSocket, etc.).


DatagramSocket

Instances of DatagramSocket provide datagram-type communication. Datagram communication does not require that a connection be established before communication can begin as does stream-type communication. Typically, one party to the communication (the server) binds its socket to a port number known to the other parties. The other parties do not explicitly bind to a port number, but simply accept the port assigned to them by the Windows Sockets software. When the server receives data, it can obtain the address and port number of the sender to send a reply.

Datagrams are limited in size by the particular TCP/IP implementation and messages cannot be automatically divided across multiple datagrams. Datagrams are always delivered as a unit and are never combined or fragmented when delivered as stream-type messages can be. Datagrams are not guaranteed to be delivered as are stream-type communications, but this is rarely a problem in a LAN environment. Also, there is no notification provided when the partner in a datagram communications session terminates or closes its socket.

Note that arbitrary byte sequences may be sent and received using ByteArray objects instead of String objects.

Inherits From:

Socket

Object

Inherited By:

(none)

Named Instance Variables:

readBlock
Contains a two-argument block which is evaluated when data is received.
readErrorBlock
Contains a one-argument block which is evaluated when data is received in error.

Class Variables:

(none)

Pool Dictionaries:

WinSockConstants
Contains a dictionary of Windows Sockets constants. These constants are defined in the header file WINSOCK.H contained in the Windows Sockets specification.

Class Methods:

(none)

Instance Methods:

bind: aPort
Answer errorCode (0 = success). Bind the socket to aPort. Also establishes read and close notification. Note that invocation of this method is not necessary unless other network applications are expecting to find your application at a specific service port.
onReadEvaluate: aTwoArgumentBlock error: aOneArgumentBlock
Establishes aTwoArgumentBlock to be evaluated when data is received. The arguments to aTwoArgumentBlock are a string object containing the received data and the socket instance on which the data was received. If an error occurs receiving data, aOneArgumentBlock is evaluated with the socket passed as the argument. If aOneArgumentBlock is nil, a default error handler is invoked which displays an error description in a dialog box.
onReadSend: aTwoArgumentSelector to: anObject error: aOneArgumentSelector
Establishes that aTwoArgumentSelector be sent to anObject when data is received. The arguments passed are a string object containing the data and the socket instance on which it was received. If an error occurs receiving data, aOneArgumentSelector is sent to anObject with the socket as the argument. If aOneArgumentSelector is nil, a default error handler is invoked which displays an error description in a dialog box.
write: aString
Sends aString to the host address and port from which the last incoming message was received on this socket. AString is limited to the length returned by the Sockets class method maxUdpDg.
write: aString to: anAddressString
Sends aString to the host and port designated by anAddressString. AnAddressString is normally obtained by sending the addrString message to the socket instance which was passed with the received data. AString is limited to the length returned by the Sockets class method maxUdpDg.
write: sString to: anAddressString port: aPortNumber
Sends aString to the host and port designated by anAddressString and aPortNumber. AnAddressString is in dotted form (e.g., 121.12.5.42). APortNumber is an integer. AString is limited to the length returned by the Sockets class method maxUdpDg.


StreamSocket

Stream sockets provide guaranteed sequential delivery of byte streams between communicating partners. Before stream communication can begin, one party (the server) must listen on a port known to the other party, and the other party must connect to that port. The listening party must then accept the connection. A new socket is created for the accepted connection so that the listening socket remains available to accept additional connections. Communications can then proceed between the server and client using the new server socket and the original client socket.

Termination of stream communications occurs when either party closes their socket. The other party is notified of the closing.

Note that unlike datagram-type communications, stream connections use up a socket on the listening end for each connection. TCP/IP implementations typically place a limit on the number of sockets which may be created and this limits the number of simultaneous stream connections possible.

Stream socket implementations are allowed to deliver received data in pieces different than those in which it was sent, although the bytes are required to be in the same order. Stream socket implementations may coalesce or fragment the data at will. Thus, data may not always be received in the same chunks in which it was sent as is the case with datagram-type communications. Note that the MessageSocket class provides datagram-type messages over a stream- type connection, providing the benefits of both types of socket communication.

Note that arbitrary byte sequences may be sent and received using ByteArray objects instead of String objects.

Inherits From:

Socket

Object

Inherited By:

LineAtATimeSocket

MessageSocket

Named Instance Variables:

acceptBlock
Contains a block to be evaluated when connections are accepted.
closeBlock
Contains a block to be evaluated when a connection is closed.
connectBlock
Contains a block to be evaluated when a connection is established.
connectErrorBlock
Contains a block to be evaluated when an error occurs in an attempt to establish a connection.
listenErrorBlock
Contains a one-argument block evaluated when an error occurs when attempting a listen operation.
readBlock
Contains a two-argument block evaluated when data is received.
readErrorBlock
Contains a one-argument block evaluated when data is received in error.

Class Variables:

(none)

Pool Dictionaries:

WinSockConstants
Contains a dictionary of Windows Sockets constants. These constants are defined in the header file WINSOCK.H contained in the Windows Sockets specification.

Class Methods:

(none)

Instance Methods:

connect: anAddressString port: aPortNumber evaluate: aOneArgumentBlock error: aOneArgErrorBlock
Attempts to establish a connection to aPortNumber on the host specified by anAddressString. AnAddressString is in dotted form (e.g., 121.13.24.56). If the connection is successful, aOneArgumentBlock is evaluated with the argument being the socket which successfully connected. If an error occurs, aOneArgErrorBlock is evaluated with the socket passed as the argument. If aOneArgErrorBlock is nil, a default error handler is invoked which displays an error description in a dialog box. Answers the bind or connect error code (0 = success).
connect: anAddressString port: aPortNumber send: aOneArgumentSelector to: anObject error: aOneArgErrorSelector
Attempts to establish a connection to aPortNumber on the host specified by anAddressString. AnAddressString is in dotted form (e.g., 121.13.24.56). If the connection is successful, aOneArgumentSelector is sent to anObject with the argument being the socket which successfully connected. If an error occurs, aOneArgErrorSelector is sent with the socket passed as the argument. If aOneArgErrorSelector is nil, a default error handler is invoked which displays an error description in a dialog box. Answers the bind or connect error code (0 = success).
listenOn: aPort onAcceptEvaluate: aOneArgumentBlock error: aOneArgErrorBlock
Bind to aPort and evaluate aOneArgumentBlock when a connection is accepted. The argument to aOneArgumentBlock is the newly created socket. If an error occurs, evaluate aOneArgErrorBlock passing the socket as the argument. If aOneArgErrorBlock is nil, a default error handler is invoked which displays an error description in a dialog box. Answers the error code returned from the listen call (0 = success).
listenOn: aPort onAcceptSend: aOneArgumentSelector to: anObject error: aOneArgErrorSelector
Bind to aPort and send aOneArgumentSelector to anObject when a connection is accepted. The argument to aOneArgumentBlock is the newly created socket. If an error occurs, send aOneArgErrorSelector to anObject with the socket as the argument. If aOneArgErrorSelector is nil, a default error handler is invoked which displays an error description in a dialog box. Answers the error code returned from the listen call (0 = success).
onAcceptEvaluate: aOneArgumentBlock
Establish aOneArgumentBlock to be evaluated whenever a connection is accepted. The argument is the newly created socket.
onAcceptSend: aOneArgumentSelector to: anObject
Establishes that aOneArgumentSelector be sent to anObject when a connection is accepted. The argument is the newly created socket.
onCloseEvaluate: aOneArgumentBlock
Establishes aOneArgumentBlock to be evaluated when the connection is closed. The argument is the socket whose connection is being closed. Note: You should send close to the socket to free the resources associated with it after you have finished with it.
onCloseSend: aOneArgumentSelector to: anObject
Establishes that aOneArgumentSelector be sent to anObject when the connection is closed. The argument is the socket whose connection is being closed. Note: You should send close to the socket to free the resources associated with it after you have finished with it.
onReadEvaluate: aTwoArgumentBlock error: aOneArgumentBlock
Establishes aTwoArgumentBlock to be evaluated when data is received. The arguments to aTwoArgumentBlock are a string object containing the received data and the socket instance on which the data was received. If an error occurs, aOneArgumentBlock is evaluated with the socket as the argument. If aOneArgumentBlock is nil, a default error handler is invoked which displays an error description in a dialog box.
onReadSend: aTwoArgumentSelector to: anObject error: aOneArgumentSelector
Establishes that aTwoArgumentSelector be sent to anObject when data is received. The arguments passed are a string object containing the data and the socket instance on which it was received. If a read error occurs, aOneArgumentSelector is sent to anObject with the socket as the argument.If aOneArgumentSelector is nil, a default error handler is invoked which displays an error description in a dialog box.
write: aString
Sends aString to the connected host and port.


LineAtATimeSocket

LineAtATimeSocket objects provide a line-at-a-time text record service appropriate for use with Internet protocols such as FTP, SMTP, and POP3. These protocols expect messages to be delimited with carriage returns or carriage return-line feed pairs. The LineAtATimeSocket onReadEvaluate:error: method (inherited from StreamSocket) passes only complete lines to the twoArgumentBlock rather than fragments as might occur with StreamSocket. (LineAtATimeSocket also strips the lines of the delimiting CR or CR-LF characters.) This allows the application to focus on the protocol in use rather than the buffering of data until a complete record is obtained.

The write: method suffixes its argument with the result of evaluating Stream>>crString before sending it to the remote partner.

Inherits From:

StreamSocket

Socket

Object

Inherited By:

(none)

Named Instance Variables:

(none)

Class Variables:

(none)

Pool Dictionaries:

(none)

Class Methods:

(none)

Instance Methods:

write: aString
Writes aString on the LineAtATimeSocket suffixed with the result of Stream>>crString.


MessageSocket

MessageSocket objects provide sequenced and reliable datagram-style communications over stream-type connections. MessageSocket objects pass structured messages using NetworkMessage objects. The NetworkMessage objects are always delivered as a unit. This allows message-based communications to proceed without requiring the application developer to deal with datagram size limitations, unguaranteed delivery, and the lack of close notification as would be the case if datagram sockets were used. NetworkMessage objects allow automatic dispatching of the received message based on the content of the message. See the description of NetworkMessage for more information.

Note that MessageSockets can only be used with another application supporting MessageSockets and NetworkMessages.

Inherits From:

StreamSocket

MessageSocket

Socket

Object

Inherited By:

StringSocket

Named Instance Variables:

currentMsg
Contains the message currently being received.
msgLen
Contains the length of the message currently being received.
onElementList
A dictionary containing information on blocks to execute when NetworkMessage elements arrive with specified values.

Class Variables:

(none)

Pool Dictionaries:

(none)

Class Methods:

(none)

Instance Methods:

onReadElement: anInteger value: aString evaluate: aTwoArgumentBlock
Establishes that aTwoArgumentBlock be evaluated whenever a message containing aString in element number anInteger is received. The arguments passed are the NetworkMessage and the socket. NetworkMessage elements are numbered beginning with one.
onReadElement anInteger value: aString send: aTwoArgumentSelector to: anObject
Establishes that aTwoArgumentSelector be sent to anObject whenever a message containing aString in element number anInteger is received. The arguments passed are the NetworkMessage and the socket. NetworkMessage elements are numbered beginning with one.
write: aNetworkMessage
Sends aNetworkMessage to the remote partner.


StringSocket

StringSocket objects provide a simplified MessageSocket service. StringSockets allow single strings or ByteArrays to be sent and received using a MessageSocket service without the necessity of dealing with NetworkMessages.

The StreamSocket onRead methods are used to read incoming strings.

Inherits From:

MessageSocket

Socket

Object

Inherited By:

(none)

Named Instance Variables:

(none)

Class Variables:

(none)

Pool Dictionaries:

(none)

Class Methods:

(none)

Instance Methods:

write: aString
Writes aString on the StringSocket.


ObjectSocket

ObjectSocket objects provide a MessageSocket specialized to send and receive objects. Classes of objects to be sent must be defined in the receiving Visual Smalltalk image and must support the storeString method.

The StreamSocket onRead methods are used to read incoming objects.

Inherits From:

MessageSocket

Socket

Object

Inherited By:

(none)

Named Instance Variables:

(none)

Class Variables:

(none)

Pool Dictionaries:

(none)

Class Methods:

(none)

Instance Methods:

write: anObject
Writes anObject on the ObjectSocket.


NetworkMessage

NetworkMessage objects provide a means of sending and receiving record- oriented structures between cooperating Sockets/V applications. NetworkMessage objects are similar to OrderedCollection objects in that they contain numbered elements. NetworkMessage objects automatically expand to accommodate the highest numbered element added. Upon receipt, the MessageSocket onMessageElement methods may be used to dispatch the received message based on the contents of any element.

NetworkMessage objects, combined with MessageSockets, provide the easiest method of transferring complex data between cooperating Sockets/V programs.

Inherits From:

WinSockBuffer

ExternalBuffer

Object

Inherited By:

(none)

Named Instance Variables:

current
Contains a boolean value indicating whether the transmit buffer is current.
elements
Contains an OrderedCollection of the message elements.

Class Variables:

(none)

Pool Dictionaries:

(none)

Class Methods:

new
Answer a new NetworkMessage object.
with: aByteArray
Answer a NetworkMessage with element one initialized to aByteArray.
with: aByteArray1with: aByteArray2
Answer a NetworkMessage with elements one and two initialized to aByteArray1 and aByteArray2.
with: aByteArray with: aByteArray with: aByteArray
Answer a NetworkMessage with elements one, two, and three initialized.
with: aByteArray with: aByteArray with: aByteArray with: aByteArray
Answer a NetworkMessage with elements one, two, and three initialized.

Instance Methods:

add: aByteArray
Add aByteArray to the next element position in the message. The message is automatically expanded to accommodate the new element.
at: anInteger
Answer element number anInteger. Elements are numbered starting at one.
at: anInteger put: aByteArray
Insert aByteArray in element number anInteger. If there are fewer than anInteger elements in the message, empty elements are created until number anInteger is reached.
do: aOneArgumentBlock
Evaluate aOneArgumentBlock once for each element in the message, passing the element as the argument.
last
Answer the last element in the message.
last: aByteArray
Insert aByteArray in the last message element.


Error Codes

The following error codes are contained in WinSockConstants dictionary. The text descriptions are contained in the WinSockErrorDescriptions dictionary. The WinSockErrorCodes dictionary translates the numeric codes returned by Windows Sockets to the error text shown in the first column below.

Error Code Description
WsaeAcces The requested address is a broadcast address, but the appropriate flag was not set.
WsaeAddrInUse An attempt has been made to listen on an address in use.
WsaeAddrNotAvail The specified address is not available from the local machine.
WsaeAFNoSupport Addresses in the specified family cannot be used with this socket.
WsaeAlready The asynchronous routine being canceled has already completed.
WsaeConnAborted The connection was aborted due to timeout or other failure.
WsaeConnRefused The attempt to connect was forcefully rejected.
WsaeConnReset The connection was reset by the remote side.
WsaeDestAddrReq A destination address is required.
WsaeFault The optlen argument was invalid.
WsaeInProgress A blocking Windows Sockets call is in progress.
WsaeIntr The call was canceled.
WsaeInval The socket is already bound to an address.
WsaeIsConn The socket is already connected.
WsaeMFile No more file descriptors are available.
WsaeMsgSize The datagram was too large to fit into the specified buffer and was truncated.
WsaeNetDown The Windows Sockets implementation as detected that the network subsystem has failed.
WsaeNetReset The connection must be reset because the Windows Sockets implementation dropped it.
WsaeNetUnreach The network can't be reached from this host at this time.
WsaeNoBufs No/insufficient buffer space is available
WsaeNoProtoOpt The option is unknown or unsupported. In particular, SO_BROADCAST is not supported on sockets of type SOCK_STREAM, while SO_ACCEPTCONN, SO_DONTLINGER, SO_KEEPALIVE, SO_LINGER and SO_OOBINLINE are not supported on sockets of type SOCK_DGRAM.
WsaeNotConn The socket is not connected.
WsaeNotSock The descriptor is not a socket.
WsaeOpNotSupp The specified operatin is not supported by the socket.
WsaeOpNotSupp The referenced socket is not a type that supports connection-oriented service.
WsaeProtoType The specified protocol is the wrong type for this socket.
WsaeShutdown The socket has been shutdown.
WsaeSocktNoSupport The specified socket type is not supported in this address family.
WsaeTimedOut Attempt to connect timed out without establishing a connection
WsaeWouldBlock The asynchronous operation cannot be scheduled at this time due to resource or other constraints.
WsaHostNotFound Authoritative Answer Host not found.
WsaNoData Valid name, no data record of requested type.
WsaNoRecovery Non recoverable errors, FORMERR, REFUSED, NOTIMP.
WsaNotInitialised A successful Socket startup or Socket startupShowInfo must occur before using this API.
WsaSysNotReady Indicates that the underlying network subsystem is not ready for network communication.
WsaTryAgain Non-Authoritative Host not found, or SERVERFAIL.
WsaVerNotSupported The version of Windows Sockets API support requested is not provided by this particular Windows Sockets implementation.


Development and Runtime Files

Development Files

The following files may be used to develop programs using Sockets/V, but must not, under the terms of your license, be distributed with programs you develop with Sockets/V.

SOCKETSV.SML
Source code for Sockets/V

The following files are included with Sockets/V to aid you in developing your programs. You may incorporate portions of these sample programs in your programs, but you may not distribute the sample programs themselves.

PSSWRDDL.CLS
Password dialog for BBClient
CNNCTDLG.CLS
Connect dialog for BBClient
POSTDILG.CLS
Post dialog for BBClient
DGRMSCKT.CLS
Datagram socket test application
MSGSCKTT.CLS
Message socket test application
OBJSCKTT.CLS
Object socket test application
BBSERVER.CLS
BBServer network bulletin board sample application
BBCLIENT.CLS
BBClient netwrok bulletin board sample application
SVTABLE.CLS
SVTable class: 2-dimensional table class used by StateMachine
STATMCHN.CLS
StateMachine class: used to dispatch events in FTPClient
FTPCLINT.CLS
FTPClient class: interface to FTP user functions
FTPAPP.CLS
FTPApp sample FTP user program
SENDMAIL.CLS
SMTP user sample program

Runtime Files

The following files are required to both develop and execute programs developed with Sockets/V. These files may be distributed with programs you develop with Sockets/V.

SOCKETSV.SLL


Ordering Information

Sockets/V includes all source code. See the text file ORDER.FRM for ordering details.

There are no run-time fees for applications developed with Sockets/V. The run-time SLL's may be distributed freely with your applications.

P1 Systems Incorporated provides 90 days of free technical support via voicemail, FAX, BBS, Internet mail and CompuServe mail. Guarantee: Sockets/V may be returned for a full refund for any reason within 90 days if you are not fully satisfied. VISA, MasterCard, and corporate purchase orders accepted.

P1 Systems Networking Products for Smalltalk:

Sockets/V for Visual Smalltalk 3.0 Win32
Sockets/V for Smalltalk/V 2.0 Win32
Sockets/V for Smalltalk/V for Windows
PARTSNet for PARTS Win32
PARTSNet for Visual Smalltalk Win32

Network parts including NetInfo, NetIF, and NetEvent. Allows network programming without coding! NetInfo part for general network information, NetIF part for sending/receiving messages, NetEvent part for triggering events in remote applications (allows emulating a remote part's interface). Network parts allow passing objects such as sets, dictionaries, etc. between applications in addition to Strings and ByteArrays.

Sockets/V is available from

P1 Systems Incorporated PMB 320, 1315 Madison Street, Seattle, WA 98104-3512 VoiceMail: +1 206 374-2475 FAX: +1 206 374-2475 Internet: info@p1.com


P1 Systems Incorporated License Agreement

This is a legal agreement between you, the end user, and P1 Systems Incorporated (P1). Having installed the software on your computer, you have agreed to be bound by the terms of this Agreement. If you do not agree to the terms of this Agreement, do not install the software and promptly return the software and the accompanying items (including written materials and other containers) to the place you obtained them for a full refund.

Grant of License. P1 grants you (i) a non-exclusive, nontransferrable license to use one copy of the enclosed P1 software program (the "Software") on a single computer for your personal use on the understanding that a single person uses each copy, and (ii) a non-exclusive, nontransferable license to use one copy of the related written materials enclosed ("Documentation"). Purchasers of the Software are therefore licensed to use it themselves on one computer at a time, and to make a single backup copy for their own use. No other license is given. In particular, the Software may not be installed on a computer network for use by more than one person. The Software may not be rented or leased to others, and the conditions of this sale apply to the purchaser in any resale.

Limited Warranty. P1 Systems Incorporated (P1) warrants the enclosed diskettes and documentation to be free of defects in materials and workmanship for 90 days from the date of purchase. Defective products returned to P1 during this period will be replaced without charge and are subject to the original warranty. Furnishing such replacements is P1's only obligation under the terms of this sale.

Although P1 has made all efforts to ensure that the Software performs as stated in the Documentation, no representation is made and no guarantee is given regarding the Software's merchantability, performance, or its fitness for any purpose. It is sold as-is and purchasers assume all risks regarding its suitability for their purposes.

P1 is not liable for any loss of profit or other commercial damages, including but not limited to, special, incidental, consequential or other damages, including loss of data, resulting from the use of the Software.

This is the sole and exclusive statement of P1's warranty, and no one is authorized to alter it in any way either orally or in writing.

Copyright. The Software and Documentation are owned by P1 and are protected by US and International copyright laws. You may not copy the Software or Documentation, except that you may make one copy of the Software solely for backup or archival purposes. No part of the Documentation may be reproduced or transmitted in any form or by any means, electronic or mechanical, including but not limited to photocopying, without prior written permission from P1. Copying or duplicating the Documentation or any part thereof is a violation of the law.

Runtime Rights and Limitations. You have a royalty-free right to reproduce and distribute executable files created by using the Software that include the runtime environment portions of the Software (the "Runtime Files") which are identified in the Documentation as being required to execute programs. The executable you distribute must not contain any part of the development environment portions of the Software (the "Development Files") which are identified in the Documentation as being required to develop programs using the Software. You may not distribute any portion of the source code of the Software. You may not distribute executable files whose functionality is similar to that of the Software.

Governing Law. This Agreement shall be governed and construed under the laws of the State of California and subject to the exclusive jurisdiction of the courts therein.

Entire Agreement. You agree that this Agreement expresses the entire understanding between you and P1 and superscedes all other communications, oral or written, relating to the Software.