We have a new product based on the G120 using the CobraII schematics.
I have an ENC28J60 module.
My current problem is this: Both in server and client mode, sockets are not reliable.
It works for a while, and eventually the module does not respond at all.
If in client mode, eventually it cannot connect anymore ( I have a thread that aborts an other client thread so it tries again after a timeout)
If in server mode, eventually the server just blocks at socket.Accept(), and does not accept new connections (Also, the browser does not receive the complete response, it is cut).
I have made a Gadgeteer project using the FezCobraII board and an ENC28J60 module.
Everything works … for a while. By a while I mean, it can take minutes to hours, and the bigger the G120 sends packets, the higher the probability it will bug out (message of over 4k bytes)
Here is my current test code. I have made a minimalist example that can easily reproduce the problem.
I you want to make it hang pretty fast, put 100 lines or more in the ServerThread() method.
Now in a browser, type the device IP adress and hit Ctrl-F5 every seconds.
Eventually, it bugs out for me.
If you want to bug it pretty fast, hold the Ctrl-F5 button to spam the G120. It makes exceptions (understandly), but eventually nothing works anymore.
A) Can anyone reproduce this problem to confirm it is not just our board.
B) Any workaround so this becomes reliable, not just a few connections, but with thousands of connections over several days?
using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;
using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GHINET = GHI.Premium.Net;
using Microsoft.SPOT.Hardware;
using GHI.Premium.Hardware;
using GHI.Premium.Net;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Gadgeteer.Modules.GHIElectronics;
namespace TestNetwork {
public partial class Program {
// This method is run when the mainboard is powered up or reset.
private Thread mainLoopThread;
private Thread serverThread;
private EthernetENC28J60 NetInterface;
void ProgramStarted() {
/*******************************************************************************************
Modules added in the Program.gadgeteer designer view are used by typing
their name followed by a period, e.g. button. or camera.
Many modules generate useful events. Type +=<tab><tab> to add a handler to an event, e.g.:
button.ButtonPressed +=<tab><tab>
If you want to do something periodically, use a GT.Timer and handle its Tick event, e.g.:
GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
timer.Tick +=<tab><tab>
timer.Start();
*******************************************************************************************/
// Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
Debug.Print("Program Started");
InitNetwork();
mainLoopThread = new Thread(MainLoop);
mainLoopThread.Priority = ThreadPriority.Normal;
mainLoopThread.Start();
}
private void InitNetwork() {
try {
//ethernet_ENC28 = new GHI.Premium.Net.EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Hardware.G120.Pin.P1_17, GHI.Hardware.G120.Pin.P2_21, GHI.Hardware.G120.Pin.P1_14, 4000);
NetInterface = ethernet_ENC28.Interface;
NetInterface.CableConnectivityChanged += new GHI.Premium.Net.EthernetENC28J60.CableConnectivityChangedEventHandler(Interface_CableConnectivityChanged);
NetInterface.NetworkAddressChanged += new GHI.Premium.Net.NetworkInterfaceExtension.NetworkAddressChangedEventHandler(Interface_NetworkAddressChanged);
if (!NetInterface.IsOpen)
NetInterface.Open();
GHI.Premium.Net.NetworkInterfaceExtension.AssignNetworkingStackTo(NetInterface);
byte[] macAddress = new byte[] {0x00, 0x1c, 0x14, 0xf9, 0xda, 0xe9};
for (int i=0;i<6;i++) {
if ( NetInterface.NetworkInterface.PhysicalAddress[i] != macAddress[i] ) {
NetInterface.NetworkInterface.PhysicalAddress = macAddress;
Debug.Print("Updating MAC Address, please reboot for changes to take effect.");
}
}
if (!NetInterface.NetworkInterface.IsDhcpEnabled)
NetInterface.NetworkInterface.EnableDhcp();
NetInterface.NetworkInterface.RenewDhcpLease();
} catch (Exception ex) {
Debug.Print("Error while initializing network" + ex.Message);
}
}
void Interface_NetworkAddressChanged(object sender, EventArgs e) {
Debug.Print("AddressChanged:" + NetInterface.NetworkInterface.IPAddress);
if (NetInterface.NetworkInterface.IPAddress != "0.0.0.0") {
StartServer();
}
}
void Interface_CableConnectivityChanged(object sender, EthernetENC28J60.CableConnectivityEventArgs e) {
Debug.Print("NetworkConnectChanged:" + e.IsConnected);
}
void StartServer() {
serverThread = new Thread(ServerThread);
serverThread.Priority = ThreadPriority.Normal;
serverThread.Start();
}
byte[] request = new byte[65536];
void ServerThread() {
// Bind the listening socket to the port
IPAddress hostIP = IPAddress.Parse(NetInterface.NetworkInterface.IPAddress);
IPEndPoint ep = new IPEndPoint(hostIP, 80);
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(ep);
// Start listening
listenSocket.Listen(1);
string msgStr = "Hello, browser! I think the time is " + DateTime.Now.ToString();
string responseStr = "";
for (int i = 0; i < 75; i++) {
responseStr = responseStr + "\r" + msgStr;
}
byte[] messageBytes = Encoding.UTF8.GetBytes(responseStr);
// Main thread loop
while (true) {
Socket socket = null;
try {
Debug.Print("listening...");
socket = listenSocket.Accept();
Debug.Print("Accepted a connection from " + socket.RemoteEndPoint.ToString());
} catch (Exception e) {
Debug.Print("Exception @ listenSocket.Accept():" + e.Message);
continue;
}
if (!ReadAll(socket)) {
continue;
}
try {
socket.Send(messageBytes);
} catch (Exception e) {
Debug.Print("Exception @ listenSocket.Accept():" + e.Message);
if (ReadAll(socket)) {
}
CloseSocket(socket);
continue;
}
CloseSocket(socket);
socket = null;
}
}
bool ReadAll(Socket socket) {
try {
while (socket.Poll(15000, SelectMode.SelectRead)) {
try {
int numBytes = socket.Receive(request);
if (numBytes == 0) {
break;
}
Debug.Print("Receiving bytes(" + numBytes + "):" + Encoding.UTF8.GetChars(request).ToString());
} catch (Exception e) {
Debug.Print("Exception @ newSock.Receive():" + e.Message);
CloseSocket(socket);
return false;
}
}
} catch (Exception e) {
Debug.Print("Exception @ newSock.Poll():" + e.Message);
CloseSocket(socket);
return false;
}
return true;
}
void CloseSocket(Socket socket) {
try {
socket.Close();
} catch (Exception e) {
Debug.Print("Exception @ newSock.Close():" + e.Message);
}
}
void MainLoop() {
Thread.Sleep(-1);
}
}
}