class io.Socket

Overview

This class provides high-level asynchronous interface for accessing all kinds of sockets. More…

import "io_base.jncx"
import "io_Socket.jnc"

class Socket {
    // fields

    io.SocketEvents readonly volatile m_activeEvents;
    std.Error const* readonly volatile m_ioError;
    bool readonly m_isOpen;

    // properties

    io.SocketAddress const property m_address;
    io.SocketAddress const property m_peerAddress;
    uint_t autoget property m_readParallelism;
    size_t autoget property m_readBlockSize;
    size_t autoget property m_readBufferSize;
    size_t autoget property m_writeBufferSize;
    io.SocketOptions autoget property m_options;
    uintptr_t const property m_osHandle;

    // construction

    construct();
    destruct();

    // methods

    bool errorcode open(
        io.AddressFamily family,
        io.Protocol protocol
    );

    bool errorcode open(
        io.Protocol protocol,
        io.SocketAddress const* address
    );

    bool errorcode open(io.Protocol protocol);
    void close();
    bool errorcode connect(io.SocketAddress const* address);
    bool errorcode listen(size_t backlog = 0);

    io.Socket* errorcode accept(
        io.SocketAddress* address = null,
        bool isSuspended = false
    );

    void unsuspend();

    size_t errorcode read(
        void* p,
        size_t size
    );

    size_t errorcode write(
        void const* p,
        size_t size
    );

    size_t errorcode readDatagram(
        void* p,
        size_t size,
        io.SocketAddress* address
    );

    size_t errorcode writeDatagram(
        void const* p,
        size_t size,
        io.SocketAddress const* address
    );

    long errorcode wait(
        io.SocketEvents eventMask,
        void function* handler(io.SocketEvents triggeredEvents)
    );

    bool errorcode cancelWait(long handle);

    io.SocketEvents blockingWait(
        io.SocketEvents eventMask,
        uint_t timeout = -1
    );

    import io.Socket.SocketEvents async asyncWait(io.SocketEvents eventMask);

    // aliases

    alias dispose = close;
};

Detailed Documentation

This class provides high-level asynchronous interface for accessing all kinds of sockets.

Sockets represent endpoints of network communications. Sockets are subdivided into two large subclassess: datagram-oriented and connection-oriented. Furthermore, connection-riented sockets can operate in one of the two modes: client and server. And even though these interfaces don’t share that many commonalities, it so historically happened that they are usually blended into a single socket API.

Jancy follows this traditional approach.

Sample code(client connection-oriented TCP socket):

class MyDialog {
    // ...

    io.Socket m_socket;
    uint_t m_syncId;

    void connect(string_t addrString);
    void close();
    void waitSocketEvents();

    void onWriteButtonClicked();

    void onSocketEvent(
        uint_t syncId,
        io.SocketEvents triggeredEvents
    );
}

MyDialog.connect(string_t addrString) {
    io.SocketAddress sockAddr;
    sockAddr.parse(addrString);
    m_socket.open(io.Protocol.Tcp);
    m_socket.connect(sockAddr);
    waitSocketEvents();

catch:
    // handle the error...
}

MyDialog.close() {
    m_socket.close();
    m_syncId++; // events past this point will be discarded as 'late'
}

MyDialog.waitSocketEvent() {
    io.SocketEvents eventMask =
        io.SocketEvents.IoError |
        io.SocketEvents.IncomingData;

    if (!(m_socket.m_activeEvents & io.SocketEvents.TcpConnected))
        eventMask |= io.SocketEvents.TcpConnected;

    m_socket.wait(eventMask, onSocketEvent ~(++m_syncId) @
        g_mainThreadScheduler);
}

MyDialog.onWriteButtonClicked() {
    static char data[] = "a quick brown fox jumps over the lazy dog";
    m_socket.write(data, sizeof(data));
}

MyDialog.onSocketEvent(
    uint_t syncId,
    io.SocketEvents triggeredEvents
) {
    if (syncId != m_syncId) // late event
        return;

    if (triggeredEvents & io.SocketEvents.IoError) {
        string_t errorString = m_socket.m_ioError.m_description;
        // ...
    }

    if (triggeredEvents & io.SocketEvents.TcpConnected) {
        // TCP connection established
    }

    if (triggeredEvents & io.SocketEvents.IncomingData) {
        char buffer[256];
        size_t size = m_socket.read(buffer, sizeof(buffer));
        // ...
    }

    waitSocketEvents(); // restart wait
}

