Skip to main content
Engineering LibreTexts

3.2: TCP Client

  • Page ID
    43800
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    We call TCP client an application that initiates a TCP connection to exchange data with another application: the server. It is important to mention that the client and the server may be developed in different languages. The life-cycle of such a client in Pharo decomposes into 4 steps:

    1. Create a TCP socket.
    2. Connect the socket to a server.
    3. Exchange data with the server through the socket.
    4. Close the socket.

    Create a TCP Socket

    Pharo provides a single socket class. It has one creation method per socket type (TCP or UDP). To create a TCP socket, you need to evaluate the following expression:

    Socket newTCP
    

    Connect a TCP Socket to some Server

    To connect a TCP Socket to a server, you need to have the object representing the IP address of that server. This address is an instance of SocketAddress. A handy way to create it is to use NetNameResolver that provides IP style network name lookup and translation facilities.

    Script \(\PageIndex{1}\) provides two examples of socket address creation. The first one creates an address from a string describing the server name ('www.esug.org'), while the second does the creation from a string representing the IP address of the server ('127.0.0.1'). Note that to use the NetNameResolver you need to have your machine connected to a network with a DNS1, which is likely the case. The only exception is for retrieving the local host address, i.e. 127.0.0.1 which is the generic address to refer to the machine that runs your software (Pharo here).

    Script \(\PageIndex{1}\) (Pharo): Creating a Socket Address

    | esugAddress localAddress |
    esugAddress := NetNameResolver addressForName: 'www.esug.org'.
    localAddress := NetNameResolver addressForName: '127.0.0.1'.
    

    Now we can connect our TCP socket to the server as shown in Script \(\PageIndex{2}\). Message connectTo:port: attempts to connect the socket to the server using the server address and port provided as parameters. The server address refers to the address of the network interface (e.g. ethernet, wifi) used by the server. The port refers to the communication endpoint on the network interface. Each network interface has for each IP transport protocol (e.g. TCP, UDP) a collection of ports that are numbered from 0 to 65535. For a given protocol, a port number on an interface can only be used by a single process.

    Script \(\PageIndex{2}\) (Pharo): Connecting a TCP Socket to ESUG Server

    | clientSocket serverAddress |
    clientSocket := Socket newTCP.
    serverAddress := NetNameResolver addressForName: 'www.esug.org'.
    clientSocket
        connectTo: serverAddress port: 80;
        waitForConnectionFor: 10.
    clientSocket isConnected
        → true
    

    The connectTo:port: message returns immediately after issuing the request to connect the socket to the system (through a primitive call). Message waitForConnectionFor: 10 suspends the current process until the socket is connected to the server. It waits at most, 10 seconds as requested by the parameter. If the socket is not connected after 10 seconds, the ConnectionTimedOut exception is signaled. Otherwise, the execution can proceed by evaluating the expression clientSocket isConnected which answers true.

    Exchange Data with Server

    Once the connection is established, the client can exchange (send/receive) instances of ByteString with the server. Typically, the client sends some request to the server and then waits for a response. Web browsers act according to this schema. A web browser is a client that issues a request to some web server identified by the URL. Such a request is often the path to some resource on the server such as a html file or a picture. Then, the browser awaits the server response (e.g., html code, picture bytes).

    Script \(\PageIndex{3}\) (Pharo): Exchanging Data with some Server through a TCP Socket

    | clientSocket data |
    ... "create and connect the TCP clientSocket"
    clientSocket sendData: 'Hello server'.
    data := clientSocket receiveData.
    ... "Process data"
    

    Script \(\PageIndex{3}\) shows the protocol to send and receive data through a client socket. Here, we send the string 'Hello server!' to the server using the sendData: message. Next, we send the receiveData message to our client socket to read the answer. Note that reading the answer is blocking, meaning receiveData returns when a response has been read. Then, the contents of variable data is processed.

    Script \(\PageIndex{4}\) (Pharo): Bounding the Maximum Time for Data Reception

    |clientSocket data|
    ... "create and connect the TCP clientSocket"
    [data := clientSocket receiveDataTimeout: 5.
    ... "Process data"
        ] on: ConnectionTimedOut
        do: [ :timeOutException |
            self
                crLog: 'No data received!';
                crLog: 'Network connection is too slow or server is down.'] 
    

    Note that by using receiveData, the client waits until the server either sends no more data, or closes the connection. This means that the client may wait indefinitely. An alternative is to have the client signal a ConnectionTimedOut exception if client had waited for too long as shown in Script \(\PageIndex{4}\). We use message receiveDataTimeout: to ask the client socket to wait for 5 seconds. If data is received during this period of time, it is processed silently. But if no data is received during the 5 seconds, a ConnectionTimedOut is signaled. In the example we log a description of what happened.

    Close a Socket

    A TCP socket remains alive while devices at both ends are connected. A socket is closed by sending the message close to it. The socket remains connected until the other side closes it. This may last indefinitely when there is a network failure or when the other side is down. This is why sockets also accept the destroy message, which frees system resources required by the socket.

    In practice we use closeAndDestroy. It first attempts to close the socket by sending the close message. Then, if the socket is still connected after a duration of 20 seconds, the socket is destroyed. Note that there exist a variant closeAndDestroy: seconds which takes as a parameter the duration to wait before destroying the socket.

    Script \(\PageIndex{5}\) (Pharo): Interaction with a Web Site and Cleanup

    | clientSocket serverAddress httpQuery htmlText |
    httpQuery := 'GET / HTTP/1.1', String crlf,
        'Host: www.esug.org:80', String crlf,
        'Accept: text/html', String crlfcrlf.
    serverAddress := NetNameResolver addressForName: 'www.esug.org'.
    clientSocket := Socket newTCP.
    [ clientSocket
        connectTo: serverAddress port: 80;
        waitForConnectionFor: 10.
    clientSocket sendData: httpQuery.
    htmlText := clientSocket receiveDataTimeout: 5.
    htmlText crLog ] ensure: [clientSocket closeAndDestroy].
    

    To summarize all steps described so far, we use the example of getting a web page from a server in Script \(\PageIndex{5}\). First, we forge a HTTP2 query. The string corresponding to our query starts with the GET keyword, followed by a slash saying that we are requesting the root file of the server, as specified in the protocol HTTP/1.1. The second line includes the name of the web server and its port. The third and last line of the HTTP query refers to format accepted by our client. Since, we intend to display the result of our query on the Transcript, we state in the HTTP query (see line beginning with Accept:) that our client accepts texts with html format.

    Next, we retrieve the IP address of the www.esug.org server. Then, we create a TCP socket and connect it to the server. We use the IP address we got from the previous step and the default port for web servers: 80. The connection should be established in less than 10 seconds (waitForConnectionFor: 10), otherwise we get a ConnectionTimedOut exception.

    After sending the http query (clientSocket sendData: httpQuery), we read the received html text that we display from the socket. Note that the we ask the socket to wait at most 5 seconds for the answer from the server (clientSocket receiveDataTimeout: 5). On timeout, the socket answers an empty socket.

    Finally, we close the socket and free related resources (clientSocket closeAndDestroy). We ensure the cleanup by means of the ensure: message sent to the block that performs socket connection and data exchange with the web server.


    1. Domain Name System: basically a directory that maps device names to their IP address.
    2. HyperText Transfer Protocol used for web communications.

    This page titled 3.2: TCP Client is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.