Socket

The mbed C++ Socket API provides a simple and consistent way to communicate using bsd-like TCP and UDP sockets over various transports such as ethernet, wifi and mobile networks.

The Socket library is included as part of the networking libraries that implement the different transports, for example:

To use the sockets interfaces, include the appropriate transport library in your program. This page documents the Sockets API they will make available.

There are also various common protocols implemented on top of the sockets libraries to provide higher level APIs such as HTTP Clients; see:

TCP Socket

/media/uploads/emilmont/tcp.png

Import library

Public Member Functions

  TCPSocketServer ()
  Instantiate a TCP Server.
int  bind (int port)
  Bind a socket to a specific port.
int  listen (int backlog=1)
  Start listening for incoming connections.
int  accept ( TCPSocketConnection &connection)
  Accept a new connection.
void  set_blocking (bool blocking, unsigned int timeout=1500)
  Set blocking or non-blocking mode of the socket and a timeout on blocking socket operations.
int  set_option (int level, int optname, const void *optval, socklen_t optlen)
  Set socket options.
int  get_option (int level, int optname, void *optval, socklen_t *optlen)
  Get socket options.
int  close (bool shutdown=true)
  Close the socket.

Import library

Public Member Functions

  TCPSocketConnection ()
  TCP socket connection.
int  connect (const char *host, const int port)
  Connects this TCP socket to the server.
bool  is_connected (void)
  Check if the socket is connected.
int  send (char *data, int length)
  Send data to the remote host.
int  send_all (char *data, int length)
  Send all the data to the remote host.
int  receive (char *data, int length)
  Receive data from the remote host.
int  receive_all (char *data, int length)
  Receive all the data from the remote host.
void  set_blocking (bool blocking, unsigned int timeout=1500)
  Set blocking or non-blocking mode of the socket and a timeout on blocking socket operations.
int  set_option (int level, int optname, const void *optval, socklen_t optlen)
  Set socket options.
int  get_option (int level, int optname, void *optval, socklen_t *optlen)
  Get socket options.
int  close (bool shutdown=true)
  Close the socket.
void  reset_address (void)
  Reset the address of this endpoint.
int  set_address (const char *host, const int port)
  Set the address of this endpoint.
char *  get_address (void)
  Get the IP address of this endpoint.
int  get_port (void)
  Get the port of this endpoint.

Friends

class  TCPSocketServer

TCP Echo Server

Import program

#include "mbed.h"
#include "EthernetInterface.h"

#define ECHO_SERVER_PORT   7

int main (void) {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    printf("IP Address is %s\n", eth.getIPAddress());
    
    TCPSocketServer server;
    server.bind(ECHO_SERVER_PORT);
    server.listen();
    
    while (true) {
        printf("\nWait for new connection...\n");
        TCPSocketConnection client;
        server.accept(client);
        client.set_blocking(false, 1500); // Timeout after (1.5)s
        
        printf("Connection from: %s\n", client.get_address());
        char buffer[256];
        while (true) {
            int n = client.receive(buffer, sizeof(buffer));
            if (n <= 0) break;
            
            client.send_all(buffer, n);
            if (n <= 0) break;
        }
        
        client.close();
    }
}

You can test the above server running on your mbed, with the following Python script running on your PC:

import socket

ECHO_SERVER_ADDRESS = "10.2.131.195"
ECHO_PORT = 7

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((ECHO_SERVER_ADDRESS, ECHO_PORT))

s.sendall('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)

TCP Echo Client

Import program

#include "mbed.h"
#include "EthernetInterface.h"

const char* ECHO_SERVER_ADDRESS = "192.168.0.51";
const int ECHO_SERVER_PORT = 7;

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    printf("IP Address is %s\n", eth.getIPAddress());
    
    TCPSocketConnection socket;
    while (socket.connect(ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT) < 0) {
        printf("Unable to connect to (%s) on port (%d)\n", ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT);
        wait(1);
    }
    
    char hello[] = "Hello World\n";
    socket.send_all(hello, sizeof(hello) - 1);
    
    char buf[256];
    int n = socket.receive(buf, 256);
    buf[n] = '\0';
    printf("%s", buf);
    
    socket.close();
    eth.disconnect();
    
    while(true) {}
}

