using System;
using System.Buffers.Binary;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace FastGithub.ReverseProxy
{
///
/// windows iphlpapi
///
[SupportedOSPlatform("windows")]
unsafe static class TcpTable
{
private const int ERROR_INSUFFICIENT_BUFFER = 122;
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern uint GetExtendedTcpTable(void* pTcpTable, ref int pdwSize, bool bOrder, AddressFamily ulAf, TCP_TABLE_CLASS tableClass, uint reserved = 0);
///
/// 杀死占用进程
///
///
///
public static bool KillPortOwner(int port)
{
if (TryGetOwnerProcessId(port, out var pid) == false)
{
return true;
}
try
{
var proess = Process.GetProcessById(pid);
proess.Kill();
return proess.WaitForExit(1000);
}
catch (ArgumentException)
{
return true;
}
catch (Exception)
{
return false;
}
}
///
/// 获取tcp端口的占用进程id
///
///
///
///
public static bool TryGetOwnerProcessId(int port, out int processId)
{
processId = 0;
var pdwSize = 0;
var result = GetExtendedTcpTable(null, ref pdwSize, false, AddressFamily.InterNetwork, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER);
if (result != ERROR_INSUFFICIENT_BUFFER)
{
return false;
}
var buffer = new byte[pdwSize];
fixed (byte* pTcpTable = &buffer[0])
{
result = GetExtendedTcpTable(pTcpTable, ref pdwSize, false, AddressFamily.InterNetwork, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER);
if (result != 0)
{
return false;
}
var prt = new IntPtr(pTcpTable);
var table = Marshal.PtrToStructure(prt);
prt += sizeof(int);
for (var i = 0; i < table.dwNumEntries; i++)
{
var row = Marshal.PtrToStructure(prt);
if (row.LocalPort == port)
{
processId = row.ProcessId;
return true;
}
prt += Marshal.SizeOf();
}
}
return false;
}
private enum TCP_TABLE_CLASS
{
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL,
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
}
[StructLayout(LayoutKind.Sequential)]
private struct MIB_TCPTABLE_OWNER_PID
{
public uint dwNumEntries;
}
[StructLayout(LayoutKind.Sequential)]
private struct MIB_TCPROW_OWNER_PID
{
public uint state;
public uint localAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] localPort;
public uint remoteAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] remotePort;
public int owningPid;
public int ProcessId => owningPid;
public IPAddress LocalAddress => new(localAddr);
public ushort LocalPort => BinaryPrimitives.ReadUInt16BigEndian(this.localPort);
}
}
}