In the previous articles in this series, a UWP app was developed as an array of XAML buttons that acts as the UI for an app running on a remote embedded or IoT device. Once connected the remote app sends a configuration for the UI as a Json string. Connectivity between the UWP and remote apps over Bluetooth and USB Serial has been covered. In this article connectivity over network sockets is covered. The article includes 101 on TCPIP Network Sockets for UWP and Arduino.

 

Links

Index of Articles

Next: Bluetooth Connectivity-Connectivity-1/4

Prev: SurfPad States

Code Repository: (Github) djaus2/SurfPad

 

TCPIP Network Sockets implement the client server software pattern. The server runs a service listening on a TCPIP port for connection from clients. Once a connection occurs, it initiates message sends as well as sends messages upon request from the client. The client needs to know the IP Address of the server (or its URL if DNS is available) as well as the TCPIP port that the server is using.. It attempts to connect to the service and if successful, will send messages to and receive messages from, the server.

 

Outline of TCPIP Socket Client-Server Software

UWP Network Socket Server code has two main parts. The first part starts the service. The second part is an event handler that fires whenever a connection to the server by the client is successful. This event handler needs to be kept alive throughout the connection as an event does not fire for each communication to and from the server. The socket entities, InputSream and OutputStream, created by the event handler upon connection must remain alive until the connection is broken. The event handler will typically create a reader and a writer thread that await data reception from the client on the InputStream and data to be sent to the client on the OutputStream respectively. Alternatively, the server can alternate between sends as required and poll for receives in a loop in a single thread. Disconnection is an issue with UWP; discussion later.

 

With UWP Network Socket Client code you create a StreamSocket then use it to connect to the service specifying the the server’s remote IP Address and the TCPIP Port used. To send data you create an OutputStream from the socket to which you write data, that gets sent. To receive data from the server you create an InputStream from the socket and await messages on it from the server. Typically the OutputStream and InputStreams are actioned as separate threads. You may though alternate sending and receiving and use polling in a single thread.  Whatever method used, the OutputStream and InputStream objects have to be kept alive throughout the client’s connection to the service and are closed upon disconnection.

 

The roundedBox UI UWP app runs as a Network Socket Client with a Listener thread which launches a Send thread as required by reception processing. This app is part of the SurfPad solution on GitHub,

 

The code for an Arduino device is always in two parts: A Setup() function and a Loop() function. Setup runs once after device startup (or reset) and Loop as its name suggested is called repeatedly after a call completes. When used as a Network Socket Server, the Ethernet followed by its Ethernet Service is started in the Setup(). The IP Address may be specified when starting the Ethernet for the device, or obtained automatically from DNS. The TCPIP Port of the service is specified when the service is started. In the Loop function you poll for connection and if connected you then poll for received messages. You can also optionally send messages, typically in response to received messages.

 

An Arduino device can be a Network Socket Client using the EthernetClient class. Whereas the EthernetServer requires starting, the client actions an attempt to connect which requires the server’s IP Address and Port. if successful the client can send and poll for messages to/from the server. The client can check if its still connected (eg server has shutdown or closed the connection).

 

When used as the remote app with the SurfPad roundedBox app, the Arduino device acts as the network socket service as it will deliver senor data etc. upon requests initiated by the user interacting with the UI. Similarly, when used as the remote app , an IoT-Core device acts as the socket service .  The Arduino socket server code is in the ClientSvrSockets.ino file in the ArduinoEchoSketch subproject in the SurfPad solution on GitHub.  The UWP socket server code is in the SurPadIoT subproject in that solution.

 

Client Server Arduino and UWP Code

The code as presented is simplified from the solution projects. For example most try-catches have been removed. Examine the code in the projects for more detail.

Ah.. the Code widget doesn’t work. Will reposted later with a fix.

 

byte mac = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 0, 137); IPAddress gateway(192, 168, 0, 1); IPAddress subnet(255, 255, 0, 0); // Needs to match the client EthernetServer server(PORT); boolean alreadyConnected = false; // whether or not the client was connected previously void setup() { // initialize the ethernet device Ethernet.begin(mac, ip, gateway, subnet); // start listening for clients server.begin(); }

Arduino Socket Server setup() code

 

