Cross-platform C SDK logo

Cross-platform C SDK

Sockets

❮ Back
Next ❯
This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.

The sockets establish a communication channel between two remote processes through the Internet.


Functions

Socket*bsocket_connect (...)
Socket*bsocket_server (...)
Socket*bsocket_accept (...)
voidbsocket_close (...)
voidbsocket_local_ip (...)
voidbsocket_remote_ip (...)
voidbsocket_read_timeout (...)
voidbsocket_write_timeout (...)
bool_tbsocket_read (...)
bool_tbsocket_write (...)
uint32_tbsocket_url_ip (...)
uint32_tbsocket_str_ip (...)
const char_t*bsocket_host_name (...)
const char_t*bsocket_host_name_ip (...)
const char_t*bsocket_ip_str (...)
voidbsocket_hton2 (...)
voidbsocket_hton4 (...)
voidbsocket_hton8 (...)
voidbsocket_ntoh2 (...)
voidbsocket_ntoh4 (...)
voidbsocket_ntoh8 (...)

We can define a socket as a communication channel between two processes that are running on different machines. They use as a base the family of TCP/IP protocols that govern Internet communication from the first prototypes of the big network back in 1969. For its part, the IP protocol (Internet Protocol) is responsible for sending small data packets between two remote computers through the network. As there are packets that can be lost or take different paths when crossing the Internet nodes, TCP (Transmission Control Protocol) will be in charge of sorting them sequentially and re-ordering those that have been lost. Another important aspect that TCP adds is the concept of a port, which allows the same machine to have multiple connections open at the same time. The conjunction of TCP/IP provides the process of a reliable bidirectional communication channel (full-duplex) with the remote process and is the basis of the client/server model (Figure 1).

  • Use bsocket_connect in the client process to create a communication channel with a remote server.
  • Use bsocket_server in the server process to listen for client requests.
  • Use bsocket_accept to accept a client's request and start communication.
  • Use bsocket_read to read data from a socket.
  • Use bsocket_write to write data to a socket.
  • Schema showing two remote processes connected through a socket through the Internet.
    Figure 1: TCP/IP sockets allow two processes to be connected through the Internet.

Sockets are the lowest-level communication primitive accessible by applications. They are extremely fast but, in general, their functions are blocking, that is, they will stop the process until the other party responds.

  • bsocket_connect will stop the client process until the server responds or the timeout expires.
  • bsocket_accept it will stop the server process until a request from a client arrives or the timeout is fulfilled.
  • bsocket_read will stop the process until the other interlocutor writes data to the channel or the timeout is fulfilled.
  • bsocket_write will stop the process until the other peer reads data from the channel and frees the intermediate buffer or the timeout is fulfilled.

Apart from these indications, working with sockets is very similar to working with files on disk. The TCP/IP implementation is complicated and is part of the operating system, so the establishment of the connection has been simplified through the system calls seen above. Since a socket only allows sending and receiving bytes, both partners need to define a protocol that indicates the order, sequence and type of data to be shared in such a way that communication is satisfactory and free of deadlocks. Some of the most used protocols on the Internet are: HTTP, SMTP, FTP, SSH, etc.


1. Client/Server example

As an example we are going to see how two processes exchange information through sockets. The protocol is extremely simple. After connection, the client (Listing 2) will send a series of numerical values ​​to the server (Listing 1) and it will respond by resending the same value. When the client sends the value UINT32_MAX the communication will end.

Listing 1: Simple socket-based server.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
uint32_t client_id = 0;
Socket *server_sock = bsocket_server(3444, 32, NULL);

if (server_sock == NULL)
    return;

for(;;)
{
    Socket *income_sock = NULL;
    uint32_t ip0, ip1;
    uint16_t p0, p1;

    bstd_printf("Waiting for a new client\n");

    income_sock = bsocket_accept(server_sock, 0, NULL);
    if (income_sock == NULL)
        continue;

    bstd_printf("Client %d arrives\n", client_id);
    bsocket_local_ip(income_sock, &ip0, &p0);
    bsocket_remote_ip(income_sock, &ip1, &p1);
    bstd_printf("Local IP: %s:%d\n", bsocket_ip_str(ip0), p0);
    bstd_printf("Remote IP: %s:%d\n", bsocket_ip_str(ip1), p1);

    for (;;)
    {
        byte_t data[4];
        uint32_t rsize;
        if (bsocket_read(income_sock, data, sizeof(data), &rsize, NULL) == TRUE)
        {
            uint32_t i;
            bsocket_ntoh4((byte_t*)&i, data);
            if (i != UINT32_MAX)
            {
                bstd_printf("Readed %d from client\n", i);
                bsocket_hton4(data, (byte_t*)&i);
                if (bsocket_write(income_sock, data, sizeof(data), NULL, NULL) == TRUE)
                {
                    bstd_printf("Sending %d to client\n", i);
                }
                else
                {
                    bstd_printf("Error writting to client\n");
                    break;
                }
            }
            else
            {
                bstd_printf("Client %d say bye!\n", client_id);
                break;
            }
        }
        else
        {
            bstd_printf("Error reading from client\n");
            break;
        }
    }

    bstd_printf("\n\n");
    bsocket_close(&income_sock);
    client_id += 1;
}

