Di C #, bagaimana cara memeriksa apakah port TCP tersedia?

120

Dalam C # untuk menggunakan TcpClient atau secara umum untuk menghubungkan ke soket, bagaimana saya bisa pertama kali memeriksa apakah port tertentu gratis di mesin saya?

info lebih lanjut: Ini adalah kode yang saya gunakan:

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
Ali
sumber
2
Apa yang Anda maksud dengan "gratis" di sini? Jika Anda mencoba menyambungkannya dan gagal, itu mungkin berarti tidak ada yang mendengarkan.
Jon Skeet
2
Maksud saya, ini tidak digunakan oleh aplikasi lain. Jika aplikasi menggunakan port, orang lain tidak dapat menggunakannya hingga gratis.
Ali
Apa server yang Anda coba sambungkan? Apakah Anda menulisnya, atau apakah itu server yang sudah ada?
berduka
3
Seperti yang telah dinyatakan dalam banyak jawaban, Anda memiliki segalanya mundur. Porta lokal dan port jarak jauh adalah dua hal yang sama sekali berbeda. Jawaban ini secara khusus menjelaskannya dengan baik: stackoverflow.com/questions/570098/…
bzlm

Jawaban:

217

Karena Anda menggunakan a TcpClient, itu berarti Anda memeriksa port TCP terbuka. Ada banyak objek bagus yang tersedia di namespace System.Net.NetworkInformation .

Gunakan IPGlobalPropertiesobjek tersebut untuk mendapatkan larik TcpConnectionInformationobjek, yang kemudian dapat Anda interogasi tentang IP dan port titik akhir.


 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.
jro
sumber
38
Ingatlah bahwa proses lain dapat mengikat port itu saat Anda memeriksa.
Serguei
2
Bagaimana ini relevan dengan pertanyaan? Jawaban ini berkaitan dengan port lokal , bukan port jarak jauh .
bzlm
6
Relevan karena menjawab permintaan OP. Terlepas dari perbedaan lokal / jarak jauh (sangat setuju dengan Anda), persyaratan OP adalah membuat TcpClient baru dengan port yang "gratis".
jro
8
Perhatikan bahwa kode ini hanya memeriksa koneksi yang aktif. Koneksi yang belum mengirim atau menerima paket tidak akan dicantumkan.
JoeBilly
29
Bandingkan hasil kode di atas dengan netstat -a -b. Perhatikan bahwa LISTENINGkoneksi tidak ada di file GetActiveTcpConnections(). Anda juga harus check-in System.Net.IPEndPoints[]dikembalikan olehipGlobalProperties.GetActiveTcpListeners();
Mike de Klerk
44

Anda berada di ujung Intertube yang salah. Ini adalah server yang hanya dapat membuka satu port tertentu. Beberapa kode:

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

Gagal dengan:

Hanya satu penggunaan dari setiap alamat soket (protokol / alamat jaringan / port) yang biasanya diizinkan.

Hans Passant
sumber
Di situlah saya pergi dengan itu juga. Seseorang pasti bingung di sini, dan mungkin itu saya.
Moose
3
Ada kemungkinan bahwa klien memerlukan port tertentu juga, tetapi itu tidak umum.
Dave Van den Eynde
@DaveVandenEynde yang hanya dapat terjadi jika "klien" sebenarnya "melayani" sesuatu pada port tertentu itu (menjadikannya "server", setidaknya untuk port itu, sejauh menyangkut TCP). - Ketika Anda memiliki koneksi TCP klien, Anda tidak bisa mengontrol port keluar. Tumpukan TCP memberi Anda port keluar, dan Anda tidak memiliki kontrol apa pun atasnya.
BrainSlugs83
1
@ BrainSlugs83 Anda pasti bisa: stackoverflow.com/questions/2869840/…
Dave Van den Eynde
Ini adalah kode yang valid untuk memeriksa apakah porta gratis. Ingatlah untuk Menghentikan () TcpListener jika berhasil (kecuali jika Anda bermaksud menggunakan objek TcpListener yang sama untuk mulai mendengarkan di port).
bgh
19

