C #에서 TCP 포트를 사용할 수 있는지 확인하는 방법은 무엇입니까?


120

C #에서 TcpClient를 사용하거나 일반적으로 소켓에 연결하려면 내 컴퓨터에서 특정 포트가 사용 가능한지 먼저 확인하려면 어떻게해야합니까?

추가 정보 : 이것은 내가 사용하는 코드입니다.

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);

2
여기서 "무료"란 무엇을 의미합니까? 연결을 시도했지만 실패하면 아무것도 듣고 있지 않음을 의미합니다.
Jon Skeet

2
다른 응용 프로그램에서 사용하지 않음을 의미합니다. 응용 프로그램이 포트를 사용하는 경우 다른 사용자는 포트가 해제 될 때까지 사용할 수 없습니다.
알리

연결하려는 서버는 무엇입니까? 작성 했습니까, 아니면 기존 서버입니까?
슬픔

3
많은 답변에서 언급했듯이 모든 것이 거꾸로 있습니다. 로컬 포트와 원격 포트는 완전히 다른 두 가지입니다. 이 답변은 특히 잘 설명합니다. stackoverflow.com/questions/570098/…
bzlm 2009

답변:


217

를 사용하고 있으므로 TcpClient열린 TCP 포트를 확인하고 있음을 의미합니다. System.Net.NetworkInformation 네임 스페이스 에서 사용할 수있는 좋은 개체가 많이 있습니다 .

IPGlobalProperties개체를 사용하여 개체 배열에 TcpConnectionInformation도달하면 끝점 IP 및 포트에 대해 조사 할 수 있습니다.


 int port = 456; //<--- This is your value
 bool isAvailable = true;

 // Evaluate current system tcp connections. This is the same information provided
 // by the netstat command line application, just in .Net strongly-typed object
 // form.  We will look through the list, and if our port we would like to use
 // in our TcpClient is occupied, we will set isAvailable to false.
 IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
 TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

 foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
 {
   if (tcpi.LocalEndPoint.Port==port)
   {
     isAvailable = false;
     break;
   }
 }

 // At this point, if isAvailable is true, we can proceed accordingly.

38
확인하는 동안 다른 프로세스가 해당 포트에 바인드 될 수 있다는 점에 유의하십시오.
Serguei

2
이것이 질문과 어떤 관련이 있습니까? 이 답변은 원격 포트가 아닌 로컬 포트를 다룹니다 .
bzlm 2009

6
OP의 요청에 응답한다는 점에서 관련이 있습니다. 로컬 / 원격 차이에도 불구하고 (완전히 동의 함) OP의 요구 사항은 "무료"포트로 새 TcpClient를 만드는 것이 었습니다.
jro 2009

8
이 코드는 활성 연결 만 확인합니다. 패킷을 보내거나받지 않은 연결은 나열되지 않습니다.
JoeBilly 2011-06-17

29
위 코드의 결과를 netstat -a -b. 에는 LISTENING연결이 없습니다 GetActiveTcpConnections(). 또한 System.Net.IPEndPoints[]반환 된 체크인을해야합니다ipGlobalProperties.GetActiveTcpListeners();
Mike de Klerk 2013

44

Intertube의 끝이 잘못되었습니다. 특정 포트를 하나만 열 수있는 서버입니다. 일부 코드 :

  IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
  try {
    TcpListener tcpListener = new TcpListener(ipAddress, 666);
    tcpListener.Start();
  }
  catch (SocketException ex) {
    MessageBox.Show(ex.Message, "kaboom");
  }

실패 :

일반적으로 각 소켓 주소 (프로토콜 / 네트워크 주소 / 포트)를 한 번만 사용할 수 있습니다.


그것이 내가 그것과 함께했던 곳이기도합니다. 누군가가 여기에서 확실히 혼란 스럽습니다.
Moose

3
클라이언트에도 특정 포트가 필요할 수 있지만 일반적이지 않습니다.
Dave Van den Eynde 2009

@DaveVandenEynde는 "클라이언트"가 실제로 특정 포트에서 무언가를 "서비스"하는 경우에만 발생할 수 있습니다 (적어도 TCP에 관한 한 해당 포트에 대해서는 "서버"로 만듭니다). -클라이언트 TCP 연결이 있으면 나가는 포트를 제어 할 수 없습니다. TCP 스택은 나가는 포트를 할당하며 사용자는이를 제어 할 수 없습니다.
BrainSlugs83

