C # 'da, bir TCP bağlantı noktasının mevcut olup olmadığı nasıl kontrol edilir?


120

C # 'da bir TcpClient kullanmak veya genellikle bir sokete bağlanmak için makinemde belirli bir bağlantı noktasının boş olup olmadığını ilk önce nasıl kontrol edebilirim?

daha fazla bilgi: Kullandığım kod bu:

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

2
Burada "özgür" ile ne demek istiyorsun? Bağlanmaya çalışırsanız ve başarısız olursanız, bu muhtemelen hiçbir şeyin dinlemediği anlamına gelir.
Jon Skeet

2
Yani başka herhangi bir uygulama tarafından kullanılmıyor. Bir uygulama bir bağlantı noktasını kullanıyorsa, ücretsiz olana kadar başkaları onu kullanamaz.
Ali

Bağlanmaya çalıştığınız sunucu nedir? Yazdınız mı yoksa mevcut bir sunucu mu?
yas

3
Birçok cevapta belirtildiği gibi, her şey ters yöndedir. Yerel bağlantı noktaları ve uzak bağlantı noktaları tamamen iki farklı şeydir. Bu cevap özellikle bunu iyi açıklıyor: stackoverflow.com/questions/570098/…
bzlm

Yanıtlar:


218

A kullandığınız için TcpClient, bu, açık TCP bağlantı noktalarını kontrol ettiğiniz anlamına gelir. System.Net.NetworkInformation ad alanında çok sayıda iyi nesne vardır .

IPGlobalPropertiesNesneyi, daha TcpConnectionInformationsonra uç nokta IP'si ve bağlantı noktası hakkında sorgulayabileceğiniz bir dizi nesneye ulaşmak için kullanın .


 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
Siz kontrol ederken başka bir işlemin bu bağlantı noktasına bağlanabileceğini unutmayın.
Serguei

2
Bu soru ile nasıl alakalı? Bu cevap , uzak bağlantı noktaları ile değil, yerel bağlantı noktaları ile ilgilidir.
bzlm

6
OP'nin talebine cevap vermesi ile ilgilidir. Yerel / uzak farkı ne olursa olsun (size tamamen katılıyorum), OP'nin gerekliliği "ücretsiz" bir bağlantı noktasına sahip yeni bir TcpClient oluşturmaktı.
jro

8
Bu kodun yalnızca aktif bağlantıları kontrol ettiğini unutmayın. Paket göndermeyen veya almayan bağlantılar listelenmeyecektir.
JoeBilly

29
Yukarıdaki kodun sonucunu ile karşılaştırın netstat -a -b. O Bildirimi LISTENINGbağlantıları bulunmaz GetActiveTcpConnections(). Ayrıca kontrol etmelisiniz System.Net.IPEndPoints[]tarafından döndürülenipGlobalProperties.GetActiveTcpListeners();
Mike de Klerk

44

Intertube'un yanlış ucundasın. Yalnızca belirli bir bağlantı noktası açık olabilen sunucudur. Bazı kodlar:

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

Şununla başarısız olur:

Normalde her soket adresinin (protokol / ağ adresi / bağlantı noktası) yalnızca bir kullanımına izin verilir.


Ben de oraya gidiyordum. Burada kesinlikle birilerinin kafası karışık ve bu da benim olabilir.
Moose

3
İstemcinin de belirli bir bağlantı noktasına ihtiyaç duyması mümkündür, ancak bu yaygın değildir.
Dave Van den Eynde

@DaveVandenEynde, yalnızca "istemci" o belirli bağlantı noktasında gerçekten bir şey "hizmet veriyorsa" gerçekleşebilir (en azından o bağlantı noktası için, TCP söz konusu olduğunda onu bir "sunucu" yapar). - İstemci TCP bağlantınız olduğunda, giden bağlantı noktasını kontrol edemezsiniz. TCP yığını size bir giden bağlantı noktası atar ve onun üzerinde herhangi bir kontrolünüz yoktur.
BrainSlugs83

1
@ BrainSlugs83 Kesinlikle şunları yapabilirsiniz: stackoverflow.com/questions/2869840/…
Dave Van den Eynde