void loop() { // wait for a new client: EthernetClient client = server.available(); // when the client sends the first byte, say hello: if (client) { thisByte=-1; if (client.available() > 0) { // read the bytes incoming from the client: thisByte = client.read(); } if (thisByte != -1) { switch (thisByte) { case '0': client.write('1'); mode = ACK1; break; case '2': client.write('3'); mode = ACK2; break; .... .... } } }

Arduino Socket Server loop() code

 

private async Task StartServer() { streamSocketListener = new Windows.Networking.Sockets.StreamSocketListener(); // The ConnectionReceived event is raised when connections are received. streamSocketListener.ConnectionReceived += this.StreamSocketListener_ConnectionReceived; // Start listening for incoming TCP connections on the specified port. You can specify any port that's not currently in use. await streamSocketListener.BindServiceNameAsync(SocketServerTerminalPage.PortNumber); _Mode = Mode.JustConnected; }

UWP code to initiate a Socket Server

private async void StreamSocketListener_ConnectionReceived(Windows.Networking.Sockets.StreamSocketListener sender, Windows.Networking.Sockets.StreamSocketListenerConnectionReceivedEventArgs args) { string response; char chars = new char; int responseLength; try { using (var streamReader = new StreamReader(args.Socket.InputStream.AsStreamForRead())) { using (Stream outputStream = args.Socket.OutputStream.AsStreamForWrite()) { using (var streamWriter = new StreamWriter(outputStream)) { if (_Mode == Mode.JustConnected) { //Wait until a string is written with end of line by the Client response = await streamReader.ReadLineAsync(); //Send a response to the Client await streamWriter.WriteLineAsync(response); await streamWriter.FlushAsync();//Note you have to Flush after a write .... ..... bool listening = true; _Mode = Mode.Listening; while (listening) { //Get a char from the UI. The UI sends a coded char for each button responseLength = await streamReader.ReadAsync(chars, 0, 1); if (listening) switch (chars) { case '^': //Client can send ^ to disconnect listening = false; break; default: //Do app stuff here. For now just echo chars sent await streamWriter.WriteAsync(chars); await streamWriter.FlushAsync(); break; } } } } } } } catch (Exception ex) { } }

UWP Server Listener code

//These need to be kept alive throught the connection: private Windows.Networking.Sockets.StreamSocket streamSocket = null; private Stream outputStream = null; private StreamWriter streamWriter = null; private Stream inputStream=null; private StreamReader streamReader = null; private async Task StartSocketClient() { try { string port = tbPort.Text; string svr = tbSvrName.Text; // Create the StreamSocket and establish a connection to the echo server. streamSocket = new Windows.Networking.Sockets.StreamSocket(); var hostName = new Windows.Networking.HostName(host); await streamSocket.ConnectAsync(hostName, port); outputStream = streamSocket.OutputStream.AsStreamForWrite(); streamWriter = new StreamWriter(outputStream); inputStream = streamSocket.InputStream.AsStreamForRead(); streamReader = new StreamReader(inputStream); } catch (Exception ex) { } }

The UWP Socket Client C# code

 

public async Task SendCh(char ch) { char chars = new char; chars = ch; try { await streamWriter.WriteAsync(ch); await streamWriter.FlushAsync(); } catch (Exception ex) { }

UWP C# Client code to send a character

 

public async Task<char> ReceiveCh() { char ch = ' '; char chars = new char; try { int responseLength = await streamReader.ReadAsync(chars, 0, 1); if (responseLength == 1) ch = chars; } catch (Exception ex) { } return ch; }

UWP Client C# code to receive a character.

 

 

To receive a line terminated string:

string ret = await streamReader.ReadLineAsync();

 

private async void Listen() { try { while (true) { await ReadAsync(); } } catch (Exception ex) { } } public async Task ReadAsync() { char chars = new char; int responseLength = await streamReader.ReadAsync(chars,0,1024); byte bytes = Encoding.Unicode.GetBytes(chars); //Next line custs byte array down to received bytes only. Requires using Linq; bytes = bytes = bytes.Skip(0).Take(responseLength).ToArray(); string recvdtxt = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length); //Send received msg back to UI await MainPage.MP.UpdateTextAsync(recvdtxt); }
The Client Listener code (Shows how to receive an array of bytes sent as an array of characters).

jj