1
: 당신은 가장 확실하게 할 수 BrainSlugs83 @ stackoverflow.com/questions/2869840/...
Eynde 서재 데이브 반

포트가 비어 있는지 확인하는 데 유효한 코드입니다. 성공할 경우를 대비하여 TcpListener를 Stop ()하는 것을 잊지 마십시오 (동일한 TcpListener 개체를 사용하여 포트에서 수신을 시작하려는 경우 제외).
bgh

19

TCP 연결을 설정할 때 4- 튜플 (source-ip, source-port, dest-ip, dest-port)은 고유해야합니다. 이는 패킷이 올바른 위치로 전달되도록하기위한 것입니다.

서버 측에는 하나의 서버 프로그램 만 들어오는 포트 번호에 바인딩 할 수 있다는 추가 제한이 있습니다 (하나의 IP 주소를 가정하면 다중 NIC 서버에는 다른 권한이 있지만 여기서 논의 할 필요는 없습니다).

따라서 서버 측에서 다음을 수행합니다.

  • 소켓을 만듭니다.
  • 해당 소켓을 포트에 바인딩하십시오.
  • 그 포트에서 들어요.
  • 해당 포트에서 연결을 수락합니다. 여러 연결이 들어올 수 있습니다 (클라이언트 당 하나씩).

클라이언트 측에서는 일반적으로 조금 더 간단합니다.

  • 소켓을 만듭니다.
  • 연결을 엽니 다. 클라이언트가 연결을 열 때 서버 의 IP 주소와 포트를 지정 합니다 . 그것은 수있는 소스 포트를 지정하지만, 일반적으로 자동에게 무료로 포트를 할당 시스템의 제로하는 결과를 사용합니다.

대상 IP / 포트가 고유 필요 는 없습니다. 그럴 경우 한 번에 한 사람 만 Google을 사용할 수 있고 비즈니스 모델이 거의 파괴 될 수 있기 때문입니다.

즉, 소스 포트가 유일한 차이점 인 여러 세션을 설정하여 청크를 병렬로 다운로드 할 수 있기 때문에 다중 세션 FTP와 같은 놀라운 일을 할 수도 있습니다. 급류는 일반적으로 각 세션의 목적지가 다르다는 점에서 약간 다릅니다.

그리고 그 모든 혼란스러운 (죄송합니다), 특정 질문에 대한 대답은 자유 포트를 지정할 필요가 없다는 것입니다. 소스 포트를 지정하지 않는 호출로 서버에 연결하는 경우 거의 확실하게 커버 아래에서 0을 사용하고 시스템에서 사용하지 않는 포트를 제공합니다.


15
TcpClient c;

//I want to check here if port is free.
c = new TcpClient(ip, port);

... 컴퓨터에서 특정 포트가 사용 가능한지 어떻게 먼저 확인할 수 있습니까?

다른 응용 프로그램에서 사용하지 않음을 의미합니다. 응용 프로그램이 포트를 사용하는 경우 다른 사용자는 포트가 해제 될 때까지 사용할 수 없습니다. – 알리

여기서 무슨 일이 일어나고 있는지 오해했습니다.

TcpClient (...) 매개 변수는 연결하려는 서버 IP 및 서버 포트입니다.

TcpClient는 사용 가능한 풀에서 임시 로컬 포트를 선택하여 서버와 통신합니다. winsock 계층에 의해 자동으로 처리되므로 로컬 포트의 가용성을 확인할 필요가 없습니다.

위의 코드 조각을 사용하여 서버에 연결할 수없는 경우 문제는 여러 가지 중 하나 이상일 수 있습니다. (예 : 서버 IP 및 / 또는 포트가 잘못되었거나 원격 서버를 사용할 수 없음 등)


15