Bu, bağlantı noktasının boş olup olmadığını kontrol etmek için geçerli bir kod parçasıdır. Başarılı olması durumunda TcpListener'ı Stop () yapmayı unutmayın (bağlantı noktasında dinlemeye başlamak için aynı TcpListener nesnesini kullanmayı düşünmüyorsanız).
bgh

19

Bir TCP bağlantısı kurduğunuzda, 4-tuple (kaynak-ip, kaynak-port, dest-ip, dest-port) benzersiz olmalıdır - bu, paketlerin doğru yere teslim edilmesini sağlamak içindir.

Sunucu tarafında, yalnızca bir sunucu programının gelen bir bağlantı noktası numarasına bağlanabileceği başka bir kısıtlama vardır (bir IP adresi varsayılarak; çoklu NIC sunucularının başka yetkileri vardır, ancak bunları burada tartışmamıza gerek yoktur).

Yani sunucu sonunda siz:

  • bir soket oluşturun.
  • bu soketi bir bağlantı noktasına bağlayın.
  • o limanda dinle.
  • o bağlantı noktasındaki bağlantıları kabul edin. ve gelen birden fazla bağlantı olabilir (istemci başına bir).

İstemci tarafında, genellikle biraz daha basittir:

  • bir soket oluşturun.
  • bağlantıyı açın. Bir istemci bağlantıyı açtığında, sunucunun ip adresini ve bağlantı noktasını belirtir . Bu edebilir kaynak bağlantı noktası belirtin ancak genellikle otomatik it a serbest liman atama sisteminde sıfır hangi sonuçları kullanır.

Orada hiçbir Google'a kullanmak mümkün olan bir seferde sadece bir kişi neden olacaktır ve bu oldukça iyi kendi iş modelini yok edeceğini beri hedef IP / port benzersiz olmasını şart.

Bu, tek farkın kaynak bağlantı noktanız olduğu ve parçaları paralel olarak indirmenize izin veren birden fazla oturum ayarladığınız için çoklu oturum FTP gibi harika şeyler bile yapabileceğiniz anlamına gelir. Torrentler, her oturumun hedefi genellikle farklı olduğu için biraz farklıdır.

Ve tüm bu wafflinglerden sonra (üzgünüm), özel sorunuzun cevabı, boş bir bağlantı noktası belirlemenize gerek olmadığıdır. Bir sunucuya kaynak bağlantı noktanızı belirtmeyen bir çağrı ile bağlanıyorsanız, neredeyse kesinlikle kapakların altında sıfır kullanacak ve sistem size kullanılmayan bir bağlantı verecektir.


15
TcpClient c;

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

... makinemde belirli bir bağlantı noktasının boş olup olmadığını ilk önce nasıl kontrol edebilirim?

Yani başka herhangi bir uygulama tarafından kullanılmıyor. Bir uygulama bir bağlantı noktasını kullanıyorsa, ücretsiz olana kadar başkaları onu kullanamaz. - Ali

Burada neler olduğunu yanlış anladınız.

TcpClient (...) parametreleri bağlanmak istediğiniz sunucu ip ve sunucu portuna aittir.

TcpClient, sunucuyla iletişim kurmak için kullanılabilir havuzdan geçici bir yerel bağlantı noktası seçer. Winsock katmanı tarafından otomatik olarak işlendiği için yerel bağlantı noktasının kullanılabilirliğini kontrol etmeye gerek yoktur.

Yukarıdaki kod parçasını kullanarak sunucuya bağlanamamanız durumunda, sorun biri veya birkaçından biri olabilir. (ör. sunucu ip ve / veya bağlantı noktası yanlış, uzak sunucu kullanılamıyor vb.)


15

Bu ipucu için teşekkürler. Aynı işlevselliğe ihtiyacım vardı, ancak Sunucu tarafında bir Bağlantı Noktasının kullanımda olup olmadığını kontrol etmek için bu kodu değiştirdim.

 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;
}

Buna ihtiyacın yok. Sadece sıfır portunu belirtin.
Marquis of Lorne

Kaynak kod açıklamasındaki not: "Bu, netstat komut satırı uygulaması tarafından sağlanan bilginin aynısıdır" - bir yalandır. Netstat komutu aynı zamanda uygulamanın PID'sini port ( -anb) kullanarak sağlar ve herhangi bir parametre olmadan Dış bağlantıyı ve durumu gösterir.
Kraang Prime

6

