ข้อใดต่อไปนี้เป็นวิธีที่ดีที่สุดและพกพาได้มากที่สุดในการรับชื่อโฮสต์ของคอมพิวเตอร์ปัจจุบันใน Java
Runtime.getRuntime().exec("hostname")
VS
InetAddress.getLocalHost().getHostName()
ข้อใดต่อไปนี้เป็นวิธีที่ดีที่สุดและพกพาได้มากที่สุดในการรับชื่อโฮสต์ของคอมพิวเตอร์ปัจจุบันใน Java
Runtime.getRuntime().exec("hostname")
VS
InetAddress.getLocalHost().getHostName()
คำตอบ:
พูดอย่างเคร่งครัด - คุณไม่มีทางเลือก แต่เรียกอย่างใดอย่างหนึ่งhostname(1)หรือ - บน gethostname(2)Unix นี่คือชื่อคอมพิวเตอร์ของคุณ ความพยายามใด ๆ ในการระบุชื่อโฮสต์ตามที่อยู่ IP เช่นนี้
InetAddress.getLocalHost().getHostName()
ถูกผูกไว้กับความล้มเหลวในบางสถานการณ์:
อย่าสับสนชื่อของที่อยู่ IP กับชื่อของโฮสต์ (ชื่อโฮสต์) คำอุปมาอาจทำให้ชัดเจน:
มีเมืองใหญ่ (เซิร์ฟเวอร์) เรียกว่า "ลอนดอน" ข้างในกำแพงเมืองมีเรื่องมากมายเกิดขึ้น เมืองนี้มีหลายประตู (ที่อยู่ IP) แต่ละประตูมีชื่อ ("North Gate", "River Gate", "Southampton Gate" ... ) แต่ชื่อของประตูไม่ใช่ชื่อของเมือง นอกจากนี้คุณไม่สามารถอนุมานชื่อของเมืองโดยใช้ชื่อของประตู - "North Gate" จะจับครึ่งหนึ่งของเมืองใหญ่และไม่ใช่แค่เมืองเดียว อย่างไรก็ตาม - คนแปลกหน้า (แพ็คเก็ต IP) เดินไปตามแม่น้ำและถามคนท้องถิ่น: "ฉันมีที่อยู่แปลก ๆ : 'ริเวอร์เกตซ้ายสองบ้านหลังที่สาม' คุณช่วยฉันได้ไหม" คนในพื้นที่พูดว่า: "แน่นอนคุณอยู่บนถนนที่ถูกต้องเพียงแค่เดินหน้าต่อไปและคุณจะไปถึงจุดหมายภายในครึ่งชั่วโมง"
นี่แสดงให้เห็นว่าฉันคิดว่าสวยมาก
ข่าวดีก็คือ: ชื่อโฮสต์จริงมักไม่จำเป็น ในกรณีส่วนใหญ่ชื่อใด ๆ ที่แก้ไขเป็นที่อยู่ IP ในโฮสต์นี้จะทำ (คนแปลกหน้าอาจเข้ามาในเมืองโดย Northgate แต่ชาวบ้านที่เป็นประโยชน์แปลส่วน "2nd left")
หากกรณีที่มุมที่เหลือคุณต้องใช้ที่ชัดเจนแหล่งที่มาของการตั้งค่าการกำหนดค่านี้ - gethostname(2)ซึ่งเป็นฟังก์ชั่นซี hostnameฟังก์ชั่นที่ยังถูกเรียกโดยโปรแกรม
InetAddress.getLocalHost().getHostName() เป็นวิธีพกพามากขึ้น
exec("hostname")จริงเรียกออกไปยังระบบปฏิบัติการเพื่อรันhostnameคำสั่ง
นี่คือคำตอบที่เกี่ยวข้องอื่น ๆ สองสามข้อเกี่ยวกับ SO:
แก้ไข:คุณควรดูคำตอบของ AHหรือคำตอบของArnout Engelenสำหรับรายละเอียดเกี่ยวกับสาเหตุที่อาจไม่ทำงานตามที่คาดไว้ทั้งนี้ขึ้นอยู่กับสถานการณ์ของคุณ ในฐานะที่เป็นคำตอบสำหรับคนที่ขอพกพาเป็นพิเศษฉันยังคิดว่าใช้ได้getHostName()แต่พวกเขานำคะแนนที่ดีมาพิจารณา
InetAddress.getLocalHost()ในบางกรณีจะส่งคืนอุปกรณ์ลูปแบ็ค ในกรณีนั้นgetHostName()คืนค่า "localhost" ซึ่งไม่มีประโยชน์มาก
ดังที่คนอื่น ๆ จดไว้การรับชื่อโฮสต์ตามการแก้ไข DNS นั้นไม่น่าเชื่อถือ
เนื่องจากคำถามนี้ยังมีความเกี่ยวข้องในปี 2561ฉันต้องการแบ่งปันโซลูชันเครือข่ายของฉันกับคุณโดยมีการทดสอบบางอย่างทำงานในระบบที่แตกต่างกัน
รหัสต่อไปนี้พยายามทำสิ่งต่อไปนี้:
บน Windows
อ่านตัวแปรสภาพแวดล้อมผ่านCOMPUTERNAMESystem.getenv()
ดำเนินการhostname.exeและอ่านการตอบสนอง
บน Linux
อ่านHOSTNAMEตัวแปรสภาพแวดล้อมผ่านSystem.getenv()
ดำเนินการhostnameและอ่านการตอบสนอง
อ่าน/etc/hostname(เพื่อทำสิ่งนี้ฉันกำลังดำเนินการcatเนื่องจากข้อมูลโค้ดมีรหัสที่จะดำเนินการและอ่านอยู่แล้วการอ่านไฟล์จะดีกว่า)
รหัส:
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() : "";
}
}
ผลลัพธ์สำหรับระบบปฏิบัติการที่แตกต่างกัน:
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
อันนี้ค่อนข้างแปลกตั้งแต่echo $HOSTNAMEคืนชื่อโฮสต์ที่ถูกต้อง แต่System.getenv("HOSTNAME")ไม่:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
แก้ไข:ตามlegolas108 , System.getenv("HOSTNAME")ทำงานบน Ubuntu 14.04 ถ้าคุณทำงานexport HOSTNAMEก่อนที่จะดำเนินรหัส Java
วินโดว 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
"
ชื่อเครื่องถูกเปลี่ยน แต่ฉันยังคงตัวพิมพ์ใหญ่และโครงสร้าง โปรดทราบการขึ้นบรรทัดใหม่เมื่อเรียกใช้hostnameงานคุณอาจต้องพิจารณาในบางกรณี
export HOSTNAMEก่อนที่จะใช้รหัส Java บน Ubuntu 14.04 LTS System.getenv("HOSTNAME")ก็ยังกลับโดย
export HOSTNAMEใช้ Java อย่างชัดเจนหรือไม่? ฉันคิดว่ามันควรเป็นค่าเริ่มต้น env var เช่น PATH
\Aคั่นเป็นเพียงสับสำหรับอ่าน InputStream Scannerทั้งหมดใช้
InetAddress.getLocalHost().getHostName() ดีกว่า (ตามที่นิคอธิบาย) แต่ก็ยังไม่ค่อยดีเท่าไหร่
หนึ่งโฮสต์สามารถเป็นที่รู้จักภายใต้ชื่อโฮสต์ที่แตกต่างกัน โดยปกติคุณจะมองหาชื่อโฮสต์ที่โฮสต์ของคุณมีในบริบทที่ระบุ
ตัวอย่างเช่นในเว็บแอปพลิเคชันคุณอาจกำลังมองหาชื่อโฮสต์ที่ใช้โดยใครก็ตามที่ออกคำขอที่คุณกำลังจัดการอยู่ในปัจจุบัน วิธีการหาที่ดีที่สุดนั้นขึ้นอยู่กับกรอบที่คุณใช้สำหรับเว็บแอปพลิเคชันของคุณ
ในบริการอินเทอร์เน็ตอื่น ๆ บางประเภทคุณจะต้องการชื่อโฮสต์ที่บริการของคุณสามารถใช้ได้จาก 'ภายนอก' เนื่องจากพร็อกซีไฟร์วอลล์ ฯลฯ อาจไม่ได้เป็นชื่อโฮสต์ในเครื่องที่ติดตั้งบริการของคุณ - คุณอาจลองใช้ค่าเริ่มต้นที่สมเหตุสมผล แต่คุณควรกำหนดค่านี้อย่างแน่นอนสำหรับผู้ที่ติดตั้งสิ่งนี้
แม้ว่าหัวข้อนี้จะได้รับคำตอบแล้วยังมีอีกหลายสิ่งที่จะพูด
ก่อนอื่น: เห็นได้ชัดว่าเราต้องการคำจำกัดความบางอย่างที่นี่ The InetAddress.getLocalHost().getHostName()ให้ชื่อโฮสต์ที่เห็นจากมุมมองเครือข่ายเท่าที่เห็นจากมุมมองของเครือข่ายปัญหาเกี่ยวกับวิธีการนี้ได้รับการบันทึกไว้เป็นอย่างดีในคำตอบอื่น ๆ : มันมักจะต้องมีการค้นหา DNS มันไม่ชัดเจนถ้าโฮสต์มีอินเตอร์เฟซเครือข่ายหลายตัวและบางครั้งก็ล้มเหลว
แต่ในระบบปฏิบัติการใด ๆ ก็มีอีกชื่อหนึ่งเช่นกัน ชื่อของโฮสต์ที่ได้รับการกำหนดตั้งแต่ต้นในกระบวนการบู๊ตนานก่อนที่เครือข่ายจะเริ่มต้นได้ ของ Windows หมายถึงนี้เป็นcomputernameลินุกซ์เรียกมันว่าเคอร์เนลชื่อโฮสต์และ Solaris ใช้คำว่าnodename ฉันชอบคำว่าcomputernameดีที่สุดดังนั้นฉันจะใช้คำนั้นต่อจากนี้ไป
บน Linux / Unix ชื่อคอมพิวเตอร์คือสิ่งที่คุณได้รับจากฟังก์ชัน C gethostname()หรือhostnameคำสั่งจากเชลล์หรือHOSTNAMEตัวแปรสภาพแวดล้อมในเชลล์เหมือน Bash
ใน Windows computername คือสิ่งที่คุณได้รับจากตัวแปรสภาพแวดล้อมCOMPUTERNAMEหรือGetComputerNameฟังก์ชันWin32
Java ไม่มีวิธีรับสิ่งที่ฉันกำหนดเป็น 'ชื่อคอมพิวเตอร์' ตรวจสอบว่ามีการแก้ไขปัญหาที่อธิบายไว้ในคำตอบอื่น ๆ เช่นสำหรับ Windows โทรSystem.getenv("COMPUTERNAME")แต่ใน Unix / Linux ไม่มีวิธีแก้ปัญหาที่ดีโดยไม่ต้อง resorting JNI / JNA Runtime.exec()หรือ หากคุณไม่สนใจโซลูชัน JNI / JNA ก็มีgethostname4jซึ่งตายง่ายและใช้งานง่ายมาก
มาต่อด้วยสองตัวอย่างจาก Linux และอีกหนึ่งจาก Solaris ซึ่งแสดงให้เห็นว่าคุณสามารถเข้าสู่สถานการณ์ที่คุณไม่สามารถรับชื่อคอมพิวเตอร์โดยใช้วิธีมาตรฐาน Java ได้อย่างไร
บนระบบที่สร้างขึ้นใหม่ซึ่งโฮสต์ระหว่างการติดตั้งได้รับการตั้งชื่อว่า 'chicago' ตอนนี้เราเปลี่ยนชื่อโฮสต์เคอร์เนล:
$ hostnamectl --static set-hostname dallas
ตอนนี้ชื่อโฮสต์เคอร์เนลคือ 'dallas' ดังที่เห็นได้จากคำสั่งชื่อโฮสต์:
$ hostname
dallas
แต่เรายังมี
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
ไม่มีการกำหนดค่าผิดพลาดในสิ่งนี้ มันหมายถึงชื่อเครือข่ายของโฮสต์ (หรือมากกว่าชื่อของส่วนต่อประสานย้อนกลับ) จะแตกต่างจากชื่อคอมพิวเตอร์ของโฮสต์
ตอนนี้ลองดำเนินการInetAddress.getLocalHost().getHostName() แล้วมันจะโยน java.net.UnknownHostException คุณติดอยู่โดยทั่วไป ไม่มีวิธีใดในการเรียกคืนทั้งค่า 'ดัลลัส' หรือค่า 'ชิคาโก'
ตัวอย่างด้านล่างใช้ Solaris 11.3
โฮสต์ได้รับการกำหนดค่าโดยเจตนาเพื่อให้ชื่อลูปแบ็ค <> ชื่อโหนด
ในคำอื่น ๆ เรามี:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
และเนื้อหาของ / etc / hosts:
:1 chicago localhost
127.0.0.1 chicago localhost loghost
และผลลัพธ์ของคำสั่ง hostname จะเป็น:
$ hostname
dallas
เช่นเดียวกับในตัวอย่างของ Linux การเรียกใช้InetAddress.getLocalHost().getHostName()จะล้มเหลว
java.net.UnknownHostException: dallas: dallas: node name or service name not known
เช่นเดียวกับตัวอย่างของ Linux ที่คุณติดอยู่ ไม่มีวิธีใดในการเรียกคืนทั้งค่า 'ดัลลัส' หรือค่า 'ชิคาโก'
บ่อยครั้งที่คุณจะพบว่าInetAddress.getLocalHost().getHostName()จริง ๆ แล้วจะคืนค่าซึ่งเท่ากับชื่อคอมพิวเตอร์ ดังนั้นจึงไม่มีปัญหา (ยกเว้นค่าใช้จ่ายเพิ่มเติมของการแก้ไขชื่อ)
ปัญหาเกิดขึ้นโดยทั่วไปในสภาพแวดล้อม PaaS ซึ่งมีความแตกต่างระหว่างชื่อคอมพิวเตอร์และชื่อของอินเทอร์เฟซย้อนกลับ ตัวอย่างเช่นผู้คนรายงานปัญหาใน Amazon EC2
บิตของการค้นหาเผยรายงาน RFE นี้: link1 , link2 อย่างไรก็ตามการตัดสินจากความคิดเห็นในรายงานนั้นดูเหมือนว่าทีม JDK จะเข้าใจผิดเป็นส่วนใหญ่ดังนั้นจึงไม่น่าที่จะได้รับการแก้ไข
ฉันชอบการเปรียบเทียบใน RFE กับภาษาการเขียนโปรแกรมอื่น
ตัวแปรสภาพแวดล้อมอาจเป็นวิธีที่มีประโยชน์COMPUTERNAMEสำหรับ Windows HOSTNAMEบนเชลล์ Unix / Linux ที่ทันสมัยที่สุด
ดู: https://stackoverflow.com/a/17956000/768795
ฉันใช้วิธีเหล่านี้เป็นวิธี "เสริม" InetAddress.getLocalHost().getHostName()เนื่องจากหลาย ๆ คนชี้ให้เห็นว่าฟังก์ชั่นนั้นไม่สามารถใช้งานได้ในทุกสภาพแวดล้อม
Runtime.getRuntime().exec("hostname")เป็นอีกอาหารเสริมที่เป็นไปได้ ในขั้นตอนนี้ฉันไม่ได้ใช้มัน
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 คอมมอนส์ lang ขอแนะนำให้ใช้หรือสิ่งที่ชอบ
System.getenv("HOSTNAME")ก็ออกมาเป็นโมฆะบน Mac ผ่าน Beanshell สำหรับ Java แต่PATHถูกสกัดออกมา ฉันก็สามารถทำได้echo $HOSTNAMEบน Mac ด้วยเช่นกันดูเหมือนว่า System.getenv ("HOSTNAME") ก็มีปัญหาเช่นกัน แปลก.
วิธีพกพาที่สุดในการรับชื่อโฮสต์ของคอมพิวเตอร์ปัจจุบันใน Java มีดังนี้:
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);
}
}
ถ้าคุณไม่ใช้การพึ่งพาภายนอกจากศูนย์กลาง maven ฉันเขียน gethostname4j เพื่อแก้ปัญหานี้ด้วยตัวเอง มันใช้ JNA เพื่อเรียกใช้ฟังก์ชัน gethostname ของ libc (หรือรับ ComputerName บน Windows) และส่งคืนให้คุณเป็นสตริง
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();
}
}
}
}
เพียงหนึ่งซับไลน์ ... ข้ามแพลตฟอร์ม (Windows-Linux-Unix-Mac (Unix)) [ใช้งานได้เสมอไม่จำเป็นต้องใช้ DNS]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
คุณทำเสร็จแล้ว !!
InetAddress.getLocalHost (). getHostName () เป็นวิธีที่ดีที่สุดจากทั้งสองเนื่องจากเป็นสิ่งที่ดีที่สุดในระดับนักพัฒนา