Я пишу сервис C # (.NET 4.0), который прослушивает порт TCP.Я запускаю TcpListener в фоновом потоке (используя Task Parallel Library), чтобы служба не реагировала на Windows.Я также использую TPL всякий раз, когда клиент подключается, так как каждый клиент выполняет некоторую работу с базой данных, и я не хочу блокировать других клиентов.
Я устанавливаю и удаляю службу с помощью InstallUtil.exe в Windows Server 2012 R2 Standard.Всякий раз, когда я останавливаю службу и удаляю ее, используя netstat -abo, я вижу, что порт все еще прослушивается процессом [System].У него есть PID, однако я не вижу процесс с этим PID в диспетчере задач или списке задач, и при этом я не могу убить его с помощью taskkill.Он просто говорит, что процесс не найден, но всегда работает, когда запускаю netstat -abo.Если я попытаюсь запустить службу снова, используя тот же порт, я получаю исключение сокета:
Only one usage of each socket address (protocol/network address/port) is normally permitted
Stacktrace:
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.Net.Sockets.TcpListener.Start(Int32 backlog)
Я предполагаю, что мои фоновые потоки все еще зависают после остановки службы, но я понятия не имею,как их убить сейчас, и как этого избежать.Вот что, я надеюсь, является соответствующим кодом (удаленная обработка исключений и ведение журнала для удобства чтения):
public partial class MyService : ServiceBase
{
private static TCPServer server = null;
protected override void OnStart(string[] args)
{
server = new TCPServer();
}
protected override void OnStop()
{
if (server != null)
{
server.StopServer();
}
}
}
class TCPServer
{
public static TcpListener listener = null;
private static Task listenerTask = null;
private static List<Task> clientTasks = new List<Task>();
public TCPServer()
{
listenerTask = new Task(() => StartServer());
listenerTask.Start();
}
public void StopServer()
{
foreach(Task task in clientTasks)
{
task.Dispose();
}
listenerTask.Dispose();
if (listener != null)
{
listener.Stop();
listener = null;
}
}
private void StartServer()
{
Int32 port = 51987;
IPAddress localAddr = GetLocalIP();
listener = new TcpListener(localAddr, port);
listener.Start();
while (listener != null)
{
if (listener.Pending())
{
TcpClient client = listener.AcceptTcpClient();
Task task = new Task((obj) => ProcessClient(obj), client);
task.Start();
clientTasks.Add(task);
}
}
}
private void ProcessClient(object obj)
{
using (TcpClient client = obj as TcpClient)
{
Byte[] bytes = new Byte[2048];
String data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = Encoding.ASCII.GetString(bytes, 0, i);
}
// do some stuff with data
// If an exception is thrown here, the rogue thread issue happens when I stop the service.
// Otherwise, everything is good - I stop the service and no rogue thread, I can reuse the listener port.
}
}
}
РЕДАКТИРОВАТЬ: Обновлен код с предлагаемыми изменениями.Я также обнаружил, что эта проблема с неконтролируемыми потоками возникает только в том случае, если в одном из моих клиентских потоков возникло исключение.Если все работает нормально, то нет остановки мошенника, когда я останавливаю службу.