cevap için teşekkürler jro. Kullanımım için ince ayar yapmak zorunda kaldım. Bir bağlantı noktasının dinlenip dinlenmediğini ve zorunlu olarak aktif olmadığını kontrol etmem gerekiyordu. Bunun için değiştirdim

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

ile

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

Bağlantı noktası değerimin bulunamadığını kontrol ederek uç noktalar dizisini yineledim.


Sadece kendiniz dinlemeye çalışın. Bunların hiçbirine ihtiyacınız yok.
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);
}

Bir sokete bağlanmaya çalışan benim. Daha net hale getirmek için soruyu düzenledim.
Ali

Bu kodu en çok beğendim, bu gerçekten bir sokete bir TCP bağlantısı açıyor, sırf biri diğer ucunu dinleyip dinlemiyorsa ona bakmak için. Ve bence pek çok kişi "uzaktaki bir ana bilgisayarda bir bağlantı noktasının açık olup olmadığını test etmek" istediklerinde bunu gerçekten istiyor. Ancak yukarıdaki kodda bir hata var: eğer (sock.Connected == true) ise bağlantı noktası bağlantılar için açıksa, bazı sunucu benzeri yazılımlar orada dinliyor. 10061 Hata Kodu içeren bir SocketException varsa (mesaj "(0x80004005): Hedef makine aktif olarak reddettiği için bağlantı kurulamadı" bu durumda bağlantı noktası kapanır!
Csaba Toth

Yani kod parçacığında durum tam tersi. Başka bir not: Eğer birisi sadece IP adreslerine sahip sanal sunucuların olduğu böyle bir test kurulumunda Dns.GetHostEntry'yi denerse, bir istisnaya sahip olacaksınız.
Csaba Toth

3

netstat! Bu, pencerelerle birlikte gelen bir ağ komut satırı yardımcı programıdır. Mevcut tüm mevcut bağlantıları ve şu anda dinlenmekte olan tüm bağlantı noktalarını gösterir. Bu programı kontrol etmek için kullanabilirsiniz, ancak bunu koddan yapmak istiyorsanız System.Net.NetworkInformation ad alanına bakın. 2.0'dan itibaren yeni bir ad alanı. Orada bazı güzellikler var. Ama nihayetinde netstat komutu ile mevcut olan aynı tür bilgileri almak istiyorsanız, P / Invoke ile sonuçlanmanız gerekir ...

Güncelleme: System.Net.NetworkInformation

Bu ad alanı, ağ hakkında bir şeyler bulmak için kullanabileceğiniz bir grup sınıf içerir.

O eski kod parçasını bulamadım ama sanırım siz de benzer bir şeyler yazabilirsiniz. İyi bir başlangıç, IP Helper API'ye göz atmaktır . GetTcpTable WINAPI işlevi için Google MSDN ve ihtiyacınız olan bilgileri elde edene kadar numaralandırmak için P / Invoke kullanın.


.NET 3.5 kullanıyorum ve bunu düzeltemiyorum.
Ali

Senin için
düzeltmeme

3

Çok yanılmıyorsam System.Network.web ne olursa olsun kontrol edebilirsin.

Ancak, bu her zaman bir yarış durumuna neden olacaktır.

Kontrol etmenin kanonik yolu o port üzerinden dinlemeye çalışmaktır. Bir hata alırsanız bu bağlantı noktası açık değildir.

Bunun , bind () ve listen () iki ayrı sistem çağrısı olmasının bir parçası olduğunu düşünüyorum .


2

Diyorsun

Yani başka herhangi bir uygulama tarafından kullanılmıyor. Bir uygulama bir bağlantı noktasını kullanıyorsa, ücretsiz olana kadar başkaları onu kullanamaz.

Ancak, orada dinleyen bir şey varsa, diğerleri onu kullanırken her zaman bir bağlantı noktasına bağlanabilirsiniz. Aksi takdirde, http bağlantı noktası 80 bir karışıklık olur.

Eğer senin

   c = new TcpClient(ip, port);

başarısız olursa, orada hiçbir şey dinlemiyor. Aksi takdirde, başka bir makinenin / uygulamanın o ip ve porta açık bir soketi olsa bile bağlanacaktır.


Uygulamam 10 numaralı bağlantı noktasını kullanarak bağlanmaya çalışırsa ve uygulamamın başka bir örneği, 10 numaralı bağlantı noktasını kullanarak yeniden bağlanmayı denerse, başarısız olur çünkü veri alma söz konusu olduğunda, her iki uygulama da bir bağlantı noktasını kullanarak veri gönderemez, yani farklı olan bağlantı noktası 80
Ali

Nasıl farklı? uygulamanız için port 10'da neler dinleniyor?
Moose

İkinci örnek bağlanmaya çalıştığında başarısız olursa, bu sizin uygulamanız değil, dinleme uygulamasıdır.
Moose

2

ipGlobalProperties.GetActiveTcpConnections() Dinleme Durumunda bağlantıları döndürmez.

Bağlantı noktası dinlemek için kullanılabilir, ancak ona hiç kimse bağlanmadığında yukarıda açıklanan yöntem çalışmayacaktır.


Yukarıda hangi yöntem açıklanmıştır? Bu soruya nasıl cevap veriyor?
Marquis of Lorne

2

Mevcut bağlantı noktalarından şunları hariç tutarım:

  • etkin TCP bağlantıları
  • etkin TCP dinleyicileri
  • aktif UDP dinleyicileri

Aşağıdaki içe aktarmayla:

using System.Net.NetworkInformation;

Bir bağlantı noktasının mevcut olup olmadığını kontrol etmek için aşağıdaki işlevi kullanabilirsiniz:

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 kullananlar için size benzer bir işlev veriyorum :

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 çekirdeğinde (birim testlerimde ihtiyacım olan şey) boş bir bağlantı noktası bulma sorusuna tam olarak cevap vermek için 3.1 bunu buldum

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;
    }

