Bad news! It doesn’t work.
I have tested the example code with 20 auto refreshing tabs (every second) and the server was accepting over 10,000 connections. But after updating my other solution it doesn’t work. The server socket stops listening after 246 connections.
Now I have added the UDP broadcast sender from the other solution to check whether this socket causes the problems.
I also increased the response size and added a small sleep before sending the response.
Then I have deployed the application and opened 5 tabs which are refreshing each second. The server socket accepts 347 sockets (without an attached debugger) at the first test run before hanging at the Accept-method.
At the second try the code runs without any problems and accepted 4,000 connections (without an attached debugger).
This is very strange.
Another interesing thing is that the server sockets hangs (at my other solution) at the Accept-method after 100 connections if the code is running in release mode.
It is possible to upload my full solution so other users can try it with that code instead of the short version?
[title]The new version[/title]
namespace SocketTest
{
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using GHI.Networking;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
public class Program
{
private static EthernetENC28J60 _networkInterface;
private static Thread _workerThread;
private static Socket _serverSocket;
private static Socket _broadcastSocket;
private static IPEndPoint _broadcastAddress = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 40000);
private static readonly byte[] _receiveBuffer = new byte[1024];
private static int _clientConnections;
public static void Main()
{
Program.InitializeNetworkHardware();
Program._broadcastSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
Program._broadcastSocket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.Broadcast, true);
Program._serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Program._serverSocket.Bind(new IPEndPoint(IPAddress.Any, 80));
Program._serverSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
Program._serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Program._serverSocket.Listen(10);
Program._workerThread = new Thread(Program.Listen);
Program._workerThread.Start();
while (true)
{
Program.PrintDebugMessage("I am alive (at least " + Program._clientConnections + " client connections)!");
Thread.Sleep(5000);
}
}
private static void PrintDebugMessage(string message)
{
Debug.Print(message);
try
{
var buffer = Encoding.UTF8.GetBytes(message);
Program._broadcastSocket.SendTo(buffer, Program._broadcastAddress);
}
catch (Exception exception)
{
Debug.Print("Could not broadcast message '" + message + "'. " + exception.Message);
}
}
private static void InitializeNetworkHardware()
{
Debug.Print("Enabling ENC28 module.");
Program._networkInterface = new EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Pins.G120.P1_17, GHI.Pins.G120.P0_5, GHI.Pins.G120.P1_14);
Debug.Print("Opening ENC28 module.");
Program._networkInterface.Open();
Debug.Print("Configuring ENC28 module.");
Program._networkInterface.EnableStaticIP("192.168.1.15", "255.255.255.0", "192.168.1.1");
// Wait 10 seconds to ensure that the network hardware is fully initialized. The first UDP broadcasts will
// fail if we not wait!
Debug.Print("Waiting for ENC28 module.");
Thread.Sleep(10000);
Debug.Print("ENC28 module initialized.");
}
private static void HandleClient(Socket client)
{
if (client.Available == 0)
{
if (!client.Poll(5000 * 1000, SelectMode.SelectRead))
{
return;
}
if (client.Available == 0)
{
return;
}
}
if (client.Available > Program._receiveBuffer.Length)
{
Program.PrintDebugMessage("Received data exceeds the buffer size.");
return;
}
int requestLength = client.Receive(Program._receiveBuffer);
Program.PrintDebugMessage("Received a request.");
string message = Program.ParseAsciiString(Program._receiveBuffer, requestLength);
// TODO: Do something with the message...
Thread.Sleep(300);
if (!client.Poll(5000 * 1000, SelectMode.SelectWrite))
{
Program.PrintDebugMessage("Could not send data to the client.");
return;
}
string body = "{\"clients\":" + Program._clientConnections + ",\"data\":\"" + Program.GetData() + "\"}";
client.Send(Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\n"));
client.Send(Encoding.UTF8.GetBytes("Access-Control-Allow-Origin: *\r\n"));
client.Send(Encoding.UTF8.GetBytes("Connection: close\r\n"));
client.Send(Encoding.UTF8.GetBytes("Content-Type: application/json\r\n"));
client.Send(Encoding.UTF8.GetBytes("Content-Length: " + body.Length + "\r\n"));
client.Send(Encoding.UTF8.GetBytes("\r\n" + body));
Program.PrintDebugMessage("Sent response to client '" + client.RemoteEndPoint + "'.");
}
private static string GetData()
{
string data = string.Empty;
for (int i = 0; i < 1024; i++)
{
data += "x";
}
return data;
}
private static string ParseAsciiString(byte[] buffer, int bufferLength)
{
var chars = new char[bufferLength];
for (int index = 0; index < chars.Length; index++)
{
chars[index] = (char)buffer[index];
}
return new string(chars);
}
private static void Listen()
{
while (true)
{
try
{
Program.WaitForClient();
}
catch (Exception exception)
{
Program.PrintDebugMessage("Unhandled exception!" + exception.Message);
}
}
}
private static void WaitForClient()
{
Program.PrintDebugMessage("Waiting for a client...");
Socket client = Program._serverSocket.Accept();
if (client == null)
{
// For shure...
return;
}
Program._clientConnections++;
Program.PrintDebugMessage("Client '" + client.RemoteEndPoint + "' connected.");
try
{
client.ReceiveTimeout = 5000;
client.SendTimeout = 5000;
client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
Program.HandleClient(client);
}
catch (Exception exception)
{
Program.PrintDebugMessage("Client connection '" + client.RemoteEndPoint + "' failed. " + exception.Message);
}
finally
{
client.Close();
Debug.GC(true);
}
}
}
}