Linux では MONO を使用します。
C# を使用してポート番号をサービスにペアリングするにはどうすればよいですか?
例:
port 80 = http
port 443 = https
コンソールに出力します。これは、私が作成した単純なポート スキャナーに必要です。
この関数がルビーに存在することは知っています:
Socket.getservbyport(80, "tcp")
モノ Linux バージョン
少し時間があったので、Ubuntu Linux ボックスに Mono をセットアップしてテストしました。getservbyport() と getservbyname() の Mono PInvoke 実装は、Windows よりも単純です (ネットワーク機能が組み込まれた libc をロードするだけです)。誰かがそれを望んでいる場合に備えて、参照用のサンプルコードを次に示します;)
namespace SocketUtil
{
using System;
using System.Net;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
[Serializable]
public class SocketUtilException : Exception
{
public SocketUtilException()
{
}
public SocketUtilException(string message)
: base(message)
{
}
public SocketUtilException(string message, Exception inner)
: base(message, inner)
{
}
protected SocketUtilException(
SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
public static class SocketUtil
{
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct servent
{
public string s_name;
public IntPtr s_aliases;
public ushort s_port;
public string s_proto;
}
[DllImport("libc", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr getservbyname(string name, string proto);
[DllImport("libc", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr getservbyport(ushort port, string proto);
public static string GetServiceByPort(ushort port, string protocol, out List<string> aliases)
{
var netport = unchecked((ushort)IPAddress.HostToNetworkOrder(unchecked((short)port)));
var result = getservbyport(netport, protocol);
if (IntPtr.Zero == result)
{
throw new SocketUtilException(
string.Format("Could not resolve service for port {0}", port));
}
var srvent = (servent)Marshal.PtrToStructure(result, typeof(servent));
aliases = GetAliases(srvent);
return srvent.s_name;
}
private static List<string> GetAliases(servent srvent)
{
var aliases = new List<string>();
if (srvent.s_aliases != IntPtr.Zero)
{
IntPtr cb;
for (var i = 0;
(cb = Marshal.ReadIntPtr(srvent.s_aliases, i)) != IntPtr.Zero;
i += Marshal.SizeOf(cb))
{
aliases.Add(Marshal.PtrToStringAnsi(cb));
}
}
return aliases;
}
public static ushort GetServiceByName(string service, string protocol, out List<string> aliases)
{
var result = getservbyname(service, protocol);
if (IntPtr.Zero == result)
{
throw new SocketUtilException(
string.Format("Could not resolve port for service {0}", service));
}
var srvent = (servent)Marshal.PtrToStructure(result, typeof(servent));
aliases = GetAliases(srvent);
var hostport = IPAddress.NetworkToHostOrder(unchecked((short)srvent.s_port));
return unchecked((ushort)hostport);
}
}
class Program
{
static void Main(string[] args)
{
try
{
List<string> aliases;
var port = SocketUtil.GetServiceByName("https", "tcp", out aliases);
Console.WriteLine("https runs on port {0}", port);
foreach (var alias in aliases)
{
Console.WriteLine(alias);
}
Console.WriteLine("Reverse call:{0}", SocketUtil.GetServiceByPort(port, "tcp", out aliases));
}
catch (SocketUtilException exception)
{
Console.WriteLine(exception.Message);
if (exception.InnerException != null)
{
Console.WriteLine(exception.InnerException.Message);
}
}
}
}
}
Windows版
更新: 投稿者が質問をした後に Linux と Mono のタグを追加したのを遅すぎたので、Windows の実装を書きました。Linux では、2 番目の投稿で Mono バージョンを使用します。
Mohammad のソリューションは、多くの点で他のソリューションよりも移植性が高くなります。getservbyname() と getservbyport() はプラットフォームに依存し、P/Invoke を使用して Windows で c# を使用する必要があり、おそらく Mono でも同様です。
以下のコードを Mono で実装するには、プラットフォーム固有の API を使用して PInvoke する必要があります (ヘッダーは netdb.h になります) - WSAStartUp() と WSACleanUp() は Windows 固有のソケット初期化関数であり、Linux では無関係であることに注意してください。システム。現時点では mono セットアップを行っていないため、Linux 固有のソリューションを提供することはできません。
namespace SocketTest
{
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
[Serializable]
public class SocketUtilException : Exception
{
public SocketUtilException()
{
}
public SocketUtilException(string message)
: base(message)
{
}
public SocketUtilException(string message, Exception inner)
: base(message, inner)
{
}
protected SocketUtilException(
SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
public static class SocketUtil
{
private const int WSADESCRIPTION_LEN = 256;
private const int WSASYSSTATUS_LEN = 128;
[StructLayout(LayoutKind.Sequential)]
public struct WSAData
{
public short wVersion;
public short wHighVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = WSADESCRIPTION_LEN+1)]
public string szDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = WSASYSSTATUS_LEN+1)]
public string wSystemStatus;
[Obsolete("Ignored when wVersionRequested >= 2.0")]
public ushort wMaxSockets;
[Obsolete("Ignored when wVersionRequested >= 2.0")]
public ushort wMaxUdpDg;
public IntPtr dwVendorInfo;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct servent
{
public string s_name;
public IntPtr s_aliases;
public short s_port;
public string s_proto;
}
private static ushort MakeWord ( byte low, byte high)
{
return (ushort)((ushort)(high << 8) | low);
}
[DllImport("ws2_32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)]
private static extern int WSAStartup(ushort wVersionRequested, ref WSAData wsaData);
[DllImport("ws2_32.dll", CharSet = CharSet.Auto, ExactSpelling = true, SetLastError = true)]
private static extern int WSACleanup();
[DllImport("ws2_32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr getservbyname(string name, string proto);
[DllImport("ws2_32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr getservbyport(short port, string proto);
public static string GetServiceByPort(short port, string protocol)
{
var wsaData = new WSAData();
if (WSAStartup(MakeWord(2, 2), ref wsaData) != 0)
{
throw new SocketUtilException("WSAStartup",
new SocketException(Marshal.GetLastWin32Error()));
}
try
{
var netport = Convert.ToInt16(IPAddress.HostToNetworkOrder(port));
var result = getservbyport(netport, protocol);
if (IntPtr.Zero == result)
{
throw new SocketUtilException(
string.Format("Could not resolve service for port {0}", port),
new SocketException(Marshal.GetLastWin32Error()));
}
var srvent = (servent)Marshal.PtrToStructure(result, typeof(servent));
return srvent.s_name;;
}
finally
{
WSACleanup();
}
}
public static short GetServiceByName(string service, string protocol)
{
var wsaData = new WSAData();
if(WSAStartup(MakeWord(2,2), ref wsaData) != 0)
{
throw new SocketUtilException("WSAStartup",
new SocketException(Marshal.GetLastWin32Error()));
}
try
{
var result = getservbyname(service, protocol);
if (IntPtr.Zero == result)
{
throw new SocketUtilException(
string.Format("Could not resolve port for service {0}", service),
new SocketException(Marshal.GetLastWin32Error()));
}
var srvent = (servent)Marshal.PtrToStructure(result, typeof(servent));
return Convert.ToInt16(IPAddress.NetworkToHostOrder(srvent.s_port));
}
finally
{
WSACleanup();
}
}
}
class Program
{
static void Main(string[] args)
{
try
{
var port = SocketUtil.GetServiceByName("http", "tcp");
Console.WriteLine("http runs on port {0}", port);
Console.WriteLine("Reverse call:{0}", SocketUtil.GetServiceByPort(port, "tcp"));
}
catch(SocketUtilException exception)
{
Console.WriteLine(exception.Message);
if(exception.InnerException != null)
{
Console.WriteLine(exception.InnerException.Message);
}
}
}
}
Windows では、System32\Drivers\Etc\ フォルダーに「services」ファイルがあります。私はそれを解析するために次のコードを書きました。これを使用して、必要なポートに関する情報を見つけることができます。
class Program
{
static void Main(string[] args)
{
var services = ReadServicesFile();
// For example, I want to find information about port 443 of TCP service
var port443Info = services.FirstOrDefault(s => s.Port == 443 && s.Type.Equals("tcp"));
if (port443Info != null)
{
Console.WriteLine("TCP Port = {0}, Service name = {1}", port443Info.Port, port443Info.Name);
}
}
static List<ServiceInfo> ReadServicesFile()
{
var sysFolder = Environment.GetFolderPath(Environment.SpecialFolder.System);
if (!sysFolder.EndsWith("\\"))
sysFolder += "\\";
var svcFileName = sysFolder + "drivers\\etc\\services";
var lines = File.ReadAllLines(svcFileName);
var result = new List<ServiceInfo>();
foreach (var line in lines)
{
if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
continue;
var info = new ServiceInfo();
var index = 0;
// Name
info.Name = line.Substring(index, 16).Trim();
index += 16;
// Port number and type
var temp = line.Substring(index, 9).Trim();
var tempSplitted = temp.Split('/');
info.Port = ushort.Parse(tempSplitted[0]);
info.Type = tempSplitted[1].ToLower();
result.Add(info);
}
return result;
}
}
次のクラス宣言も必要です。
class ServiceInfo
{
public ushort Port { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}