Not: Ben aramışlar ve port sıfır hakkında @ user207421 tarafından yorumunu esaslı bu ve hafifçe değiştirilmiş.


1

Kontrol yaptığınız zaman ile bağlantı kurmaya çalıştığınız an arasındaki zaman aralığının farkında olun, bazı işlemler bağlantı noktasını alabilir - klasik TOCTOU . Neden bağlanmayı denemiyorsun? Başarısız olursa, bağlantı noktasının mevcut olmadığını anlarsınız.


4
TOCTOU, YALAIHHOBIKTPBI'dir (Henüz Duymadığım Başka Bir Uzun Kısaltma, Ama Arkasındaki Fenomenleri Biliyorum)
Csaba Toth

1

Bazı uzak TCP hizmetlerine bağlanmak için yerel makinenizde hangi bağlantı noktalarının açık olduğunu bilmeniz gerekmez (belirli bir yerel bağlantı noktası kullanmak istemiyorsanız, ancak genellikle durum böyle değildir).

Her TCP / IP bağlantısı 4 değerle tanımlanır: uzak IP, uzak bağlantı noktası numarası, yerel IP, yerel bağlantı noktası numarası, ancak bir bağlantı kurmak için yalnızca uzak IP ve uzak bağlantı noktası numarasını bilmeniz gerekir.

Kullanarak tcp bağlantısı oluşturduğunuzda

TcpClient c;
c = new TcpClient (uzak_ip, uzak_port);

Sisteminiz, bağlantınıza birçok ücretsiz yerel bağlantı noktası numarasından birini otomatik olarak atayacaktır. Hiçbir şey yapmanıza gerek yok. Uzak bir bağlantı noktasının açık olup olmadığını da kontrol etmek isteyebilirsiniz. ancak bunu yapmanın, ona bağlanmaya çalışmaktan daha iyi bir yolu yoktur.


Bu, verilen bir dizi soketi kontrol etmek için iyidir. Soru sadece bir soket hakkında (hangi bağlantı noktası numarası belirlenememiş olabilir (?))
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
Bir kod gönderirken, sorunun neden çözüm olduğunu açıklamaya çalışın. Sadece kod çok az bilgi olabilir ve cevabınızın gözden geçirilme riski vardır.
Glubus

0

10048 hata kodunu kontrol edin

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

bunu deneyin, benim durumumda oluşturulan nesnenin bağlantı noktası numarası mevcut değildi, bu yüzden bunu buldum

IPEndPoint endPoint;
int port = 1;
while (true)
{
    try
    {
        endPoint = new IPEndPoint(IPAddress.Any, port);
        break;
    }
    catch (SocketException)
    {
         port++;
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.