I'm new to sockets and just can't seem to get my app working. What I want to do is send a log file from the Netduino+2 back to my laptop. The approach I took was to prepend the file size to the byte array before sending. However, I never seem to receive exactly what I send. I realize this is a very common problem with folks who are new to sockets and I've searched high and low to find tips on how to avoid this problem. Maybe this is something unique to micro framework, but I kind of doubt it.
Here is my code. I've got a client app that runs on the N+2 and a console app running on my laptop. The data file I'm retrieving is attached below. This sort of works, but is not delivering the file consistently. Any help you can give me would be appreciated.
Client app running on N+2. When you press the onboard button, it sends the file.
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.IO;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
namespace SocketClient
{
public class Program
{
static string strDeviceIP = "";
static string strDeviceSubnet = "";
static string strDeviceGateway = "";
static string strDevicePort = "";
static string strControllerIP = "";
public static OutputPort opLED = new OutputPort(Pins.GPIO_PIN_D13, false);
InputPort button = new InputPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled);
public static void Main()
{
strDeviceIP = "192.168.2.102";
strDeviceSubnet = "255.255.255.0";
strDeviceGateway = "192.168.2.2";
strControllerIP = "192.168.2.222";
strDevicePort = "9999";
InterruptPort btn = new InterruptPort(Pins.ONBOARD_SW1, false,
Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
btn.OnInterrupt += new NativeEventHandler(ButtonPress);
while (true)
{
}
}
public static void ButtonPress(uint data1, uint data2, DateTime time)
{
opLED.Write(true);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
IPAddress hostAddress = IPAddress.Parse(strControllerIP);
IPEndPoint endpoint = new IPEndPoint(hostAddress, Int32.Parse(strDevicePort));
string fileName = "runlog2.txt";
// read the file into a byte array
byte[] data = File.ReadAllBytes(@"SD\" + fileName);
byte[] sizeinfo = new byte[4];
byte[] senddata = new byte[4 + data.Length];
// check to make sure it's not too big
if (data.Length > 850 * 1024)
{
Debug.Print("File too large");
}
// convert data.length into a byte array
sizeinfo[0] = (byte)data.Length;
sizeinfo[1] = (byte)(data.Length >> 8);
sizeinfo[2] = (byte)(data.Length >> 16);
sizeinfo[3] = (byte)(data.Length >> 24);
// prepend the size into the senddata array
sizeinfo.CopyTo(senddata, 0);
// copy read data into the senddata array
data.CopyTo(senddata, 4);
// send the data
socket.Connect(endpoint);
socket.Send(senddata);
socket.Close();
opLED.Write(false);
}
}
}
Here is my server side console app.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
namespace SocketConsole
{
class Program
{
static void Main(string[] args)
{
Thread thread1 = new Thread(new ThreadStart(Listener));
thread1.Start();
while (true)
{
}
}
public static void Listener()
{
try
{
Socket sktMain = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
sktMain.Bind(new IPEndPoint(IPAddress.Parse("192.168.2.222"), 9999));
sktMain.Listen(10);
var message = new ArrayList();
while (true)
{
// create the client socket
using (var client = sktMain.Accept())
{
//If connected,
if (SocketConnected(client, 100))
{
while (SocketConnected(client, 100))
{
byte[] sizeinfo = new byte[4];
//read the size of the message into sizeinfo
int totalread = 0, currentread = 0;
currentread = totalread = client.Receive(sizeinfo, 4,
SocketFlags.None);
while (totalread < sizeinfo.Length && currentread > 0)
{
currentread = client.Receive(sizeinfo, totalread,
sizeinfo.Length - totalread, SocketFlags.None);
totalread += currentread;
}
int messagesize = 0;
messagesize |= sizeinfo[0];
messagesize |= (((int)sizeinfo[1]) << 8);
messagesize |= (((int)sizeinfo[2]) << 16);
messagesize |= (((int)sizeinfo[3]) << 24);
byte[] data = new byte[messagesize];
totalread = 0;
currentread = totalread = client.Receive(data, 0, data.Length -
totalread, SocketFlags.None);
var received = Encoding.UTF8.GetChars(data);
int diff = data.Length - totalread;
while (totalread < messagesize && currentread > 0)
{
currentread = client.Receive(data, 0, data.Length - totalread,
SocketFlags.None);
totalread += currentread;
for (var i = 0; i < received.Length; i++)
message.Add(received[i]);
}
string fName = "runlog.txt";
if (File.Exists(fName)) File.Delete(fName);
BinaryWriter bWrite = new BinaryWriter(File.Open(fName,
FileMode.Create));
bWrite.Write(data);
bWrite.Close();
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
// socket polling
static bool SocketConnected(Socket s, int ms)
{
return !(s.Poll(ms, SelectMode.SelectRead) & (s.Available == 0));
}
}
}
If I look at the byte array data, after receiving all the data, every byte above 255 has a value of 0. It's as if it stops reading at 255. If I debug.print in the while loop filling "data", I get the following output:
client accepting data
client.Receive sizeinfo: currentread = 4, totalread = 4
total message size = 3296
client.Receive data: currentread = 252, totalread = 252
client.Receive data: currentread = 256 totalread = 508
client.Receive data: currentread = 256 totalread = 764
client.Receive data: currentread = 256 totalread = 1020
client.Receive data: currentread = 256 totalread = 1276
client.Receive data: currentread = 256 totalread = 1532
client.Receive data: currentread = 256 totalread = 1788
client.Receive data: currentread = 256 totalread = 2044
client.Receive data: currentread = 256 totalread = 2300
client.Receive data: currentread = 256 totalread = 2556
client.Receive data: currentread = 256 totalread = 2812
client.Receive data: currentread = 256 totalread = 3068
client.Receive data: currentread = 228 totalread = 3296
client.Receive data final: currentread = 228 totalread = 3296
So it is accepting 256 bytes each time, but they are all zero. Obviously, I don't understand what's going on:(
In the second while loop, and while calling the Receive method, you are using it this way:
currentread = client.Receive(data, 0, data.Length - totalread, SocketFlags.None);
The second parameter here denotes : "The location in buffer to store the received data.
"
This means that all your read data is actually overwriting all old data.
You should replace it with the following code:
currentread = client.Receive(data, totalread, data.Length - totalread, SocketFlags.None);
Because the totalread
varaible in your code always holds the total read bytes which also can be used to point to the new location for the new received data.