Manakah dari berikut ini adalah cara terbaik dan paling portabel untuk mendapatkan nama host dari komputer saat ini di Jawa?
Runtime.getRuntime().exec("hostname")
vs.
InetAddress.getLocalHost().getHostName()
Manakah dari berikut ini adalah cara terbaik dan paling portabel untuk mendapatkan nama host dari komputer saat ini di Jawa?
Runtime.getRuntime().exec("hostname")
vs.
InetAddress.getLocalHost().getHostName()
Jawaban:
Sebenarnya - Anda tidak punya pilihan selain memanggil salah satu hostname(1)
atau - di Unix gethostname(2)
. Ini adalah nama komputer Anda. Upaya apa pun untuk menentukan nama host oleh alamat IP seperti ini
InetAddress.getLocalHost().getHostName()
pasti gagal dalam beberapa keadaan:
Juga jangan bingung nama alamat IP dengan nama host (nama host). Metafora mungkin membuatnya lebih jelas:
Ada kota besar (server) yang disebut "London". Di dalam tembok kota banyak bisnis terjadi. Kota ini memiliki beberapa gerbang (alamat IP). Setiap gerbang memiliki nama ("Gerbang Utara", "Gerbang Sungai", "Gerbang Southampton" ...) tetapi nama gerbangnya bukan nama kota tersebut. Anda juga tidak dapat menyimpulkan nama kota dengan menggunakan nama gerbang - "Gerbang Utara" akan menangkap setengah dari kota-kota besar dan bukan hanya satu kota. Namun - seorang asing (paket IP) berjalan di sepanjang sungai dan bertanya kepada seorang warga setempat: "Saya punya alamat aneh: 'Rivergate, kiri kedua, rumah ketiga'. Bisakah Anda membantu saya?" Warga setempat mengatakan: "Tentu saja, Anda berada di jalan yang benar, silakan saja dan Anda akan tiba di tempat tujuan dalam waktu setengah jam."
Ini menggambarkannya menurut saya.
Kabar baiknya adalah: The nyata hostname ini biasanya tidak diperlukan. Dalam kebanyakan kasus, nama apa pun yang berubah menjadi alamat IP pada host ini akan dilakukan. (Orang asing itu mungkin memasuki kota oleh Northgate, tetapi penduduk setempat yang membantu menerjemahkan bagian "ke-2".)
Jika kasus sudut yang tersisa Anda harus menggunakan definitif sumber pengaturan konfigurasi ini - yang merupakan fungsi C gethostname(2)
. Fungsi itu juga disebut oleh program hostname
.
InetAddress.getLocalHost().getHostName()
adalah cara yang lebih portabel.
exec("hostname")
sebenarnya memanggil sistem operasi untuk menjalankan hostname
perintah.
Berikut adalah beberapa jawaban terkait lainnya pada SO:
EDIT: Anda harus melihat jawaban AH atau jawaban Arnout Engelen untuk perincian mengapa ini mungkin tidak berfungsi seperti yang diharapkan, tergantung pada situasi Anda. Sebagai jawaban untuk orang ini yang secara spesifik meminta portable, saya pikir masih getHostName()
baik-baik saja, tetapi mereka memunculkan beberapa poin bagus yang harus dipertimbangkan.
InetAddress.getLocalHost()
dalam beberapa kasus mengembalikan perangkat loopback. Dalam hal itu, getHostName()
mengembalikan "localhost", yang tidak terlalu berguna.
Seperti yang telah dicatat orang lain, mendapatkan nama host berdasarkan resolusi DNS tidak dapat diandalkan.
Karena pertanyaan ini sayangnya masih relevan pada tahun 2018 , saya ingin berbagi dengan Anda solusi yang tidak tergantung jaringan saya, dengan beberapa pengujian berjalan pada sistem yang berbeda.
Kode berikut mencoba melakukan hal berikut:
Di Windows
Baca COMPUTERNAME
variabel lingkungan melalui System.getenv()
.
Jalankan hostname.exe
dan baca responsnya
Di Linux
Baca HOSTNAME
variabel lingkungan melaluiSystem.getenv()
Jalankan hostname
dan baca responsnya
Baca /etc/hostname
(untuk melakukan ini saya mengeksekusi cat
karena cuplikan sudah berisi kode untuk dieksekusi dan dibaca. Namun, membaca file akan lebih baik).
Kode:
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() : "";
}
}
Hasil untuk sistem operasi yang berbeda:
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 LTS
Yang ini agak aneh karena echo $HOSTNAME
mengembalikan nama host yang benar, tetapi System.getenv("HOSTNAME")
tidak:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
EDIT: Menurut legolas108 , System.getenv("HOSTNAME")
berfungsi di Ubuntu 14.04 jika Anda menjalankan export HOSTNAME
sebelum mengeksekusi kode Java.
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
"
Nama-nama mesin telah diganti tetapi saya tetap menggunakan huruf besar dan struktur. Perhatikan baris baru tambahan saat menjalankan hostname
, Anda mungkin harus mempertimbangkannya dalam beberapa kasus.
export HOSTNAME
sebelum menjalankan kode Java pada Ubuntu 14.04 LTS juga dikembalikan oleh System.getenv("HOSTNAME")
.
export HOSTNAME
agar Java menggunakannya? Saya pikir itu harus menjadi standar env var seperti PATH.
\A
pembatas hanyalah retasan untuk membaca seluruh InputStream menggunakan a Scanner
.
InetAddress.getLocalHost().getHostName()
lebih baik (seperti yang dijelaskan oleh Nick), tetapi masih belum terlalu bagus
Satu host dapat dikenal dengan banyak nama host yang berbeda. Biasanya Anda akan mencari nama host yang dimiliki host Anda dalam konteks tertentu.
Misalnya, dalam aplikasi web, Anda mungkin mencari nama host yang digunakan oleh siapa pun yang mengeluarkan permintaan yang sedang Anda tangani. Cara terbaik menemukan itu tergantung pada kerangka mana yang Anda gunakan untuk aplikasi web Anda.
Dalam beberapa jenis layanan lain yang berhubungan dengan internet, Anda akan menginginkan nama host layanan Anda tersedia dari 'luar'. Karena proksi, firewall, dll. Ini bahkan mungkin bukan nama host di mesin tempat layanan Anda diinstal - Anda mungkin mencoba membuat default yang masuk akal, tetapi Anda harus membuat ini dapat dikonfigurasi untuk siapa pun yang menginstalnya.
Meskipun topik ini sudah dijawab, masih ada lagi yang bisa dikatakan.
Pertama-tama: Jelas kita perlu beberapa definisi di sini. The InetAddress.getLocalHost().getHostName()
memberikan nama host seperti yang terlihat dari perspektif jaringan . Masalah dengan pendekatan ini didokumentasikan dengan baik dalam jawaban lain: sering membutuhkan pencarian DNS, itu ambigu jika host memiliki beberapa antarmuka jaringan dan itu kadang-kadang gagal kadang-kadang (lihat di bawah).
Tetapi pada OS apa pun ada nama lain juga. Nama host yang didefinisikan sangat awal dalam proses boot, jauh sebelum jaringan diinisialisasi. Jendela mengacu pada ini sebagai computername , Linux menyebutnya kernel nama host dan Solaris menggunakan kata nodename . Saya paling suka kata computername , jadi saya akan menggunakan kata itu mulai sekarang.
Di Linux / Unix, computername adalah apa yang Anda dapatkan dari fungsi C gethostname()
, atau hostname
perintah dari shell atau HOSTNAME
variabel lingkungan di shell mirip Bash.
Pada Windows, nama pengguna adalah apa yang Anda dapatkan dari variabel lingkungan COMPUTERNAME
atau GetComputerName
fungsi Win32 .
Java tidak memiliki cara untuk mendapatkan apa yang saya definisikan sebagai 'nama pengguna'. Tentu, ada solusi seperti yang dijelaskan dalam jawaban lain, seperti untuk panggilan Windows System.getenv("COMPUTERNAME")
, tetapi pada Unix / Linux tidak ada solusi yang baik tanpa menggunakan JNI / JNA atau Runtime.exec()
. Jika Anda tidak keberatan dengan solusi JNI / JNA maka ada gethostname4j yang mati sederhana dan sangat mudah digunakan.
Mari kita lanjutkan dengan dua contoh, satu dari Linux dan satu dari Solaris, yang menunjukkan bagaimana Anda dapat dengan mudah masuk ke situasi di mana Anda tidak dapat memperoleh nama pengguna menggunakan metode Java standar.
Pada sistem yang baru dibuat, tempat host selama instalasi dinamai 'chicago', kami sekarang mengubah apa yang disebut nama host kernel:
$ hostnamectl --static set-hostname dallas
Sekarang nama host kernel adalah 'dallas', seperti yang terlihat dari perintah hostname:
$ hostname
dallas
Tapi kita masih punya
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
Tidak ada kesalahan konfigurasi dalam hal ini. Ini hanya berarti nama jaringan host (atau lebih tepatnya nama antarmuka loopback) berbeda dari nama pengguna host.
Sekarang, coba jalankan InetAddress.getLocalHost().getHostName()
dan itu akan membuang java.net.UnknownHostException. Anda pada dasarnya terjebak. Tidak ada cara untuk mengambil nilai 'dallas' maupun nilai 'chicago'.
Contoh di bawah ini didasarkan pada Solaris 11.3.
Tuan rumah telah sengaja dikonfigurasi sehingga nama loopback <> nama file.
Dengan kata lain kita memiliki:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
dan isi / etc / hosts:
:1 chicago localhost
127.0.0.1 chicago localhost loghost
dan hasil dari perintah hostname adalah:
$ hostname
dallas
Sama seperti pada contoh Linux panggilan ke InetAddress.getLocalHost().getHostName()
akan gagal
java.net.UnknownHostException: dallas: dallas: node name or service name not known
Sama seperti contoh Linux Anda sekarang terjebak. Tidak ada cara untuk mengambil nilai 'dallas' maupun nilai 'chicago'.
Sangat sering Anda akan menemukan bahwa InetAddress.getLocalHost().getHostName()
memang akan mengembalikan nilai yang sama dengan nama pengguna. Jadi tidak ada masalah (kecuali untuk penambahan resolusi nama).
Masalahnya muncul biasanya dalam lingkungan PaaS di mana ada perbedaan antara nama pengguna dan nama antarmuka loopback. Misalnya orang melaporkan masalah di Amazon EC2.
Sedikit pencarian mengungkapkan laporan RFE ini: link1 , link2 . Namun, menilai dari komentar pada laporan itu, masalah ini tampaknya telah banyak disalahpahami oleh tim JDK, sehingga tidak mungkin akan ditangani.
Saya suka perbandingan dalam RFE dengan bahasa pemrograman lain.
Variabel lingkungan juga dapat memberikan cara yang bermanfaat - COMPUTERNAME
pada Windows, HOSTNAME
pada sebagian besar shell Unix / Linux modern.
Lihat: https://stackoverflow.com/a/17956000/768795
Saya menggunakan ini sebagai metode "tambahan" untuk InetAddress.getLocalHost().getHostName()
, karena seperti yang ditunjukkan beberapa orang, fungsi itu tidak berfungsi di semua lingkungan.
Runtime.getRuntime().exec("hostname")
adalah suplemen lain yang mungkin. Pada tahap ini, saya belum menggunakannya.
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
, itu disediakan oleh proyek commons-lang Apache. Sangat disarankan untuk menggunakannya.
System.getenv("HOSTNAME")
keluar nol pada Mac melalui Beanshell untuk Java, tetapi PATH
diekstraksi ok. Saya juga bisa melakukannya echo $HOSTNAME
di Mac, hanya System.getenv ("HOSTNAME") tampaknya memiliki masalah. Aneh.
Cara paling portabel untuk mendapatkan nama host dari komputer saat ini di Jawa adalah sebagai berikut:
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);
}
}
Jika Anda tidak menentang menggunakan dependensi eksternal dari maven central, saya menulis gethostname4j untuk menyelesaikan masalah ini untuk diri saya sendiri. Itu hanya menggunakan JNA untuk memanggil fungsi gethostname libc (atau mendapatkan ComputerName di Windows) dan mengembalikannya kepada Anda sebagai string.
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();
}
}
}
}
Hanya lintas satu ... lintas platform (Windows-Linux-Unix-Mac (Unix)) [Selalu berfungsi, Tidak diperlukan DNS]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
Kamu sudah selesai !!
InetAddress.getLocalHost (). GetHostName () adalah cara terbaik dari keduanya karena ini adalah abstraksi terbaik di tingkat pengembang.