See also:

io.SocketEvents, io.SocketAddress

Fields

bool readonly m_isOpen

Holds the open status for the socket, i.e. true if opened; false otherwise.

Properties

io.SocketAddress const property m_address

This property is used for getting the local address assigned to this socket. If the address has not been assigned yet, returns empty address.

io.SocketAddress const property m_peerAddress

This property is used for getting the remote address of the peer this socket is connected to. If the connection has not been established yet, returns empty address.

Methods

bool errorcode open(
    io.AddressFamily family,
    io.Protocol protocol
)

Opens a new unbound socket.

The function accepts three arguments. The first one, family, specifies the address family of the new socket(IP4 vs IP6). The second argument, protocol, specifies the protocol of the new socket (datagram-oriented UDP vs connection-oriented TCP). The third and final argument, flags can be used to specify additional open options.

Returns true on success. If a new socket could not be opened, IO error supplied by operating system is set and then the function returns false [1].

bool errorcode open(
    io.Protocol protocol,
    io.SocketAddress const* address
)

Opens a new socket and binds it to the specified local address.

The function accepts three arguments. The first one, protocol, specifies the protocol of the new socket(datagram-oriented UDP vs connection-oriented TCP). The second argument, address, specifies the local address to bind the new socket to. The third and final argument, flags can be used to specify additional open options.

Returns true on success. If a new socket could not be opened, IO error supplied by operating system is set and then the function returns false [1].

bool errorcode open(io.Protocol protocol)

Opens a new unbound socket.

The function is equivalent to the very first overload of open method with family argument set to io.AddressFamily.Ip4.

void close()

Closes a previously opened socket, does nothing if the file is not opened. This function always succeeds.

Sometimes it may be convenient to use disposable pattern to ensure timely invokation of close [2].

bool errorcode connect(io.SocketAddress const* address)

Initiates a connection request to address. This function is only valid for TCP sockets.

This method initiates a connection request and returns immediatly. After connection request completes, an event io.SocketEvents.TcpConnected (on success) or io.SocketEvents.IoError (on failure) gets fired.

Returns true on success. If a connection could not be established, IO error supplied by operating system is set and then the function returns false [1].

bool errorcode listen(size_t backlog = 0)

Places a server socket into listen state. This function is only valid for TCP sockets.

The only argument of the method, backlog, specifies the maximum length of the queue of pending client-side connections, i.e. connections which has not been accepted via accept method yet.

Returns true on success. If the socket could not be placed into listen state, IO error supplied by operating system is set and then the function returns false [1].

io.Socket* errorcode accept(
    io.SocketAddress* address = null,
    bool isSuspended = false
)

Accepts a client connection and returns a resulting io.Socket object to communicate with this particular client. To terminate a client connection, issue close method on the client file stream object.

If method fails, null value is returned [1].

void unsuspend()

Accepted sockets may initially be suspended (so that the user has a chance to configure reading options such as m_readBlockSize)

Call unsuspend to awaken the accepted socket after it has been configured.

size_t errorcode write(
    void const* p,
    size_t size
)

Attempts to send size bytes from the buffer pointed to by p over the connected socket.

Returns the actual amount of bytes written on success. If write operation is unsuccessful, IO error supplied by the operating system is set and then the function returns -1 [1].

If the return value shows less bytes than specified by size argument, you should suspend further transmission until the file stream is ready to accept more data. When this happens, WriteBufferReady event is fired and transmission could be resumed.

size_t errorcode readDatagram(
    void* p,
    size_t size,
    io.SocketAddress* address
)

Attempts to read up to size bytes from the socket into the buffer pointed to by p; stores the address of the sender into the address.

Returns the actual amount of bytes read on success. If read operation is unsuccessful, IO error supplied by the operating system is set and then the function returns -1 [1].

Normally you would call this function from within your event handler for IncomingData event.

size_t errorcode writeDatagram(
    void const* p,
    size_t size,
    io.SocketAddress const* address
)

Attempts to send size bytes from the buffer pointed to by p to the remote node pointed to by address.

Returns the actual amount of bytes written on success. If write operation is unsuccessful, IO error supplied by the operating system is set and then the function returns -1 [1].

If the return value shows less bytes than specified by size argument, you should suspend further transmission until the file stream is ready to accept more data. When this happens, WriteBufferReady event is fired and transmission could be resumed.

Aliases

alias dispose = close

Effectively makes io.Socket a disposable class [2].


Footnotes