bsocket_close(&server_sock);
Listing 2: Client process.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
Socket *sock = NULL;
serror_t error;
uint32_t i = 0;
byte_t data[4];

sock = bsocket_connect(bsocket_str_ip("192.168.1.21"), 3444, 5000, &error);

if (sock == NULL)
{
    bstd_printf("Connection error\n");
    return;
}

bsocket_read_timeout(sock, 2000);
bsocket_write_timeout(sock, 5000);

while (i < kPING_COUNTER)
{
    bsocket_hton4(data, (const byte_t*)&i);
    if (bsocket_write(sock, data, sizeof(data), NULL, NULL) == TRUE)
    {
        bstd_printf("Sending %d to server\n", i);
    }
    else
    {
        bstd_printf("Error writting in socket\n");
        break;
    }

    if (bsocket_read(sock, data, sizeof(data), NULL, NULL) == TRUE)
    {
        uint32_t j;
        bsocket_ntoh4((byte_t*)&j, data);
        bstd_printf("Readed %d from server\n", j);
        if (j != i)
        {
            bstd_printf("Error data corruption\n");
            break;
        }

        i += 1;
    }
    else
    {
        bstd_printf("Error reading in socket\n");
        break;
    }
}

if (i == kPING_COUNTER)
{
    i = UINT32_MAX;
    bsocket_hton4(data, (const byte_t*)&i);
    if (bsocket_write(sock, data, sizeof(data), NULL, NULL) == TRUE)
    {
        bstd_printf("Sending FINISH to server\n");
    }
    else
    {
        bstd_printf("Error writting in socket\n");
    }
}

bsocket_close(&sock);

bsocket_connect ()

Create a client socket and try to establish a connection to a remote server.

Socket*
bsocket_connect(const uint32_t ip,
                const uint16_t port,
                const uint32_t timeout_ms,
                serror_t *error);
ip

The 32-bit IPv4 address of the remote host. bsocket_str_ip.

port

The connection port.

timeout_ms

Maximum number of milliseconds to wait to establish connection. If it is 0 it will wait indefinitely.

error

Error code if the function fails. Can be NULL.

Return

Socket handle, or NULL if the function fails.

Remarks

The process will be blocked until a response is obtained from the server or the timeout is fulfilled. See Client/Server example.


bsocket_server ()

Create a server socket.

Socket*
bsocket_server(const uint16_t port,
               const uint32_t max_connect,
               serror_t *error);
port

The port where the server will "listen".

max_connect

The maximum number of connections can queue.

error

Error code if the function fails. It can be NULL.

Return

Socket handle, or NULL if the function fails.

Remarks

Client requests will be stored in a queue until a call to bsocket_accept is received. See Client/Server example.


bsocket_accept ()

Accepts a connection to the server created with bsocket_server and starts the conversation with the client.

Socket*
bsocket_accept(Socket *socket,
               const uint32_t timeout_ms,
               serror_t *error);
socket

Handler returned by bsocket_server.

timeout_ms

Maximum number of milliseconds to wait to receive the request. If it is 0 it will wait indefinitely.

error

Error code if the function fails. It can be NULL.

Return

Socket handle, or NULL if the function fails.

Remarks

The process will be blocked until a request is obtained from a client or the timeout is fulfilled. See Client/Server example.


bsocket_close ()

Close a previously created socket with bsocket_connect, bsocket_server or bsocket_accept.

void
bsocket_close(Socket **socket);
socket

The socket handler. It will be set to NULL after closing.


bsocket_local_ip ()

Get the local ip address and port associated with the socket.

void
bsocket_local_ip(Socket *socket,
                 uint32_t *ip,
                 uint16_t *port);
socket

Socket handle.

ip

Local IP address.

port

Local IP port.


bsocket_remote_ip ()

Get the IP address and the remote port associated with the other interlocutor of the connection.

void
bsocket_remote_ip(Socket *socket,
                  uint32_t *ip,
                  uint16_t *port);
socket

Socket handle.

ip

Remote IP address.

port

Remote IP port.


bsocket_read_timeout ()

Sets the maximum time to wait for the function bsocket_read.

void
bsocket_read_timeout(Socket *socket,
                     const uint32_t timeout_ms);
socket

Socket handle.

timeout_ms

Maximum number of milliseconds to wait for the caller to write data to the channel. If it is 0 it will wait indefinitely.


bsocket_write_timeout ()

Sets the maximum time to wait for the function bsocket_write.

void
bsocket_write_timeout(Socket *socket,
                      const uint32_t timeout_ms);
socket

Socket handle.

timeout_ms

Maximum number of milliseconds that will wait until the caller reads the data and unblocked on the channel. If it is 0 it will wait indefinitely.


bsocket_read ()

Read data from the socket.

