我编写了一个UWP后台应用程序,该应用程序在运行最新版本的Windows IoT的Raspberry Pi上运行。目的是处理http请求并返回对多个移动应用程序的响应。
效果很好,只是看起来套接字上的侦听端口有时会挂起。后台应用程序的其余部分保持响应状态,因此我知道该应用程序仍在运行。但是http请求停止响应。通常只需登录IoT仪表板并重新启动我的应用程序即可解决问题。但我不知道为什么该应用偶尔会挂起。
这是我认为相关的代码段:
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);
}
}
}
}
我已经确认在我的构建配置中启用了“使用.NET Native Toolchain进行编译”。我正在发布模式下运行它。
我不确定是否需要采取其他措施来释放传入的连接?可能是因为同时有多个请求而无法处理却挂起了?
这里是当端口(在本例中为8081)挂起时netstat的示例:
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 *:*
在这一点上,如果有人遇到类似情况,我愿意提出建议...。
谢谢!
您可以尝试添加StreamSocket.Dispose方法来中止任何挂起的操作并释放与StreamSocket对象关联的所有非托管资源。
listener.Control.KeepAlive = true;
listener.ConnectionReceived += async (sender, args) =>
{
//Your codes
args.Socket.Dispose();
};