You can test the above Client running on your mbed, with the following Python script running on your PC:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 7))
s.listen(1)

while True:
    conn, addr = s.accept()
    print 'Connected by', addr
    while True:
        data = conn.recv(1024)
        if not data: break
        conn.sendall(data)
    conn.close()

UDP Socket

/media/uploads/emilmont/udp.png

Import library

Public Member Functions

  UDPSocket ()
  Instantiate an UDP Socket .
int  init (void)
  Init the UDP Client Socket without binding it to any specific port.
int  bind (int port)
  Bind a UDP Server Socket to a specific port.
int  join_multicast_group (const char *address)
  Join the multicast group at the given address.
int  set_broadcasting (bool broadcast=true)
  Set the socket in broadcasting mode.
int  sendTo ( Endpoint &remote, char *packet, int length)
  Send a packet to a remote endpoint.
int  receiveFrom ( Endpoint &remote, char *buffer, int length)
  Receive a packet from a remote endpoint.
void  set_blocking (bool blocking, unsigned int timeout=1500)
  Set blocking or non-blocking mode of the socket and a timeout on blocking socket operations.
int  set_option (int level, int optname, const void *optval, socklen_t optlen)
  Set socket options.
int  get_option (int level, int optname, void *optval, socklen_t *optlen)
  Get socket options.
int  close (bool shutdown=true)
  Close the socket.

Import library

Public Member Functions

  Endpoint (void)
  IP Endpoint (address, port)
void  reset_address (void)
  Reset the address of this endpoint.
int  set_address (const char *host, const int port)
  Set the address of this endpoint.
char *  get_address (void)
  Get the IP address of this endpoint.
int  get_port (void)
  Get the port of this endpoint.

Friends

class  UDPSocket

UDP Echo Server

Import program

#include "mbed.h"
#include "EthernetInterface.h"

#define ECHO_SERVER_PORT   7

int main (void) {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    printf("IP Address is %s\n", eth.getIPAddress());
    
    UDPSocket server;
    server.bind(ECHO_SERVER_PORT);
    
    Endpoint client;
    char buffer[256];
    while (true) {
        printf("\nWait for packet...\n");
        int n = server.receiveFrom(client, buffer, sizeof(buffer));
        
        printf("Received packet from: %s\n", client.get_address());
        server.sendTo(client, buffer, n);
    }
}

You can test the above Server running on your mbed, with the following Python script running on your PC:

import socket
 
ECHO_SERVER_ADDRESS = '10.2.131.195'
ECHO_PORT = 7

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.sendto("Hello World\n", (ECHO_SERVER_ADDRESS, ECHO_PORT))
response = sock.recv(256)
sock.close()

print response

UDP Echo Client

Import program

#include "mbed.h"
#include "EthernetInterface.h"

const char* ECHO_SERVER_ADDRESS = "10.2.200.94";
const int ECHO_SERVER_PORT = 7;

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    
    UDPSocket sock;
    sock.init();
    
    Endpoint echo_server;
    echo_server.set_address(ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT);
    
    char out_buffer[] = "Hello World\n";
    sock.sendTo(echo_server, out_buffer, sizeof(out_buffer));
    
    char in_buffer[256];
    int n = sock.receiveFrom(echo_server, in_buffer, sizeof(in_buffer));
    
    in_buffer[n] = '\0';
    printf("%s\n", in_buffer);
    
    sock.close();
    
    eth.disconnect();
    while(1) {}
}

You can test the above Client running on your mbed, with the following Python script running on your PC:

import socket
 
ECHO_PORT = 7

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', ECHO_PORT))

while True:
    data, address = sock.recvfrom(256)
    print "datagram from", address
    sock.sendto(data, address)

Blocking/Non-Blocking and Timeout

The standard Berkeley sockets functions (accept, send, receive, etc) are blocking, for this reason also our Socket methods are blocking by default.

If you want a non-blocking behaviour, waiting for a certain event only for a certain amount of time, you have to explicitly make a call to the set_blocking(bool blocking, unsigned int timeout) method:

