ข้อใดต่อไปนี้เป็นวิธีที่ดีที่สุดและพกพาได้มากที่สุดในการรับชื่อโฮสต์ของคอมพิวเตอร์ปัจจุบันใน 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
อ่านตัวแปรสภาพแวดล้อมผ่านCOMPUTERNAME
System.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 () เป็นวิธีที่ดีที่สุดจากทั้งสองเนื่องจากเป็นสิ่งที่ดีที่สุดในระดับนักพัฒนา