Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TCP

TCP is a connection: a stream of bytes in each direction between two programs. A TcpListener waits for connections and a TcpStream is one end of one. The example plays both sides on this machine.

#import "std/net"
#import "std/fs"

'' A server on a free port of this machine.
dim server as net.TcpListener
server.Bind( net.SocketAddress( net.Loopback( ), 0 ) )
var where = server.LocalAddress( ).Value( )

'' Connect, then accept: the system completes the connection on its own,
'' so one thread can be both client and server.
dim client as net.TcpStream
var ok = client.Connect( where, 2000 )
print "connected: "; ok.IsOk( )
dim conn as net.TcpStream
server.Accept( conn, 2000 )

'' A TcpStream is an fs.Stream, so the stream helpers work on it.
client.WriteUtf8( "ping" )
dim as string buf = space( 4 )
conn.ReadExact( cptr( ubyte ptr, strptr( buf ) ), 4 )
print "server read: "; buf
conn.WriteUtf8( "pong" )
client.ReadExact( cptr( ubyte ptr, strptr( buf ) ), 4 )
print "client read: "; buf

'' The peer's address is the client's own.
print "same ends: "; conn.PeerAddress( ).Value( ).Equals( client.LocalAddress( ).Value( ) )

'' With nothing to read, a timeout ends the wait.
client.SetReadTimeout( 100 )
dim as ubyte one( 0 to 0 )
var r = client.Read( @one( 0 ), 1 )
print "read: "; r.Failure( ).Message( ); ", code FS_TIMED_OUT: "; cbool( r.Failure( ).Code( ) = fs.FS_TIMED_OUT )

'' Closing the connection: the other side reads 0 bytes, the end of the data.
client.Close( )
print "after close: "; conn.Read( @one( 0 ), 1 ).Value( ); " bytes"

Output

connected: true
server read: ping
client read: pong
same ends: true
read: timed out, code FS_TIMED_OUT: true
after close:  0 bytes

Bind to port 0 lets the system choose a free port, and LocalAddress( ) says which. Connect takes a SocketAddress and a timeout in milliseconds; ConnectHost( "example.com", 80, 5000 ) looks a name up first and tries its addresses in turn. Accept waits for the next connection and opens the TcpStream it is given.

A TcpStream is a stream, the same kind as an open file, so WriteUtf8, WriteAll, ReadExact and ReadToEnd work on it. A plain Read returns whatever has arrived, which may be less than asked for: TCP delivers bytes, not the pieces they were written in. A read of 0 bytes means the other end has finished.

Reads and writes report an fs.FsError, as a file's do: FS_TIMED_OUT when a SetReadTimeout runs out, FS_CONNECTION_RESET when the other end drops the connection. Connecting, binding and accepting report a NetError, such as NET_CONNECTION_REFUSED when nothing listens on the port.

Activities

  1. Close server before connecting and print the Connect failure's Message( ).
  2. Send 100,000 bytes with WriteAll and read them on the other side with ReadExact. Then call client.SetWriteTimeout( 2000 ) and try 10,000,000. Why does the write give up when nobody reads yet?