이 팁에 감사드립니다. 동일한 기능이 필요했지만 서버 측에서 포트가 사용 중인지 확인하기 위해이 코드를 수정했습니다.

 private bool CheckAvailableServerPort(int port) {
    LOG.InfoFormat("Checking Port {0}", port);
    bool isAvailable = true;

    // Evaluate current system tcp connections. This is the same information provided
    // by the netstat command line application, just in .Net strongly-typed object
    // form.  We will look through the list, and if our port we would like to use
    // in our TcpClient is occupied, we will set isAvailable to false.
    IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
    IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();

    foreach (IPEndPoint endpoint in tcpConnInfoArray) {
        if (endpoint.Port == port) {
            isAvailable = false;
            break;
        }
    }

    LOG.InfoFormat("Port {0} available = {1}", port, isAvailable);

    return isAvailable;
}

이건 필요하지 않습니다. 포트 0을 지정하십시오.
Marquis of Lorne

소스 코드 주석의 메모 : "이것은 netstat 명령 줄 응용 프로그램에서 제공하는 것과 동일한 정보입니다."-거짓말입니다. netstat 명령이 포트 ( -anb)를 사용하여 애플리케이션의 PID를 제공하는 것과 동일한 정보를 제공 하지 않으며 매개 변수없이 외부 연결과 상태를 표시합니다.
Kraang Prime

6

답변 jro에 감사드립니다. 내 용도에 맞게 조정해야했습니다. 포트가 수신 대기 중인지, 필요하지 않은지 확인해야했습니다. 이를 위해 나는 대체

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.  

내 포트 값을 찾을 수 없는지 확인하는 끝점 배열을 반복했습니다.


직접 들어보십시오. 이 중 아무것도 필요하지 않습니다.
Marquis of Lorne

5
string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];


try
{
    System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
    sock.Connect(ipa, portno);
    if (sock.Connected == true)  // Port is in use and connection is successful
            MessageBox.Show("Port is Closed");
    sock.Close();

}
catch (System.Net.Sockets.SocketException ex)
{
    if (ex.ErrorCode == 10061)  // Port is unused and could not establish connection 
        MessageBox.Show("Port is Open!");
    else
        MessageBox.Show(ex.Message);
}

나는 소켓에 연결하려는 사람입니다. 더 명확하게 질문을 편집했습니다.
알리