Saat Anda mengatur koneksi TCP, 4-tuple (source-ip, source-port, dest-ip, dest-port) harus unik - ini untuk memastikan paket dikirimkan ke tempat yang tepat.

Ada batasan lebih lanjut di sisi server bahwa hanya satu program server yang dapat mengikat ke nomor port masuk (dengan asumsi satu alamat IP; server multi-NIC memiliki kekuatan lain tetapi kami tidak perlu membahasnya di sini).

Jadi, di ujung server, Anda:

  • buat soket.
  • ikat soket itu ke port.
  • dengarkan di pelabuhan itu.
  • menerima koneksi di port itu. dan mungkin ada beberapa koneksi yang masuk (satu per klien).

Di sisi klien, biasanya sedikit lebih sederhana:

  • buat soket.
  • buka koneksi. Ketika klien membuka koneksi, itu menentukan alamat ip dan port server . Ia dapat menentukan port sumbernya tetapi biasanya menggunakan nol yang mengakibatkan sistem menetapkannya sebagai port bebas secara otomatis.

Tidak ada persyaratan bahwa IP / port tujuan harus unik karena hanya akan menghasilkan satu orang pada satu waktu yang dapat menggunakan Google, dan itu akan menghancurkan model bisnis mereka.

Ini berarti Anda bahkan dapat melakukan hal-hal menakjubkan seperti FTP multi-sesi karena Anda mengatur beberapa sesi di mana satu-satunya perbedaan adalah port sumber Anda, memungkinkan Anda mengunduh potongan secara paralel. Torrent sedikit berbeda karena tujuan tiap sesi biasanya berbeda.

Dan, setelah semua omong kosong itu (maaf), jawaban atas pertanyaan spesifik Anda adalah Anda tidak perlu menentukan port gratis. Jika Anda terhubung ke server dengan panggilan yang tidak menentukan port sumber Anda, itu hampir pasti akan menggunakan nol di bawah selimut dan sistem akan memberi Anda yang tidak terpakai.

paxdiablo
sumber
15
TcpClient c;

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

... bagaimana saya bisa pertama kali memeriksa apakah port tertentu gratis di mesin saya?

Maksud saya, ini tidak digunakan oleh aplikasi lain. Jika sebuah aplikasi menggunakan port, orang lain tidak dapat menggunakannya hingga menjadi gratis. - Ali

Anda telah salah paham tentang apa yang terjadi di sini.

Parameter TcpClient (...) adalah ip server dan port server yang ingin Anda sambungkan.

TcpClient memilih port lokal sementara dari pool yang tersedia untuk berkomunikasi ke server. Tidak perlu memeriksa ketersediaan porta lokal karena secara otomatis ditangani oleh lapisan winsock.

Jika Anda tidak dapat terhubung ke server menggunakan fragmen kode di atas, masalahnya mungkin satu atau lebih dari beberapa. (mis. ip dan / atau port server salah, server jarak jauh tidak tersedia, dll ..)

Indy9000
sumber
15

Terima kasih atas tip ini. Saya membutuhkan fungsionalitas yang sama tetapi di sisi Server untuk memeriksa apakah Port sedang digunakan, jadi saya memodifikasinya ke kode ini.

 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;
}
Melloware
sumber
Anda tidak membutuhkan ini. Tentukan saja port nol.
Marquis dari Lorne
Catatan dalam komentar kode sumber: "Ini adalah informasi yang sama yang disediakan oleh aplikasi baris perintah netstat" - adalah bohong. Ini tidak memberikan informasi yang sama karena perintah netstat juga menyediakan PID aplikasi menggunakan port ( -anb) dan tanpa parameter apapun itu menunjukkan koneksi Asing serta status.
Kraang Prime
6

terima kasih atas jawabannya jro. Saya harus menyesuaikannya untuk penggunaan saya. Saya perlu memeriksa apakah port sedang didengarkan, dan tidak perlu aktif. Untuk ini saya ganti

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

dengan

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

Saya mengulang array titik akhir untuk memeriksa bahwa nilai port saya tidak ditemukan.

