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)



9 related questions:


36 comments:

25 Jul 2012

Thanks Emilio!!

27 Jul 2012

a question: it is not possible to connect the ethernetinterface to a interrupt? Now it is put in a endless loop.

And should it working if i make a timer 100ms and in the timer poll for incoming packets?

27 Jul 2012

Hi Bert,

bert van kokswijk wrote:

Now it is put in a endless loop.

The new networking stack is based on our operating system.

When a thread is waiting for a packet, it is put in the waiting state and, in the meantime, the scheduler will run another thread in the ready state, if there are no other threads in the ready state the scheduler can put the microcontroller to sleep, saving energy.

With this new networking stack you do not have to handle the Ethernet interrupts by yourself, you can use the standard Berkeley sockets API, or the C++ Socket API documented in this page.

Cheers, Emilio

27 Jul 2012

ok, this cleared it up for me

and btw, tnks for all your work!

08 Aug 2012

I am implementing a TFTP server (UDP Socket). I have the code working, including handling of some error conditions. Q: How can I 'poll' or be interrupted to see if a TFTP connection is being requested without being stuck in " n = server.receiveFrom(client, buffer, sizeof(buffer)); " forever?

thanks, ...kevin

08 Aug 2012

Hi Kevin,

Kevin Braun wrote:

I am implementing a TFTP server (UDP Socket). I have the code working, including handling of some error conditions.

Well done, it would be great to feature your library among our official protocol libraries. Let us know when it is ready.

Kevin Braun wrote:

Q: How can I 'poll' or be interrupted to see if a TFTP connection is being requested without being stuck in " n = server.receiveFrom(client, buffer, sizeof(buffer)); " forever?

You can set your server socket as non-blocking:

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

HTH, Emilio

08 Aug 2012

So, that's what "blocking" means... Thanks Emilio,

Can I change the timeout to "1" when looking for a connection, then change it to "3000" during a file transfer?

Also, will I find data from other tcp/ip services while looking at n = server.receiveFrom(client, buffer, sizeof(buffer)); " or only data from port 69 will be there ?

...kevin

08 Aug 2012

Kevin Braun wrote:

Can I change the timeout to "1" when looking for a connection, then change it to "3000" during a file transfer?

Yes, sure, you can change the blocking/non-blocking/timeout behaviour as many times as you want.

Kevin Braun wrote:

Also, will I find data from other tcp/ip services while looking at n = server.receiveFrom(client, buffer, sizeof(buffer)); " or only data from port 69 will be there ?

The Endpoint argument of receiveFrom will be filled with the address of the packet sender, mapping the behaviour of the Berkeley API: recvfrom.

You should receive only packets directed to the port you are bind to.

HTH, Emilio

09 Aug 2012

hello I started to implement this new ethernetinterface, but after the one of the latest releases i dont get my own ip back.. "IP Address is" that all what will come back after this code:

EthernetInterface eth; eth.init(); Use DHCP eth.connect(); printf("IP Address is %s\n", eth.getIPAddress());

ethernet is working... I'm sure it was working before some releases ago

Any suggestions?

09 Aug 2012

Hi Bert, we added a timeout to DHCP (eth.connect), but from your report and other tests we should increase the default value for the timeout. I'll update it ASAP.

Cheers, Emilio

» Show archived comment by bert1952
09 Aug 2012

ok thanks other question: off topic: i dont need the threads and i need max ram. So i putted the value to 2. Can i use also 0 thread?, and put the minimum blocksize to 0? last question: is there any work done to read in the RTC in the RTOS? Now i poll the RTC, but should be perfect to have a kind of interrupt. I never got the interrupt working on the "old" version of mbed.

09 Aug 2012

Hi Bert, I increased the DHCP default timeout from (3)s to (12)s: /users/mbed_official/code/EthernetInterface/rev/c9bb345dcc65. Of course, you can also pass your custom timeout value to eth.connect.

Cheers, Emilio

09 Aug 2012

Hi Bert, I increased the DHCP default timeout from (3)s to (12)s: /users/mbed_official/code/EthernetInterface/rev/c9bb345dcc65. Of course, you can also pass your custom timeout value to eth.connect.

Cheers, Emilio

working: you're great!!

» Show archived comment by emilmont
09 Aug 2012

Hi Bert,

bert van kokswijk wrote:

i dont need the threats and i need max ram. So i putted the value to 2. Can i use also 0 threat?

I guess you are talking about Threads and not "threats" (I do not need threats either ;-). The networking stack is based on the mbed-rtos and it does need a certain number of threads, I will document the number and their purpose. On the top of my head I remember two low level Ethernet RX and TX threads and one TCP thread. Of course, you cannot remove these thread without breaking the functionality of the networking stack.

bert van kokswijk wrote:

and put the minimum blocksize to 0?

I do not understand about which blocksize you are talking about.

bert van kokswijk wrote:

is there any work done to read in the RTC in the RTOS?

Perhaps, you could be interested in using the RTOSTimers. There is no specific RTC driver in the RTOS.

HTH, Emilio

» Show archived comment by bert1952
09 Aug 2012

sorry for the typo :-( ... and i was meaning the Words_stack_size now i putted it to 64 bytes and threads setted to 2

  1. ifndef OS_TIMERSTKSZ
  2. define OS_TIMERSTKSZ 64 WORDS_STACK_SIZE
  3. endif
» Show archived comment by emilmont
09 Aug 2012

bert van kokswijk wrote:

sorry for the typo :-(

Do not worry, English is not my mother tongue and you do have all my understanding.

bert van kokswijk wrote:

i was meaning the Words_stack_size now i putted it to 64 bytes and threats setted to 2

ifndef OS_TIMERSTKSZ define OS_TIMERSTKSZ 64 WORDS_STACK_SIZE endif

Yes, you can experiment with it, but it is risky, it can generate stack overflows late in the program execution when the stack reaches its maximum size.

We are working to provide diagnostic tools to better choose the stack sizes, but it will take a bit of time...

Cheers, Emilio

12 Aug 2012

Hello Got something weird: if connect from 1 device i got the correct ip endpoint adress. If i connect after that with a other device, i should get a different ip adress, however, the first remains... see terminal output below....

Wait for new connection... Connection from: 192.168.1.21 Connection from:192.168.1.21 Received:GET / HTTP/1.1 Host: 192.168.1.38:4200 User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:14.0) Gecko/20100101 Firefox/14.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: nl,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive

CloseSocket

Wait for new connection... Connection from: 192.168.1.21 Connection from:192.168.1.21 Received:GET /LampTil_aan.html HTTP/1.1 Host: 192.168.1.38:4200 Accept-Encoding: gzip Accept-Language: nl-NL, en-US Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 User-Agent: Mozilla/5.0 (Linux; U; Android 2.3.6; nl-nl; GT-I8150 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7

CloseSocket

Wait for new connection...

13 Aug 2012

solved by inserting reset_address() command after closing the socket

13 Aug 2012

Hi Bert,

bert van kokswijk wrote:

if connect from 1 device i got the correct ip endpoint adress. If i connect after that with a other device, i should get a different ip adress

Yes, I forgot to reset the TCPSocketConnection address when accepting a new connection: fixed.

Thanks for reporting it, Emilio

13 Aug 2012

Confirmed..... :-)

Posting new comments for this page has been disabled