이 코드가 가장 마음에 듭니다. 이것은 누군가가 다른 쪽에서 듣고 있는지 여부를보기 위해 소켓에 대한 TCP 연결을 실제로 엽니 다. 그리고 많은 사람들이 "원격 호스트에서 포트가 열려 있는지 테스트"하고 싶을 때 실제로 이것을 원한다고 생각합니다. 그러나 위 코드에는 버그가 있습니다. (sock.Connected == true) 포트가 연결을 위해 열려 있으면 서버와 같은 일부 소프트웨어가 수신 대기합니다. 10061 ErrorCode (메시지 "(0x80004005) : 대상 컴퓨터가 적극적으로 거부했기 때문에 연결을 만들 수 없습니다"라는 메시지가있는 SocketException이 발생하면 포트가 닫힙니다!
Csaba Toth 2013 년

따라서 코드 스 니펫에서 그 반대입니다. 또 다른 참고 사항 : IP 주소 만있는 가상 서버가있는 테스트 설정에서 누군가 Dns.GetHostEntry를 시도하면 예외가 발생합니다.
Csaba Toth

3

netstat! Windows와 함께 제공되는 네트워크 명령 줄 유틸리티입니다. 현재 설정된 모든 연결과 현재 수신중인 모든 포트를 표시합니다. 이 프로그램을 사용하여 확인할 수 있지만 코드에서이 작업을 수행하려면 System.Net.NetworkInformation 네임 스페이스를 살펴보십시오. 2.0부터 새로운 네임 스페이스입니다. 거기에 몇 가지 좋은 점이 있습니다. 그러나 결국 netstat 명령을 통해 사용할 수있는 동일한 종류의 정보를 얻으려면 P / Invoke로 결과를 얻어야합니다.

업데이트 : System.Net.NetworkInformation

이 네임 스페이스에는 네트워크에 대한 정보를 파악하는 데 사용할 수있는 여러 클래스가 포함되어 있습니다.

나는 그 오래된 코드를 찾을 수 없었지만 비슷한 것을 직접 작성할 수 있다고 생각합니다. 좋은 시작은 IP Helper API 를 확인하는 것 입니다. GetTcpTable WINAPI 기능에 대한 Google MSDN을 사용하고 P / Invoke를 사용하여 필요한 정보를 얻을 때까지 열거합니다.


.NET 3.5를 사용하고 있는데 괜찮습니다.
알리


3

내가별로 착각하지 않았다면 System.Network.whatever를 사용하여 확인할 수 있습니다.

그러나 이것은 항상 경쟁 조건이 발생합니다.

표준 검사 방법은 해당 포트에서 수신을 시도하는 것입니다. 오류가 발생하면 해당 포트가 열리지 않았습니다.

나는 생각 이 바인드 () 듣고 ()는 두 개의 분리 된 시스템 호출 이유의 일부입니다.


2

당신은 말한다

다른 응용 프로그램에서 사용하지 않음을 의미합니다. 응용 프로그램이 포트를 사용하는 경우 다른 사용자는 포트가 해제 될 때까지 사용할 수 없습니다.

그러나 다른 사람들이 거기에서 듣고 있다면 항상 포트에 연결할 수 있습니다. 그렇지 않으면 http 포트 80이 엉망이 될 것입니다.

귀하의

   c = new TcpClient(ip, port);

실패하면 아무것도 듣고 있지 않습니다. 그렇지 않으면 다른 컴퓨터 / 응용 프로그램에 해당 IP 및 포트에 대한 소켓이 열려 있어도 연결됩니다.


내 응용 프로그램이 포트 10을 사용하여 연결을 시도하고 내 응용 프로그램의 다른 인스턴스가 포트 10을 사용하여 다시 연결을 시도하면 두 응용 프로그램이 하나의 포트를 사용하여 데이터를 보낼 수 없기 때문에 실패합니다. 즉, 다른 포트 80을 수신 할 때
알리

어떻게 다릅니 까? 애플리케이션의 포트 10에서 수신 대기하는 것은 무엇입니까?
Moose

두 번째 인스턴스가 연결을 시도 할 때 실패하면 애플리케이션이 아니라 수신 애플리케이션입니다.
Moose

2

ipGlobalProperties.GetActiveTcpConnections() 수신 상태에서 연결을 반환하지 않습니다.

포트는 청취에 사용할 수 있지만 아무도 연결하지 않으면 위에서 설명한 방법이 작동하지 않습니다.


위에서 설명한 방법은 무엇입니까? 이것은 질문에 어떻게 대답합니까?
Marquis of Lorne

2

사용 가능한 포트에서 제외합니다.

  • 활성 TCP 연결
  • 활성 TCP 리스너
  • 활성 UDP 리스너

다음 가져 오기 :

using System.Net.NetworkInformation;

다음 기능을 사용하여 포트의 사용 가능 여부를 확인할 수 있습니다.

private bool isPortAvalaible(int myPort)
{
    var avalaiblePorts = new List<int>();
    var properties = IPGlobalProperties.GetIPGlobalProperties();

    // Active connections
    var connections = properties.GetActiveTcpConnections();
    avalaiblePorts.AddRange(connections);

    // Active tcp listners
    var endPointsTcp = properties.GetActiveTcpListeners();
    avalaiblePorts.AddRange(endPointsTcp);

    // Active udp listeners
    var endPointsUdp = properties.GetActiveUdpListeners();
    avalaiblePorts.AddRange(endPointsUdp);

    foreach (int p in avalaiblePorts){
        if (p == myPort) return false;
    }
    return true;
}

VB.NET 을 사용하는 사람들에게 비슷한 기능을 제공합니다 .

Imports System.Net.NetworkInformation
Private Function isPortAvalaible(ByVal myPort As Integer) As Boolean
  Dim props As IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()

  ' ignore active connections
  Dim tcpConnInfoArray() As TcpConnectionInformation = props.GetActiveTcpConnections()
  For Each tcpi As Net.NetworkInformation.TcpConnectionInformation In tcpConnInfoArray
    If tcpi.LocalEndPoint.Port = myPort Then
      Return False
    End If
  Next tcpi

  ' ignore active TCP listeners
  Dim activeTcpListeners() As Net.IPEndPoint = props.GetActiveTcpListeners
  For Each tcpListener As Net.IPEndPoint In activeTcpListeners
    If tcpListener.Port = myPort Then
      Return False
    End If
  Next tcpListener

  ' ignore active UPD listeners
  Dim activeUdpListeners() As Net.IPEndPoint = props.GetActiveUdpListeners
  For Each udpListener As Net.IPEndPoint In activeUdpListeners
    If udpListener.Port = myPort Then
      Return False
    End If
  Next udpListener

  Return True
End Function

2

dotnet core 3.1에서 사용 가능한 포트 (내 단위 테스트에서 필요한 것)를 찾는 정확한 질문에 답하기 위해 다음을 찾았습니다.

public static int GetAvailablePort(IPAddress ip) {
        TcpListener l = new TcpListener(ip, 0);
        l.Start();
        int port = ((IPEndPoint)l.LocalEndpoint).Port;
        l.Stop();
        Log.Info($"Available port found: {port}");
        return port;
    }

참고 : 나는 검색과 발견 포트 제로에 대해 @ user207421하여 주석 기반 살짝 수정합니다.


1

확인하는 시간과 연결을 시도하는 순간 사이의 시간 창에 일부 프로세스가 포트-클래식 TOCTOU를 취할 수 있습니다 . 그냥 연결 해보지 그래? 실패하면 포트를 사용할 수없는 것입니다.


4
TOCTOU는 YALAIHHOBIKTPBI (또 다른 긴 약기 내가 유무는 들어 보지,하지만 그 뒤에 현상을 알고)입니다
사바 토스

1

일부 원격 TCP 서비스에 연결하기 위해 로컬 컴퓨터에서 어떤 포트가 열려 있는지 알 필요가 없습니다 (특정 로컬 포트를 사용하려는 경우는 아니지만 일반적으로 그렇지 않음).

모든 TCP / IP 연결은 원격 IP, 원격 포트 번호, 로컬 IP, 로컬 포트 ​​번호의 4 가지 값으로 식별되지만 연결을 설정하려면 원격 IP와 원격 포트 번호 만 알면됩니다.

다음을 사용하여 tcp 연결을 만들 때

TcpClient c;
c = 새 TcpClient (remote_ip, remote_port);

시스템은 연결에 사용 가능한 여러 로컬 포트 ​​번호 중 하나를 자동으로 할당합니다. 아무것도 할 필요가 없습니다. 원격 포트가 열려 있는지 확인할 수도 있습니다. 하지만 연결을 시도하는 것보다 더 좋은 방법은 없습니다.


주어진 소켓 세트를 확인하는 데 좋습니다. 질문은 단지 하나의 소켓에 관한 것입니다 (어떤 포트 번호가 (?)를 통해 결정되지 않을 수 있음)
Csaba Toth

1
    public static bool TestOpenPort(int Port)
    {
        var tcpListener = default(TcpListener);

        try
        {
            var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];

            tcpListener = new TcpListener(ipAddress, Port);
            tcpListener.Start();

            return true;
        }
        catch (SocketException)
        {
        }
        finally
        {
            if (tcpListener != null)
                tcpListener.Stop();
        }

        return false;
    }