// [Default] Blocking: wait the socket being (readable/writable) forever
socket.set_blocking(true)

// Non-Blocking: Return after a maximum of (timeout)ms.
socket.set_blocking(false, timeout)

Broadcasting

/media/uploads/emilmont/broadcast.png

Send Broadcast

Import program

#include "mbed.h"
#include "EthernetInterface.h"

const int BROADCAST_PORT = 58083;

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    
    UDPSocket sock;
    sock.init();
    sock.set_broadcasting();
    
    Endpoint broadcast;
    broadcast.set_address("255.255.255.255", BROADCAST_PORT);
    
    char out_buffer[] = "very important data";
    
    while (true) {
        printf("Broadcasting...\n");
        sock.sendTo(broadcast, out_buffer, sizeof(out_buffer));
        Thread::wait(1000);
    }
}

You can receive the messages sent by the above broadcaster running on your mbed, with the following Python script running on your PC:

import socket

BROADCAST_PORT = 58083

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('0.0.0.0', BROADCAST_PORT))

while True:
    print s.recvfrom(256)

Receive Broadcast

Import program

#include "mbed.h"
#include "EthernetInterface.h"

const int BROADCAST_PORT = 58083;

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    
    UDPSocket socket;
    socket.bind(BROADCAST_PORT);
    socket.set_broadcasting();
    
    Endpoint broadcaster;
    char buffer[256];
    while (true) {
        printf("\nWait for packet...\n");
        int n = socket.receiveFrom(broadcaster, buffer, sizeof(buffer));
        buffer[n] = '\0';
        printf("Packet from \"%s\": %s\n", broadcaster.get_address(), buffer);
    }
}

To broadcast messages to the above broadcast receiver running on your mbed you can use the following Python script running on your PC:

import socket
from time import sleep, time

BROADCAST_PORT = 58083

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

while True:
    print "Broadcasting..."
    data = 'Hello World: ' + repr(time()) + '\n'
    s.sendto(data, ('<broadcast>', BROADCAST_PORT))
    sleep(1)

Multicasting

/media/uploads/emilmont/multicast.png

Send Multicast

Import program

#include "mbed.h"
#include "EthernetInterface.h"

const char* MCAST_GRP = "224.1.1.1";
const int MCAST_PORT = 5007;

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    
    UDPSocket sock;
    sock.init();
    
    Endpoint multicast_group;
    multicast_group.set_address(MCAST_GRP, MCAST_PORT);
    
    char out_buffer[] = "very important data";
    while (true) {
        printf("Multicast to group: %s\n", MCAST_GRP);
        sock.sendTo(multicast_group, out_buffer, sizeof(out_buffer));
        Thread::wait(1000);
    }
}

You can receive the messages sent by the above multicaster running on your mbed, with the following Python script running on your PC:

import socket
import struct

MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)

sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

while True:
    print sock.recv(10240)

Receive Multicast

Import program

#include "mbed.h"
#include "EthernetInterface.h"

const char* MCAST_GRP = "224.1.1.1";
const int MCAST_PORT = 5007;

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    
    UDPSocket server;
    server.bind(MCAST_PORT);
    if (server.join_multicast_group(MCAST_GRP) != 0) {
        printf("Error joining the multicast group\n");
        while (true) {}
    }
    
    Endpoint client;
    char buffer[256];
    while (true) {
        printf("\nWait for packet...\n");
        int n = server.receiveFrom(client, buffer, sizeof(buffer));
        
        printf("Packet from \"%s\": %s\n", client.get_address(), buffer);
    }
}

Broken

The joining of multicast groups is currently broken in lwIP: bug #38165

To multicast messages to the above multicast receiver running on your mbed you can use the following Python script running on your PC:

import socket
from time import sleep, time

MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)

while True:
    print "Multicast to group: %s\n" % MCAST_GRP
    data = 'Hello World: ' + repr(time()) + '\n'
    sock.sendto(data, (MCAST_GRP, MCAST_PORT))
    sleep(1)

Discussion topics

Nothing here yet!

Questions