ใน C # เพื่อใช้ TcpClient หรือโดยทั่วไปเพื่อเชื่อมต่อกับซ็อกเก็ตฉันจะตรวจสอบก่อนว่าพอร์ตบางพอร์ตว่างบนเครื่องของฉันได้อย่างไร?
ข้อมูลเพิ่มเติม: นี่คือรหัสที่ฉันใช้:
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
ใน C # เพื่อใช้ TcpClient หรือโดยทั่วไปเพื่อเชื่อมต่อกับซ็อกเก็ตฉันจะตรวจสอบก่อนว่าพอร์ตบางพอร์ตว่างบนเครื่องของฉันได้อย่างไร?
ข้อมูลเพิ่มเติม: นี่คือรหัสที่ฉันใช้:
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
คำตอบ:
เนื่องจากคุณใช้ a 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.
netstat -a -b
เปรียบเทียบผลของรหัสดังกล่าวไปที่ โปรดสังเกตว่าไม่มีLISTENING
การเชื่อมต่อในไฟล์GetActiveTcpConnections()
. คุณควรเช็คอินที่System.Net.IPEndPoints[]
ส่งคืนภายในipGlobalProperties.GetActiveTcpListeners();
คุณอยู่ผิดจุดสิ้นสุดของ 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");
}
ล้มเหลวด้วย:
โดยปกติอนุญาตให้ใช้ที่อยู่ซ็อกเก็ตแต่ละอันเท่านั้น (โปรโตคอล / ที่อยู่เครือข่าย / พอร์ต) เท่านั้น
เมื่อคุณตั้งค่าการเชื่อมต่อ TCP 4-tuple (source-ip, source-port, dest-ip, dest-port) จะต้องไม่ซ้ำกัน - เพื่อให้แน่ใจว่าแพ็กเก็ตจะถูกส่งไปยังตำแหน่งที่ถูกต้อง
มีข้อ จำกัด เพิ่มเติมในฝั่งเซิร์ฟเวอร์ที่มีเพียงโปรแกรมเซิร์ฟเวอร์เดียวเท่านั้นที่สามารถผูกกับหมายเลขพอร์ตขาเข้าได้ (สมมติว่ามีที่อยู่ IP เดียวเซิร์ฟเวอร์หลาย NIC มีอำนาจอื่น ๆ แต่เราไม่จำเป็นต้องพูดถึงที่นี่)
ดังนั้นในตอนท้ายของเซิร์ฟเวอร์คุณ:
ในตอนท้ายของไคลเอนต์มักจะง่ายกว่าเล็กน้อย:
นอกจากนี้ไม่มีความต้องการที่ปลายทาง IP / พอร์ตจะไม่ซ้ำกันเนื่องจากว่าจะส่งผลให้เพียงคนเดียวในช่วงเวลาที่ความสามารถในการใช้ Google และที่สวยดีจะทำลายรูปแบบธุรกิจของพวกเขา
ซึ่งหมายความว่าคุณสามารถทำสิ่งมหัศจรรย์เช่น FTP แบบหลายเซสชันได้เนื่องจากคุณตั้งค่าหลายเซสชันซึ่งความแตกต่างเพียงอย่างเดียวคือพอร์ตต้นทางของคุณทำให้คุณสามารถดาวน์โหลดชิ้นส่วนแบบขนานได้ Torrents มีความแตกต่างกันเล็กน้อยโดยที่ปลายทางของแต่ละเซสชันมักจะแตกต่างกัน
และหลังจากทั้งหมดวาฟเฟิล (ขออภัย) คำตอบสำหรับคำถามเฉพาะของคุณคือคุณไม่จำเป็นต้องระบุพอร์ตฟรี หากคุณกำลังเชื่อมต่อกับเซิร์ฟเวอร์ด้วยการโทรที่ไม่ได้ระบุพอร์ตต้นทางของคุณมันแทบจะใช้ศูนย์ภายใต้ฝาปิดและระบบจะให้สิ่งที่ไม่ได้ใช้กับคุณ
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
... ฉันจะตรวจสอบก่อนว่าพอร์ตบางพอร์ตว่างบนเครื่องของฉันได้อย่างไร?
ฉันหมายความว่าไม่มีการใช้งานโดยแอปพลิเคชันอื่นใด หากแอปพลิเคชันใช้พอร์ตอื่นจะไม่สามารถใช้งานได้จนกว่าจะว่าง - อาลี
คุณเข้าใจผิดว่าเกิดอะไรขึ้นที่นี่
พารามิเตอร์ TcpClient (... ) เป็นของเซิร์ฟเวอร์ ip และพอร์ตเซิร์ฟเวอร์ที่คุณต้องการเชื่อมต่อ
TcpClient เลือกพอร์ตโลคัลชั่วคราวจากพูลที่พร้อมใช้งานเพื่อสื่อสารกับเซิร์ฟเวอร์ ไม่จำเป็นต้องตรวจสอบความพร้อมใช้งานของพอร์ตโลคัลเนื่องจากมีการจัดการโดยเลเยอร์ Winsock โดยอัตโนมัติ
ในกรณีที่คุณไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์โดยใช้ส่วนของโค้ดด้านบนปัญหาอาจเกิดจากหลายอย่าง (เช่นเซิร์ฟเวอร์ ip และ / หรือพอร์ตผิดเซิร์ฟเวอร์ระยะไกลไม่พร้อมใช้งาน ฯลฯ .. )
ขอบคุณสำหรับเคล็ดลับนี้ ฉันต้องการฟังก์ชันเดียวกัน แต่ในฝั่งเซิร์ฟเวอร์เพื่อตรวจสอบว่ามีการใช้พอร์ตหรือไม่ดังนั้นฉันจึงแก้ไขเป็นรหัสนี้
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;
}
-anb
) และไม่มีพารามิเตอร์ใด ๆ จะแสดงการเชื่อมต่อต่างประเทศเช่นเดียวกับสถานะ
ขอบคุณสำหรับคำตอบ jro ฉันต้องปรับแต่งสำหรับการใช้งานของฉัน ฉันต้องการตรวจสอบว่ามีการรับฟังพอร์ตหรือไม่และไม่จำเป็นต้องเปิดใช้งาน สำหรับสิ่งนี้ฉันแทนที่
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
กับ
IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.
ฉันทำซ้ำอาร์เรย์ของปลายทางเพื่อตรวจสอบว่าไม่พบค่าพอร์ตของฉัน
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);
}
netstat! นั่นคือยูทิลิตี้บรรทัดคำสั่งเครือข่ายที่มาพร้อมกับ windows จะแสดงการเชื่อมต่อที่สร้างขึ้นในปัจจุบันทั้งหมดและพอร์ตทั้งหมดที่กำลังรับฟังอยู่ คุณสามารถใช้โปรแกรมนี้เพื่อตรวจสอบได้ แต่ถ้าคุณต้องการทำสิ่งนี้จากการดูโค้ดในเนมสเปซ System.Net.NetworkInformation? เป็นเนมสเปซใหม่ตั้งแต่ 2.0 มีสินค้ามากมายที่นั่น แต่ในที่สุดถ้าคุณต้องการรับข้อมูลประเภทเดียวกันที่มีอยู่ผ่านคำสั่ง netstat คุณจะต้องส่งผลให้ P / Invoke ...
เนมสเปซนั้นมีคลาสมากมายที่คุณสามารถใช้เพื่อค้นหาสิ่งต่างๆเกี่ยวกับเครือข่าย
ฉันไม่พบรหัสเก่า ๆ นั้น แต่ฉันคิดว่าคุณสามารถเขียนสิ่งที่คล้ายกันได้ด้วยตัวเอง เริ่มต้นที่ดีคือการตรวจสอบIP Helper API Google MSDN สำหรับ ฟังก์ชันGetTcpTable WINAPI และใช้ P / Invoke เพื่อแจกแจงจนกว่าคุณจะมีข้อมูลที่ต้องการ
ถ้าฉันไม่เข้าใจผิดมากนักคุณสามารถใช้ System.Network.w ก็ได้เพื่อตรวจสอบ
อย่างไรก็ตามสิ่งนี้จะเกิดขึ้นกับสภาพการแข่งขันเสมอ
วิธีการตรวจสอบมาตรฐานคือลองฟังจากพอร์ตนั้น หากคุณได้รับข้อผิดพลาดว่าพอร์ตไม่เปิด
ฉันคิดว่านี่เป็นส่วนหนึ่งของสาเหตุที่ bind () และ listen () เป็นการเรียกระบบสองสายที่แยกจากกัน
คุณพูด
ฉันหมายความว่าไม่ได้ใช้งานโดยแอปพลิเคชันอื่นใด หากแอปพลิเคชันใช้พอร์ตอื่นจะไม่สามารถใช้งานได้จนกว่าจะว่าง
แต่คุณสามารถเชื่อมต่อกับพอร์ตได้ตลอดเวลาในขณะที่คนอื่นกำลังใช้งานอยู่หากมีบางสิ่งกำลังฟังอยู่ มิฉะนั้น http พอร์ต 80 จะเป็นระเบียบ
ถ้าคุณ
c = new TcpClient(ip, port);
ล้มเหลวแล้วไม่มีอะไรฟังที่นั่น มิฉะนั้นจะเชื่อมต่อแม้ว่าเครื่อง / แอปพลิเคชันอื่น ๆ จะมีซ็อกเก็ตที่เปิดไปยัง ip และพอร์ตนั้น
ipGlobalProperties.GetActiveTcpConnections()
ไม่ส่งคืนการเชื่อมต่อใน Listen State
สามารถใช้พอร์ตสำหรับการฟังได้ แต่ไม่มีใครเชื่อมต่อกับมันวิธีการที่อธิบายไว้ข้างต้นจะไม่ได้ผล
จากพอร์ตที่พร้อมใช้งานฉันจะไม่รวม:
ด้วยการนำเข้าต่อไปนี้:
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
เพื่อตอบคำถามที่แน่นอนในการค้นหาพอร์ตฟรี (ซึ่งเป็นสิ่งที่ฉันต้องการในการทดสอบหน่วยของฉัน) ใน 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 เกี่ยวกับพอร์ตศูนย์ฉันค้นหาและพบสิ่งนี้และแก้ไขเล็กน้อย
โปรดทราบหน้าต่างเวลาระหว่างที่คุณทำการตรวจสอบและขณะที่คุณพยายามที่จะทำให้การเชื่อมต่อกระบวนการบางอย่างอาจใช้พอร์ต - คลาสสิกTOCTOU ทำไมคุณไม่ลองเชื่อมต่อดูล่ะ? หากล้มเหลวแสดงว่าคุณทราบว่าไม่มีพอร์ต
คุณไม่จำเป็นต้องรู้ว่าพอร์ตใดที่เปิดอยู่ในเครื่องของคุณเพื่อเชื่อมต่อกับบริการ TCP ระยะไกลบางอย่าง (เว้นแต่คุณต้องการใช้พอร์ตโลคัลเฉพาะ แต่โดยปกติจะไม่เป็นเช่นนั้น)
ทุกการเชื่อมต่อ TCP / IP จะระบุด้วยค่า 4 ค่า ได้แก่ IP ระยะไกลหมายเลขพอร์ตระยะไกล IP ในเครื่องหมายเลขพอร์ตภายในเครื่อง แต่คุณจำเป็นต้องทราบเฉพาะ IP ระยะไกลและหมายเลขพอร์ตระยะไกลเพื่อสร้างการเชื่อมต่อ
เมื่อคุณสร้างการเชื่อมต่อ tcp โดยใช้
TcpClient c; c = TcpClient ใหม่ (remote_ip, remote_port);
ระบบของคุณจะกำหนดหมายเลขพอร์ตภายในที่ไม่เสียค่าใช้จ่ายให้กับการเชื่อมต่อของคุณโดยอัตโนมัติ คุณไม่จำเป็นต้องทำอะไร คุณอาจต้องการตรวจสอบว่าพอร์ตระยะไกลเปิดอยู่หรือไม่ แต่ไม่มีวิธีใดดีไปกว่าการพยายามเชื่อมต่อ
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;
}
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.");
}
}
}
ตรวจสอบรหัสข้อผิดพลาด 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;
}
ลองทำเช่นนี้ในกรณีของฉันหมายเลขพอร์ตสำหรับวัตถุที่สร้างขึ้นไม่พร้อมใช้งานดังนั้นฉันจึงคิดสิ่งนี้ขึ้นมา
IPEndPoint endPoint;
int port = 1;
while (true)
{
try
{
endPoint = new IPEndPoint(IPAddress.Any, port);
break;
}
catch (SocketException)
{
port++;
}
}