Issue
I have a UWP background app that I wrote which runs on a Raspberry Pi running the latest build of Windows IoT. It's purpose is to handle http requests and return a response to several mobile apps.
It works great, except that it seems like the listening port on the socket will occasionally hang. The rest of the background app remains responsive so I know the app is still running. But the http requests stop responding. Usually just logging into the IoT Dashboard and restarting my app will resolve the problem. But I can't figure out why the app occasionally hangs.
Here is the segment of code that I think is relevant:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Windows.ApplicationModel.Background;
using Windows.Networking.Sockets;
namespace MyApp.Sandbox
{
public class SystemTest : IBackgroundTask
{
private StreamSocketListener listener = null;
public void Run(IBackgroundTaskInstance taskInstance)
{
StartServer();
}
public async void StartServer()
{
try
{
int port = 8189;
listener = new StreamSocketListener();
var currentSetting = listener.Control.QualityOfService;
listener.Control.QualityOfService = SocketQualityOfService.LowLatency;
await listener.BindServiceNameAsync(port.ToString());
listener.ConnectionReceived += async (sender, args) =>
{
var request = new StringBuilder();
using (var input = args.Socket.InputStream.AsStreamForRead())
{
int maxBuffer = 8192;
int index = 0;
List<byte> line = new List<byte>();
int b;
while (true)
{
try
{
b = input.ReadByte();
line.Add((byte)b);
if (b == 10 && line.Count >= 2)
{
if (line[line.Count - 2] == 13 && line[line.Count - 1] == 10)
{
byte[] byteArray = line.ToArray();
var dataString = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
request.Append(dataString);
line = new List<byte>();
if (request.ToString().StartsWith("GET"))
{
break;
}
if (request.ToString().StartsWith("POST") &&
request.ToString().Contains(Environment.NewLine + Environment.NewLine))
{
string contentLength = GetValueFromHeader("Content-Length", request.ToString());
if (!contentLength.Equals(""))
{
int length = Convert.ToInt32(contentLength);
if (length > 0)
{
byteArray = new byte[length];
input.Read(byteArray, 0, length);
dataString = Encoding.UTF8.GetString(byteArray, 0, byteArray.Length);
request.Append(dataString);
}
}
break;
}
}
}
index++;
if (index > maxBuffer)
{
break;
}
}
catch
{
break;
}
}
input.Dispose();
}
using (var output = args.Socket.OutputStream)
{
using (var response = output.AsStreamForWrite())
{
var requestLines = request.ToString().Split(' ');
var url = requestLines.Length > 1 ? requestLines[1] : string.Empty;
string postLine = null;
if (requestLines.Length > 0)
{
if (requestLines[0] == "POST")
{
postLine = requestLines[requestLines.Length - 1];
}
}
string str = null;
try
{
// handle response here which fills "str"
}
catch (Exception innerEx)
{
Debug.WriteLine(innerEx.Message);
Debug.WriteLine(innerEx.StackTrace);
}
var html = Encoding.UTF8.GetBytes(str);
using (var bodyStream = new MemoryStream(html))
{
var header = $"HTTP/1.1 200 OK\r\nContent-Length: {bodyStream.Length}\r\nContent-Type: application/json\r\ncharset: UTF-8\r\nConnection: close\r\n\r\n";
var headerArray = Encoding.UTF8.GetBytes(header);
await response.WriteAsync(headerArray, 0, headerArray.Length);
await bodyStream.CopyToAsync(response);
await response.FlushAsync();
}
}
output.Dispose();
}
};
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.StackTrace);
}
}
}
}
I have confirmed that "Compile with .NET Native Toolchain" is enabled in my build configuration. And I am running this in release mode.
I am not sure if there is something different I need to be doing to release the incoming connections? Is it perhaps hanging because multiple requests are coming in at the same time and it can't handle it?
Here is an example of what netstat looks like when the port (in this case it is 8081) hangs:
TCP 192.168.1.190:8081 5.101.0.209:32880 CLOSE_WAIT
TCP 192.168.1.190:8081 5.101.0.209:33494 CLOSE_WAIT
TCP 192.168.1.190:8081 5.101.0.209:60412 CLOSE_WAIT
TCP 192.168.1.190:8081 Mike-PC:59879 CLOSE_WAIT
TCP 192.168.1.190:8081 Mike-PC:59880 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43096 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43110 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43114 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43120 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43130 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43742 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43744 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43750 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43822 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43914 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:43986 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48646 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48648 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48702 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48724 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48774 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48776 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48820 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48834 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:48918 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:49036 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:49058 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:49284 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:49416 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:49672 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:49680 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:50360 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:50566 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:50718 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:50724 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:50734 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:50938 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:51082 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:51524 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:51880 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:51946 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:52146 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:52212 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:52224 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:52310 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:53126 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:53206 CLOSE_WAIT
TCP 192.168.1.190:8081 Galaxy-S20-5G:53284 CLOSE_WAIT
TCP 192.168.1.190:8081 192.227.118.82:1550 ESTABLISHED
TCP 192.168.1.190:59613 52.242.211.89:https ESTABLISHED
TCP [::]:22 myapp:0 LISTENING
TCP [::]:135 myapp:0 LISTENING
TCP [::]:445 myapp:0 LISTENING
TCP [::]:5985 myapp:0 LISTENING
TCP [::]:8080 myapp:0 LISTENING
TCP [::]:8081 myapp:0 LISTENING
TCP [::]:47001 myapp:0 LISTENING
TCP [::]:49664 myapp:0 LISTENING
TCP [::]:49665 myapp:0 LISTENING
TCP [::]:49667 myapp:0 LISTENING
UDP 0.0.0.0:123 *:*
UDP 0.0.0.0:5050 *:*
UDP 0.0.0.0:5353 *:*
UDP 0.0.0.0:5355 *:*
UDP 0.0.0.0:29819 *:*
UDP 0.0.0.0:51049 *:*
UDP [::]:123 *:*
UDP [::]:5353 *:*
UDP [::]:5355 *:*
At this point I am open to suggestions if anybody else has run into a similar situation....
Thanks!
Solution
You may try to add StreamSocket.Dispose Method to abort any pending operations and releases all unmanaged resources associated with the StreamSocket object.
listener.Control.KeepAlive = true;
listener.ConnectionReceived += async (sender, args) =>
{
//Your codes
args.Socket.Dispose();
};
Answered By - Michael Xu - MSFT