Aşağıdakilerden hangisi Java'da mevcut bilgisayarın ana bilgisayar adını almanın en iyi ve en taşınabilir yoludur?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
Aşağıdakilerden hangisi Java'da mevcut bilgisayarın ana bilgisayar adını almanın en iyi ve en taşınabilir yoludur?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
Yanıtlar:
Kesinlikle konuşmak gerekirse - hostname(1)
Unix'te ya da --'dan birini çağırmaktan başka seçeneğiniz yok gethostname(2)
. Bu bilgisayarınızın adıdır. Ana bilgisayar adını böyle bir IP adresiyle belirleme girişimi
InetAddress.getLocalHost().getHostName()
bazı durumlarda başarısızlığa mahkumdur:
Ayrıca bir IP adresinin adını ana bilgisayar adıyla (ana bilgisayar adı) karıştırmayın. Bir metafor bunu daha açık hale getirebilir:
"Londra" adında büyük bir şehir (sunucu) var. Surların içinde çok iş var. Şehrin birkaç kapısı vardır (IP adresleri). Her kapının bir adı vardır ("Kuzey Kapısı", "Nehir Kapısı", "Southampton Kapısı" ...) ama kapının adı şehrin adı değildir. Ayrıca bir kapı adını kullanarak şehrin adını çıkaramazsınız - "Kuzey Kapısı" sadece bir şehri değil, büyük şehirlerin yarısını yakalardı. Ancak - bir yabancı (IP paketi) nehir boyunca yürür ve yerel bir sorar: "Garip bir adresim var: 'Rivergate, ikinci sol, üçüncü ev'. Bana yardım edebilir misin?" Yerel diyor ki: "Elbette, doğru yoldasınız, sadece devam edin ve hedefinize yarım saat içinde varacaksınız."
Sanırım bunu neredeyse gösteriyor.
İyi haber şu: Gerçek ana bilgisayar adı genellikle gerekli değildir. Çoğu durumda, bu ana bilgisayarda bir IP adresine çözümlenen herhangi bir ad kullanılır. (Yabancı şehre Northgate tarafından girebilir, ancak yardımsever yerliler "2. sol" kısmı tercüme ederler.)
Kalan köşe durumları varsa , bu yapılandırma ayarının kesin kaynağını kullanmalısınız - C işlevi gethostname(2)
. Bu fonksiyon program tarafından da çağrılır hostname
.
InetAddress.getLocalHost().getHostName()
daha taşınabilir bir yoldur.
exec("hostname")
aslında hostname
komutu çalıştırmak için işletim sistemini çağırır .
İşte SO ile ilgili diğer birkaç cevap:
DÜZENLEME: Durumunuza bağlı olarak bunun neden beklendiği gibi çalışmayabileceğine ilişkin ayrıntılar için AH'nin cevabına veya Arnout Engelen'in cevabına bir göz atmalısınız . Özellikle portatif talep eden bu kişi için bir cevap olarak, hala iyi olduğunu düşünüyorum getHostName()
, ancak dikkate alınması gereken bazı iyi noktalar getiriyorlar.
InetAddress.getLocalHost()
bazı durumlarda geri döngü aygıtı döndürür. Bu durumda, getHostName()
çok yararlı olmayan "localhost" döndürür.
Diğerlerinin de belirttiği gibi, ana bilgisayar adını DNS çözümlemesine göre almak güvenilir değildir.
Bu soru maalesef 2018'de hala alakalı olduğundan , farklı sistemlerde bazı test çalışmalarıyla ağdan bağımsız çözümümü sizinle paylaşmak istiyorum.
Aşağıdaki kod aşağıdakileri yapmaya çalışır:
Windows'ta
COMPUTERNAME
Ortam değişkenini aracılığıyla okuyun System.getenv()
.
hostname.exe
Yanıtı yürütün ve okuyun
Linux'ta
HOSTNAME
Ortam değişkenini şu yolla okuyun:System.getenv()
hostname
Yanıtı yürütün ve okuyun
Oku /etc/hostname
(bunu yapmak için yürütüyorumcat
için snippet zaten yürütmek ve okumak için kod içerdiğinden . Sadece dosyayı okumak daha iyi olsa da).
Kod:
public static void main(String[] args) throws IOException {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
System.out.println("Windows computer name through env:\"" + System.getenv("COMPUTERNAME") + "\"");
System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
} else if (os.contains("nix") || os.contains("nux") || os.contains("mac os x")) {
System.out.println("Unix-like computer name through env:\"" + System.getenv("HOSTNAME") + "\"");
System.out.println("Unix-like computer name through exec:\"" + execReadToString("hostname") + "\"");
System.out.println("Unix-like computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
}
}
public static String execReadToString(String execCommand) throws IOException {
try (Scanner s = new Scanner(Runtime.getRuntime().exec(execCommand).getInputStream()).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}
Farklı işletim sistemleri için sonuçlar:
macOS 10.13.2
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
OpenSuse 13.1
Unix-like computer name through env:"machinename"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
Ubuntu 14.04 LTSecho $HOSTNAME
Doğru ana bilgisayar adını döndürdüğü için
bu tür bir garip , ancak System.getenv("HOSTNAME")
şunları yapmıyor:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
DÜZENLEME: Legolas108'e göre ,System.getenv("HOSTNAME")
koşarsan Ubuntu 14.04 üzerinde çalışır export HOSTNAME
Java kodunu çalıştırmadan önce.
Windows 7
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
Windows 10
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
Makine adları değiştirildi ancak büyük / küçük harf kullanımını ve yapısını korudum. Yürütürken ekstra satırsonuna dikkat edin, hostname
bazı durumlarda bunu dikkate almanız gerekebilir.
export HOSTNAME
önce Ubuntu 14.04 LTS Java kodu çalıştırarak aynı zamanda tarafından döndürülür System.getenv("HOSTNAME")
.
export HOSTNAME
Java'nın kullanması için açıkça mi? PATH gibi varsayılan bir env var olması gerektiğini düşündüm.
\A
sınırlayıcı sadece a kullanarak tüm InputStream okumak için bir hack Scanner
.
InetAddress.getLocalHost().getHostName()
(Nick'in açıkladığı gibi) daha iyi, ama yine de çok iyi değil
Bir ana makine birçok farklı ana makine adı altında bilinir. Genellikle, barındırıcınızın belirli bir bağlamda sahip olduğu ana bilgisayar adını ararsınız.
Örneğin, bir web uygulamasında, şu anda yürütmekte olduğunuz isteği veren kişi tarafından kullanılan ana bilgisayar adını arıyor olabilirsiniz. Bunu en iyi nasıl bulacağınız, web uygulamanız için hangi çerçeveyi kullandığınıza bağlıdır.
İnternete yönelik başka bir tür hizmette, hizmetinizin ana bilgisayar adının 'dışarıdan' erişilebilir olmasını istersiniz. Proxy'ler, güvenlik duvarları vb. Nedeniyle, hizmetinizin yüklü olduğu makinede bir ana makine adı bile olmayabilir - makul bir varsayılan bulmaya çalışabilirsiniz, ancak bunu yükleyen herkes için kesinlikle yapılandırılabilir hale getirmelisiniz.
Bu konu zaten cevaplanmış olsa da söylenecek daha çok şey var.
Her şeyden önce: Burada bazı tanımlara ihtiyacımız var. InetAddress.getLocalHost().getHostName()
Size konağın adını veren bir ağ perspektifinden görüldüğü gibi . Bu yaklaşımla ilgili sorunlar diğer cevaplarda iyi belgelenmiştir: genellikle bir DNS araması gerektirir, ana bilgisayarın birden çok ağ arabirimi varsa belirsizdir ve bazen basitçe başarısız olur (aşağıya bakın).
Ancak herhangi bir işletim sisteminde başka bir isim de var. Ağ başlatılmadan çok önce, önyükleme işleminde çok erken tanımlanan ana bilgisayarın adı. , Windows olarak adlandırır bilgisayaradı , Linux onu çağırır Hostadı çekirdek ve Solaris kelime kullanır nodename . Bilgisayar adı kelimesini en iyi şekilde sevdim, bundan sonra bu kelimeyi kullanacağım.
Linux / Unix'te bilgisayar adı, C işlevinden gethostname()
veya Bash benzeri kabuklardaki hostname
kabuk veya HOSTNAME
ortam değişkeninden komut alır .
Windows'ta bilgisayar adı, ortam değişkeni COMPUTERNAME
veya Win32 GetComputerName
işlevinden elde ettiğiniz addır .
Java'nın 'bilgisayaradı' olarak tanımladığım şeyi elde etmenin bir yolu yoktur. Elbette, Windows çağrısı gibi diğer yanıtlarda açıklandığı gibi geçici çözümler vardır System.getenv("COMPUTERNAME")
, ancak Unix / Linux'ta JNI / JNA veya 'ya başvurmadan iyi bir geçici çözüm yoktur Runtime.exec()
. Bir JNI / JNA çözümüne aldırmazsanız , ölü basit ve kullanımı çok kolay olan gethostname4j var .
Biri Linux ve diğeri Solaris'ten olmak üzere iki örnekle devam edelim, bu da standart Java yöntemlerini kullanarak bilgisayar adını nasıl elde edemeyeceğinize kolayca nasıl ulaşabileceğinizi gösterir.
Yükleme sırasında ana bilgisayarın 'chicago' olarak adlandırıldığı yeni oluşturulan bir sistemde, şimdi çekirdek ana makine adını değiştiriyoruz:
$ hostnamectl --static set-hostname dallas
Artık ana makine adı komutundan da anlaşılacağı üzere çekirdek ana makine adı 'dallas':
$ hostname
dallas
Ama hala var
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
Bunda yanlış bir yapılandırma yok. Bu yalnızca ana bilgisayarın ağa bağlı adının (veya geri döngü arayüzünün adının) ana bilgisayarın bilgisayar adından farklı olduğu anlamına gelir.
Şimdi, çalıştırmayı deneyin InetAddress.getLocalHost().getHostName()
ve java.net.UnknownHostException atar. Temelde sıkışıp kaldınız. Ne 'dallas' değerini ne de 'chicago' değerini almanın bir yolu yoktur.
Aşağıdaki örnek Solaris 11.3'e dayanmaktadır.
Ana bilgisayar, geri döngü adı <> nodename olacak şekilde kasıtlı olarak yapılandırılmıştır.
Başka bir deyişle:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
ve / etc / hosts öğelerinin içeriği:
:1 chicago localhost
127.0.0.1 chicago localhost loghost
ve hostname komutunun sonucu:
$ hostname
dallas
Sadece Linux örnekte bir çağrı gibi InetAddress.getLocalHost().getHostName()
başarısız olur
java.net.UnknownHostException: dallas: dallas: node name or service name not known
Tıpkı Linux örneği gibi, artık sıkışıp kaldınız. Ne 'dallas' değerini ne de 'chicago' değerini almanın bir yolu yoktur.
Çoğu zaman InetAddress.getLocalHost().getHostName()
bunun gerçekten bilgisayar adına eşit bir değer döndüreceğini göreceksiniz . Yani sorun yok (isim çözümünün ek yükü hariç).
Sorun genellikle bilgisayar adı ve geridöngü arabiriminin adı arasında bir fark olduğu PaaS ortamlarında ortaya çıkar. Örneğin, insanlar Amazon EC2'deki sorunları bildiriyor.
Biraz arama şu RFE raporunu ortaya çıkarır: link1 , link2 . Bununla birlikte, bu rapordaki yorumlardan yola çıkarak, sorunun JDK ekibi tarafından büyük ölçüde yanlış anlaşıldığı görülüyor, bu yüzden ele alınması muhtemel değildir.
RFE'deki diğer programlama dilleriyle karşılaştırmayı seviyorum.
Ortam değişkenleri de yararlı bir yol sağlayabilir - COMPUTERNAME
Windows'ta,HOSTNAME
çoğu modern Unix / Linux kabuğunda .
Bkz. Https://stackoverflow.com/a/17956000/768795
Bunları "ek" yöntemler olarak kullanıyorum InetAddress.getLocalHost().getHostName()
, çünkü birkaç kişinin işaret ettiği gibi, bu işlev tüm ortamlarda çalışmaz.
Runtime.getRuntime().exec("hostname")
başka bir olası ek. Bu aşamada hiç kullanmadım.
import java.net.InetAddress;
import java.net.UnknownHostException;
// try InetAddress.LocalHost first;
// NOTE -- InetAddress.getLocalHost().getHostName() will not work in certain environments.
try {
String result = InetAddress.getLocalHost().getHostName();
if (StringUtils.isNotEmpty( result))
return result;
} catch (UnknownHostException e) {
// failed; try alternate means.
}
// try environment properties.
//
String host = System.getenv("COMPUTERNAME");
if (host != null)
return host;
host = System.getenv("HOSTNAME");
if (host != null)
return host;
// undetermined.
return null;
StringUtils
, Apache commons-lang projesi tarafından sağlanır. Bunu veya bunun gibi bir şeyi kullanmanız şiddetle tavsiye edilir.
System.getenv("HOSTNAME")
Java için Beanshell aracılığıyla Mac'te null çıktı, ancak PATH
tamam çıkarıldı. echo $HOSTNAME
Mac'te de yapabilirim , sadece System.getenv ("HOSTNAME") sorunu var gibi görünüyor. Garip.
Geçerli bilgisayarın ana bilgisayar adını Java'da almanın en taşınabilir yolu aşağıdaki gibidir:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class getHostName {
public static void main(String[] args) throws UnknownHostException {
InetAddress iAddress = InetAddress.getLocalHost();
String hostName = iAddress.getHostName();
//To get the Canonical host name
String canonicalHostName = iAddress.getCanonicalHostName();
System.out.println("HostName:" + hostName);
System.out.println("Canonical Host Name:" + canonicalHostName);
}
}
Eğer maven central'ın harici bir bağımlılığını kullanmaya karşı değilseniz, bu sorunu kendim çözmek için gethostname4j yazdım. Sadece libc'nin gethostname işlevini çağırmak için JNA kullanır (veya Windows'ta BilgisayarAdı alır) ve size bir dize olarak döndürür.
hostName == null;
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
{
while (interfaces.hasMoreElements()) {
NetworkInterface nic = interfaces.nextElement();
Enumeration<InetAddress> addresses = nic.getInetAddresses();
while (hostName == null && addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (!address.isLoopbackAddress()) {
hostName = address.getHostName();
}
}
}
}
Sadece bir astarlı ... çapraz platform (Windows-Linux-Unix-Mac (Unix)) [Her zaman çalışır, DNS gerekmez]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
Sen bittin !!
InetAddress.getLocalHost (). GetHostName (), geliştirici düzeyindeki en iyi soyutlama olduğundan ikisinin en iyi yoludur.