pengguna336046
sumber
Coba saja dengarkan sendiri. Anda tidak membutuhkan semua ini.
Marquis dari 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);
}
Belajar
sumber
Akulah yang mencoba menyambung ke soket. Saya telah mengedit pertanyaan agar lebih jelas.
Ali
Saya paling suka kode ini, ini benar-benar membuka koneksi TCP ke soket hanya untuk mengintip jika seseorang mendengarkan di ujung lain atau tidak. Dan saya pikir banyak orang benar-benar menginginkan ini, ketika mereka ingin "menguji apakah sebuah port terbuka pada host jarak jauh". Namun ada bug dalam kode di atas: if (sock.Connected == true) maka port terbuka untuk koneksi, beberapa perangkat lunak mirip server mendengarkan di sana. Jika ada SocketException dengan 10061 ErrorCode (pesan "(0x80004005): Tidak ada koneksi yang dapat dibuat karena mesin target secara aktif menolaknya" maka port ditutup!
Csaba Toth
Jadi sebaliknya di potongan kode. Catatan lain: jika seseorang mencoba Dns.GetHostEntry dalam pengaturan pengujian seperti itu di mana Anda memiliki server virtual dengan hanya alamat IP, Anda akan mendapat pengecualian.
Csaba Toth
3

netstat! Itu adalah utilitas baris perintah jaringan yang dikirimkan bersama windows. Ini menunjukkan semua koneksi yang dibuat saat ini dan semua port yang saat ini sedang didengarkan. Anda dapat menggunakan program ini untuk memeriksa, tetapi jika Anda ingin melakukan ini dari kode lihat ke namespace System.Net.NetworkInformation? Ini adalah namespace baru mulai 2.0. Ada beberapa barang di sana. Tetapi pada akhirnya jika Anda ingin mendapatkan jenis informasi yang sama yang tersedia melalui perintah netstat, Anda harus menghasilkan P / Invoke ...

Pembaruan: System.Net.NetworkInformation

Namespace itu berisi sekumpulan kelas yang dapat Anda gunakan untuk mencari tahu hal-hal tentang jaringan.

Saya tidak dapat menemukan potongan kode lama itu tetapi saya pikir Anda dapat menulis sesuatu yang serupa sendiri. Awal yang baik adalah memeriksa API Pembantu IP . Google MSDN untuk fungsi GetTcpTable WINAPI dan gunakan P / Invoke untuk menghitung sampai Anda memiliki informasi yang Anda butuhkan.

John Leidegren
sumber
Saya menggunakan .NET 3.5 dan saya tidak bisa mendenda itu.
Ali
Izinkan saya melakukannya untuk Anda: msdn.microsoft.com/en-us/library/…
bzlm
3

Jika saya tidak terlalu salah, Anda dapat menggunakan System.Network. Apa pun untuk diperiksa.

Namun hal tersebut akan selalu menimbulkan kondisi balapan.

Cara pemeriksaan kanonik adalah mencoba mendengarkan pada port itu. Jika Anda mendapatkan kesalahan, port tidak terbuka.

Saya pikir ini adalah bagian dari mengapa bind () dan listen () adalah dua panggilan sistem yang terpisah.

Joshua
sumber
2

Kamu bilang

Maksud saya, ini tidak digunakan oleh aplikasi lain. Jika aplikasi menggunakan port, orang lain tidak dapat menggunakannya hingga gratis.

Tetapi Anda selalu dapat terhubung ke port sementara orang lain menggunakannya jika ada sesuatu yang mendengarkan di sana. Jika tidak, port http 80 akan berantakan.

Jika Anda

   c = new TcpClient(ip, port);

gagal, maka tidak ada yang mendengarkan di sana. Jika tidak, itu akan terhubung, bahkan jika beberapa mesin / aplikasi lain memiliki soket yang terbuka ke ip dan port tersebut.

Moose
sumber
Jika aplikasi saya mencoba untuk terhubung menggunakan port 10 dan contoh lain dari aplikasi saya mencoba untuk menghubungkan menggunakan port 10 lagi itu akan gagal karena kedua aplikasi tidak dapat mengirim data menggunakan satu port, ketika datang untuk menerima data yaitu port 80 yang berbeda
Ali
apa bedanya? apa yang mendengarkan pada port 10 untuk aplikasi Anda?
Moose
jika gagal ketika instance kedua mencoba untuk terhubung, itu adalah aplikasi yang mendengarkan, bukan aplikasi Anda.
Moose
2

ipGlobalProperties.GetActiveTcpConnections() tidak mengembalikan koneksi dalam Status Dengar.

Port dapat digunakan untuk mendengarkan, tetapi tanpa ada yang terhubung dengannya, metode yang dijelaskan di atas tidak akan berfungsi.

Tevo D
sumber
Metode mana yang dijelaskan di atas? Bagaimana ini menjawab pertanyaan?
Marquis dari Lorne
2

Dari port yang tersedia saya akan mengecualikan:

  • koneksi TCP aktif
  • pendengar TCP aktif
  • pendengar UDP aktif

Dengan impor berikut:

using System.Net.NetworkInformation;

Anda dapat menggunakan fungsi berikut untuk memeriksa apakah port tersedia atau tidak:

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

Saya memberi Anda fungsi serupa untuk mereka yang menggunakan 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
Simone
sumber
2

Untuk menjawab pertanyaan pasti tentang menemukan port gratis (yang saya butuhkan dalam pengujian unit saya) di dotnet core 3.1, saya membuat ini

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

catatan: berdasarkan komentar oleh @ user207421 tentang port nol saya mencari dan menemukan ini dan sedikit memodifikasinya.

CCondron
sumber
1

Perhatikan jendela waktu antara Anda membuat cek dan saat Anda mencoba membuat koneksi, beberapa proses mungkin memerlukan port - TOCTOU klasik . Mengapa Anda tidak mencoba terhubung saja? Jika gagal maka Anda tahu port tersebut tidak tersedia.

ya23
sumber
4
TOCTOU adalah YALAIHHOBIKTPBI (Singkatan Panjang Lagi yang Belum Saya Dengar, Tapi Saya Tahu Fenomena di Baliknya)
Csaba Toth
1

Anda tidak perlu mengetahui port apa yang terbuka di komputer lokal Anda untuk terhubung ke beberapa layanan TCP jarak jauh (kecuali Anda ingin menggunakan porta lokal tertentu, tetapi biasanya tidak demikian).

Setiap koneksi TCP / IP diidentifikasi oleh 4 nilai: IP jarak jauh, nomor port jarak jauh, IP lokal, nomor port lokal, tetapi Anda hanya perlu mengetahui IP jarak jauh dan nomor port jarak jauh untuk membuat sambungan.

Saat Anda membuat koneksi tcp menggunakan

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

Sistem Anda akan secara otomatis menetapkan salah satu dari banyak nomor porta lokal gratis ke koneksi Anda. Anda tidak perlu melakukan apapun. Anda mungkin juga ingin memeriksa apakah port jarak jauh terbuka. tetapi tidak ada cara yang lebih baik untuk melakukan itu selain mencoba menghubungkannya.

Michał Piaskowski
sumber
Itu bagus untuk memeriksa satu set soket yang diberikan. Pertanyaannya adalah tentang hanya satu soket (meskipun nomor port mana yang mungkin tidak ditentukan (?))
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;
    }
Martin.Martinsson
sumber
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.");
   }
 }
}
Yuriy Stanchev
sumber
1
Saat memposting beberapa kode, coba jelaskan mengapa itu adalah solusi untuk masalah tersebut. Kode saja mungkin merupakan informasi yang terlalu sedikit dan jawaban Anda berisiko dilihat.
Glubus
0

Periksa kode kesalahan 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;
}
Mohsen
sumber
-2

coba ini, dalam kasus saya nomor port untuk objek yang dibuat tidak tersedia jadi saya datang dengan ini

IPEndPoint endPoint;
int port = 1;
while (true)
{
    try
    {
        endPoint = new IPEndPoint(IPAddress.Any, port);
        break;
    }
    catch (SocketException)
    {
         port++;
    }
}
shakram02
sumber