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
- Close
serverbefore connecting and print theConnectfailure'sMessage( ). - Send 100,000 bytes with
WriteAlland read them on the other side withReadExact. Then callclient.SetWriteTimeout( 2000 )and try 10,000,000. Why does the write give up when nobody reads yet?