0
test_connection("ip", port);


public void test_connection(String hostname, int portno) {
  IPAddress ipa = (IPAddress)Dns.GetHostAddresses(hostname)[0];
  try {
    System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
   sock.Connect(ipa, portno);
   if (sock.Connected == true) {
     MessageBox.Show("Port is in use");
   }

   sock.Close();
 }
 catch (System.Net.Sockets.SocketException ex) {
   if (ex.ErrorCode == 10060) {
     MessageBox.Show("No connection.");
   }
 }
}

1
일부 코드를 게시 할 때 문제에 대한 해결책 인 이유를 자세히 설명하십시오. 코드만으로는 정보가 너무 적을 수 있으며 답변이 검토 될 위험이 있습니다.
Glubus

0

오류 코드 10048 확인

try
{
    TcpListener tcpListener = new TcpListener(ipAddress, portNumber);
    tcpListener.Start();
}
catch(SocketException ex)
{
    if(ex.ErrorCode == 10048)
    {
        MessageBox.Show("Port " + portNumber + " is currently in use.");
    }
    return;
}

-2

이것을 시도하십시오. 제 경우에는 생성 된 객체의 포트 번호를 사용할 수 없었기 때문에 이것을 생각해 냈습니다.

IPEndPoint endPoint;
int port = 1;
while (true)
{
    try
    {
        endPoint = new IPEndPoint(IPAddress.Any, port);
        break;
    }
    catch (SocketException)
    {
         port++;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.