bool_t
bsocket_read(Socket *socket,
             byte_t *data,
             const uint32_t size,
             uint32_t *rsize,
             serror_t *error);
socket

Socket handle.

data

Buffer where the read data will be written.

size

The number of maximum bytes to read (buffer size).

rsize

Receive the number of bytes actually read. Can be NULL.

error

Error code if the function fails. Can be NULL.

Return

TRUE if data has been read. FALSE if any error has occurred.

Remarks

The process will be blocked until the interlocutor writes data to the channel or the timeout expires. See bsocket_read_timeout.


bsocket_write ()

Write data in the socket.

bool_t
bsocket_write(Socket *socket,
              const byte_t *data,
              const uint32_t size,
              uint32_t *wsize,
              serror_t *error);
socket

Socket handle.

data

Buffer that contains the data to write.

size

The number of bytes to write.

wsize

It receives the number of bytes actually written. Can be NULL.

error

Error code if the function fails. Can be NULL.

Return

TRUE if data has been written. FALSE if any error has occurred.

Remarks

The process will be blocked if the channel is full until the interlocutor reads the data and unblocks or expires the timeout. See bsocket_write_timeout.


bsocket_url_ip ()

Get the IPv4 address of a host from its url.

uint32_t
bsocket_url_ip(const char_t *url,
               serror_t *error);
1
2
3
4
5
6
uint32_t ip = bsocket_url_ip("www.google.com", NULL);
if (ip != 0)
{
    Socket *sock = bsocket_connect(ip, 80, NULL);
    ...
}
url

The host url, eg. www.google.com.

error

Error code if the function fails. Can be NULL.

Return

Value of the host's IPv4 address or 0 if there has been an error.


bsocket_str_ip ()

Get the IPv4 address from a string of type "192.168.1.1".

uint32_t
bsocket_str_ip(const char_t *ip);
1
2
3
4
uint32_t ip = bsocket_str_ip("192.168.1.1");
Socket *sock = bsocket_connect(ip, 80, NULL);
    ...
}
ip

The string with the IP.

Return

Value of the IPv4 address in 32-bit binary format.


bsocket_host_name ()

Gets the name of the host.

const char_t*
bsocket_host_name(char_t *buffer,
                  const uint32_t size);
buffer

Buffer to store the name.

size

Size of buffer.

Return

Pointer to the string buffer.


bsocket_host_name_ip ()

Gets the host name from its IP.

const char_t*
bsocket_host_name_ip(uint32_t ip,
                     char_t *buffer,
                     const uint32_t size);
ip

Value of the IPv4 address in 32-bit binary format.

buffer

Buffer to store the name.

size

Size of buffer.

Return

Pointer to the string buffer.


bsocket_ip_str ()

Gets the IP address in text string format.

const char_t*
bsocket_ip_str(uint32_t ip,
               const char_t *ip);
ip

Value of the IPv4 address in 32-bit binary format.

ip

The string with the IP.

Return

String of type "192.168.1.1".

Remarks

The string is returned in an internal buffer that will be overwritten on the next call. Make a copy of the string if we need it to be persistent.


bsocket_hton2 ()

Change the "endianness" of a 16bit value prior to being sent through the socket Host-to-Network.

void
bsocket_hton2(byte_t *dest,
              const byte_t *src);
1
2
3
4
uint16_t value = 45321;
byte_t dest[2];
bsocket_hton2(dest, (const byte_t*)&value);
bsocket_write(sock, dest, 2, NULL, NULL);
dest

Destination buffer (at least 2 bytes).

src

Buffer (variable).


bsocket_hton4 ()

Same as bsocket_hton2, for 4-byte values.

void
bsocket_hton4(byte_t *dest,
              const byte_t *src);
dest

Destination buffer (at least 4 bytes).

src

Buffer (variable).


bsocket_hton8 ()

Same as bsocket_hton2, for 8-byte values.

void
bsocket_hton8(byte_t *dest,
              const byte_t *src);
dest

Destination buffer (at least 8 bytes).

src

Buffer (variable).


bsocket_ntoh2 ()

Change the "endianness" of a 16bit value after being received by the socket Network-to-Host.

void
bsocket_ntoh2(byte_t *dest,
              const byte_t *src);
1
2
3
4
5
byte_t src[2];
uint16_t value;
bsocket_read(sock, src, 2, NULL, NULL);
bsocket_ntoh2((byte_t*)&value, src);
// value = 45321
dest

16-bit destination buffer (variable).

src

Buffer received by socket.


bsocket_ntoh4 ()

Same as bsocket_ntoh2, for 4-byte values.

void
bsocket_ntoh4(byte_t *dest,
              const byte_t *src);
dest

Buffer (variable) destination 32bits.

src

Buffer received by socket.


bsocket_ntoh8 ()

Same as bsocket_ntoh2, for 8-byte values.

void
bsocket_ntoh8(byte_t *dest,
              const byte_t *src);
dest

Buffer (variable) destination 64bits.

src

Buffer received by socket.

❮ Back
Next ❯