การค้นหาที่อยู่ IP ในเครื่องโดยใช้ stythl


547

ฉันจะค้นหาที่อยู่ IP ภายในเครื่อง (เช่น 192.168.xx หรือ 10.0.xx) ในแพลตฟอร์ม Python อย่างอิสระและใช้เฉพาะไลบรารีมาตรฐานได้อย่างไร


7
IP ท้องถิ่นหรือไม่ หรือ IP สาธารณะ คุณจะจัดการกับระบบที่มีหลาย IP ได้อย่างไร
Sargun Dhillon

ใช้ifconfig -aและใช้การส่งออกจากที่นั่น ...
Fredrik พิห์ล

16
@ เฟรดริกนั่นเป็นความคิดที่ไม่ดี ก่อนอื่นคุณต้องปลอมแปลงกระบวนการใหม่โดยไม่จำเป็นซึ่งอาจทำให้โปรแกรมของคุณทำงานในการกำหนดค่าที่ล็อคไว้อย่างแน่นหนา (หรือคุณต้องอนุญาตสิทธิ์โปรแกรมที่คุณไม่ต้องการ) ประการที่สองคุณจะแนะนำข้อบกพร่องสำหรับผู้ใช้สถานที่ต่างๆ ประการที่สามถ้าคุณตัดสินใจที่จะเริ่มโปรแกรมใหม่เลยคุณไม่ควรเริ่มโปรแกรมที่เลิกใช้แล้ว - ip addrเหมาะสมกว่า (และง่ายต่อการแยกวิเคราะห์เพื่อบูต)
Phihag

12
@phihag คุณถูกต้องแน่นอนขอบคุณสำหรับการแก้ไขความโง่เขลาของฉัน
Fredrik Pihl

1
ปัญหาพื้นฐานมากขึ้นที่นี่คือในโปรแกรมเครือข่ายที่ทันสมัยเป็นลายลักษณ์อักษรอย่างถูกต้องที่อยู่ IP ท้องถิ่น (ขวา) ขึ้นอยู่กับเพื่อนหรือชุดของเพื่อนที่มีศักยภาพ หากจำเป็นต้องใช้ที่อยู่ IP ในเครื่องสำหรับbindซ็อกเก็ตไปยังอินเทอร์เฟซเฉพาะนั่นเป็นประเด็นนโยบาย หากจำเป็นต้องมีที่อยู่ IP ภายในเครื่องเพื่อส่งให้เพื่อนเพื่อให้เพื่อนสามารถ "โทรกลับ" เช่นเปิดการเชื่อมต่อกลับไปที่เครื่องท้องถิ่นสถานการณ์จะขึ้นอยู่กับว่ามี NAT (แปลที่อยู่เครือข่าย) หรือไม่ ในระหว่างกล่อง หากไม่มี NATs getsocknameเป็นตัวเลือกที่ดี
Pekka Nikander

คำตอบ:


445
import socket
socket.gethostbyname(socket.gethostname())

สิ่งนี้จะไม่ทำงานเสมอไป (กลับมา127.0.0.1ที่เครื่องที่มีชื่อโฮสต์/etc/hostsเป็น127.0.0.1), paliative จะเป็นสิ่งที่ gimel แสดงให้ใช้socket.getfqdn()แทน แน่นอนว่าเครื่องของคุณต้องการชื่อโฮสต์ที่สามารถแก้ไขได้


43
หนึ่งควรทราบว่านี่ไม่ใช่โซลูชันอิสระของแพลตฟอร์ม Linuxes จำนวนมากจะคืนค่า 127.0.0.1 เป็นที่อยู่ IP ของคุณโดยใช้วิธีนี้
Jason Baker

20
รูปแบบ: socket.gethostbyname (socket.getfqdn ())
gimel

55
ดูเหมือนว่าจะส่งคืนที่อยู่ IP เดียวเท่านั้น เกิดอะไรขึ้นถ้าเครื่องมีหลายที่อยู่?
เจสันคูมบ์สอาร์

26
บน Ubuntu จะคืนค่า 127.0.1.1 ด้วยเหตุผลบางประการ
slikts

13
@Jason R. Coombs ใช้รหัสต่อไปนี้เพื่อดึงรายการที่อยู่ IPv4 ที่เป็นของเครื่องโฮสต์:socket.gethostbyname_ex(socket.gethostname())[-1]
Barmaley

460

ฉันเพิ่งพบสิ่งนี้ แต่ดูเหมือนว่าแฮ็คเล็กน้อย แต่พวกเขาบอกว่าลองมันใน * ระวังและฉันทำบน windows และใช้งานได้

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()

สิ่งนี้จะถือว่าคุณมีอินเทอร์เน็ตและไม่มีพร็อกซีในพื้นที่


31
ดีถ้าคุณมีอินเทอร์เฟซต่าง ๆ บนเครื่องและต้องการที่จะไปเช่น gmail.com
elzapp

4
มันอาจจะเป็นความคิดที่ดีที่จะจับข้อยกเว้น socket.error ซึ่งอาจเพิ่มขึ้นโดย s.connect ()!
phobie

39
มันจะเป็นการดีกว่าถ้าใช้ที่อยู่ IP แทนชื่อโดเมน - จะต้องเร็วกว่าและไม่ขึ้นกับ DNS เช่นเราสามารถใช้ 8.8.8.8 IP - เซิร์ฟเวอร์ DNS สาธารณะของ Google
wobmene

10
ฉลาดมากทำงานได้อย่างสมบูรณ์ แทนที่จะเป็น gmail หรือ 8.8.8.8 คุณสามารถใช้ IP หรือที่อยู่ของเซิร์ฟเวอร์ที่คุณต้องการให้ดูถ้ามันใช้งานได้
ศ. Falken ผิดสัญญา

3
ตัวอย่างนี้มีการพึ่งพาจากภายนอกว่าสามารถแก้ไข gmail.com ได้จริง หากคุณตั้งค่าเป็นที่อยู่ IP ที่ไม่ได้อยู่ใน LAN ท้องถิ่นของคุณ (ไม่สำคัญว่าจะขึ้นหรือลง) มันจะทำงานได้โดยไม่ต้องพึ่งพาและไม่มีการรับส่งข้อมูลเครือข่าย
น่ากลัว

254

วิธีการนี้จะส่งกลับ "หลัก" IP บนกล่องท้องถิ่น (หนึ่งกับเส้นทางเริ่มต้นที่)

  • ไม่จำเป็นต้องเข้าถึงอินเทอร์เน็ตที่กำหนดเส้นทางได้หรือการเชื่อมต่อใด ๆ เลย
  • ใช้งานได้แม้ว่าอินเทอร์เฟซทั้งหมดจะถูกถอดออกจากเครือข่าย
  • ไม่จำเป็นต้องมีหรือแม้แต่พยายามที่จะรับทุกที่อื่น
  • ทำงานร่วมกับ NAT, สาธารณะ, ส่วนตัว, ภายนอกและ IP ภายในของ
  • Pure Python 2 (หรือ 3) โดยไม่มีการอ้างอิงภายนอก
  • ทำงานบน Linux, Windows และ OSX

Python 3 หรือ 2:

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

ส่งคืน IP เดียวซึ่งเป็นเส้นทางหลัก (อันที่มีเส้นทางเริ่มต้น) หากคุณต้องการ IP ทั้งหมดที่เชื่อมต่อกับอินเตอร์เฟสทั้งหมด (รวมถึง localhost และอื่น ๆ ) ให้ดูคำตอบนี้

หากคุณอยู่หลังไฟร์วอลล์ NAT เช่นกล่อง wifi ที่บ้านนี่จะไม่แสดง NAT IP สาธารณะของคุณ แต่แทนที่จะเป็น IP ส่วนตัวของคุณบนเครือข่ายท้องถิ่นซึ่งมีเส้นทางเริ่มต้นไปยังเราเตอร์ไร้สายในพื้นที่ของคุณ การรับ IP ภายนอกของเราเตอร์ wifi ของคุณอาจต้องการการทำงานนี้ในกล่องนั้นหรือเชื่อมต่อกับบริการภายนอกเช่น whatismyip.com/whatismyipaddress.com ที่สามารถสะท้อนกลับ IP ... แต่นั่นแตกต่างจากคำถามเดิมอย่างสิ้นเชิง :)


7
ใช้งานได้ใน Raspbian ด้วย Python 2 และ 3!
pierce.jason

3
สุกใส ทำงานบน Win7,8,8.1 + Linux Mint & Arch รวมถึง VMs
shermy

2
ทำงานได้ใน Windows 10 Pro! ขอบคุณ Jamieson Becker!
varantes

3
ด้วยเหตุผลบางอย่างสิ่งนี้ไม่ทำงานบน Mac OS X El Capitan 10.11.6 (สร้างข้อผิดพลาดของระบบปฏิบัติการยกเว้น: [Errno 49] ไม่สามารถกำหนดที่อยู่ที่ร้องขอได้) การเปลี่ยนพอร์ตจาก '0' เป็น '1': s.connect (('10.255.255.255', 1)) ทำงานให้ฉันทั้งบน Mac OS X และ Linux Ubuntu 17.04
Pedro Scarapicchia Junior

10
นี่ควรเป็นคำตอบที่ยอมรับได้ socket.gethostbyname(socket.gethostname())ให้ผลลัพธ์ที่น่ากลัว
Jason Floyd

142

ในฐานะนามแฝงที่เรียกmyipว่าควรทำงานได้ทุกที่:

alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
  • ทำงานได้อย่างถูกต้องกับ Python 2.x, Python 3.x, ดิสทริบิวชัน distros Linux รุ่นเก่าและใหม่, OSX / macOS และ Windows สำหรับค้นหาที่อยู่ IPv4 ปัจจุบัน
  • จะไม่ส่งคืนผลลัพธ์ที่ถูกต้องสำหรับเครื่องที่มีที่อยู่ IP หลายแห่ง, IPv6, ไม่มีที่อยู่ IP ที่กำหนดค่าไว้หรือไม่มีการเข้าถึงอินเทอร์เน็ต

เหมือนข้างบน แต่เป็นเพียงรหัสงูหลาม:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
  • สิ่งนี้จะทำให้เกิดข้อยกเว้นหากไม่มีการกำหนดค่าที่อยู่ IP

เวอร์ชันที่สามารถใช้งานบน LAN ได้โดยไม่ต้องเชื่อมต่ออินเทอร์เน็ต:

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(ขอบคุณ@ccpizza )


พื้นหลัง :

การใช้socket.gethostbyname(socket.gethostname())ไม่ทำงานที่นี่เพราะคอมพิวเตอร์เครื่องหนึ่งที่ฉันใช้/etc/hostsมีรายการที่ซ้ำกันและมีการอ้างอิงถึงตัวเอง socket.gethostbyname()ส่งกลับเฉพาะรายการสุดท้าย/etc/hostsเท่านั้น

นี่เป็นความพยายามครั้งแรกของฉันซึ่งกำจัดที่อยู่ทั้งหมดที่เริ่มต้นด้วย"127.":

import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])

สิ่งนี้ใช้ได้กับ Python 2 และ 3 บน Linux และ Windows แต่ไม่ได้จัดการกับอุปกรณ์เครือข่ายหลายตัวหรือ IPv6 อย่างไรก็ตามมันหยุดทำงานกับ Linux distros เมื่อเร็ว ๆ นี้ดังนั้นฉันจึงลองใช้เทคนิคทางเลือกนี้แทน พยายามเชื่อมต่อกับเซิร์ฟเวอร์ Google DNS 8.8.8.8ที่พอร์ต53:

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

จากนั้นฉันรวมเทคนิคทั้งสองข้างต้นเป็นหนึ่งซับที่ควรทำงานได้ทุกที่และสร้างข้อมูลmyipนามแฝงและ Python ที่ด้านบนของคำตอบนี้

ด้วยความนิยมที่เพิ่มขึ้นของ IPv6 และสำหรับเซิร์ฟเวอร์ที่มีอินเทอร์เฟซเครือข่ายหลายตัวการใช้โมดูล Python ของบุคคลที่สามสำหรับการค้นหาที่อยู่ IP น่าจะเป็นทั้งที่แข็งแกร่งและเชื่อถือได้กว่าวิธีการใด ๆ ที่ระบุไว้ที่นี่


2
@Alexander: เพียงแค่บอกว่าคำตอบนี้มีประโยชน์น้อยกว่าที่เคยเป็นมา (และไม่เหมือนการกรองข้อมูลที่ซ้ำกันออกมาเป็นเรื่องใหญ่;) ตามเอกสารsocket.getaddrinfo()ควรทำงานได้อย่างต่อเนื่องข้ามแพลตฟอร์ม - แต่ฉันตรวจสอบบน Linux เท่านั้นไม่ได้กังวลเกี่ยวกับระบบปฏิบัติการอื่น
Wladimir Palant

1
@Alexander, /etc/resolve.conf: No such file or directoryและฉันมีอยู่ IPv4 ifconfigท้องถิ่นแสดงโดย
Anatoly techtonik

2
ฉันสามารถยืนยันได้ว่าเวอร์ชั่นที่ได้รับการอัพเดตนั้นใช้ได้กับ Ubuntu 14.04 ทั้ง Python2 และ Py3k
Uli Köhler

4
การ "อัพเดท" แสดงเคล็ดลับที่ดีเกี่ยวกับการเชื่อมต่อ () บนซ็อกเก็ต UDP มันไม่ส่งทราฟฟิก แต่ให้คุณค้นหาว่าที่อยู่ผู้ส่งของแพ็คเก็ตไปยังผู้รับที่ระบุคืออะไร พอร์ตอาจไม่เกี่ยวข้อง (แม้แต่ 0 ควรใช้งานได้) สำหรับโฮสต์ที่มีหลายรูปแบบสิ่งสำคัญคือการเลือกที่อยู่ในซับเน็ตด้านขวา
ปีเตอร์แฮนเซ่น

17
เพียงเพราะคุณสามารถเขียนโค้ดนั้นในบรรทัดเดียวมันไม่ได้หมายความว่าคุณควร ...
JackLeo

91

คุณสามารถใช้โมดูลnetifaces เพียงพิมพ์:

pip install netifaces

ในเชลล์คำสั่งของคุณและมันจะติดตั้งเองในการติดตั้ง Python เริ่มต้น

จากนั้นคุณสามารถใช้สิ่งนี้:

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
    print '%s: %s' % (ifaceName, ', '.join(addresses))

มันพิมพ์บนคอมพิวเตอร์ของฉัน:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207

ผู้เขียนของโมดูลนี้อ้างว่ามันควรจะทำงานบน Windows, UNIX และ Mac OS X


20
ตามที่ระบุไว้ในคำถามที่ฉันต้องการบางสิ่งบางอย่างจากการติดตั้งเริ่มต้นในขณะที่ไม่จำเป็นต้องติดตั้งเพิ่มเติม
UnkwnTech

4
นี่จะเป็นคำตอบที่ฉันโปรดปรานยกเว้นว่า netifaces ไม่รองรับ IPv6 บน Windows และดูเหมือนจะไม่มีการเคลื่อนไหว มีใครคิดวิธีการรับที่อยู่ IPv6 บน Windows?
Jean-Paul Calderone

3
netifaces ไม่รองรับ py3k และต้องการคอมไพเลอร์ C ซึ่งเป็น PITA บน windows
Matt Joiner

4
@MattJoiner ไม่มีสิ่งใดที่เป็นจริงอีกต่อไป (เวอร์ชั่นล่าสุดมี Windows ไบนารีบน PyPI และรองรับ Py3K)
alastair

4
@ Jean-PaulCalderone FWIW, รุ่นล่าสุดของ netifaces ไม่สนับสนุน IPv6 บน Windows
alastair

47

วิธี Socket API

ดูhttps://stackoverflow.com/a/28950776/711085

ข้อเสีย:

  • ไม่ข้ามแพลตฟอร์ม
  • ต้องการรหัสทางเลือกเพิ่มเติมเชื่อมโยงกับการมีอยู่ของที่อยู่เฉพาะบนอินเทอร์เน็ต
  • สิ่งนี้จะไม่ทำงานหากคุณอยู่หลัง NAT
  • อาจสร้างการเชื่อมต่อ UDP ซึ่งไม่ขึ้นอยู่กับความพร้อมใช้งาน DNS ของ ISP (โดยปกติจะเป็น ISP) (ดูคำตอบอื่น ๆ สำหรับแนวคิดเช่นการใช้ 8.8.8.8: เซิร์ฟเวอร์ของ DNS (บังเอิญและ DNS) โดยบังเอิญ)
  • ตรวจสอบให้แน่ใจว่าคุณกำหนดที่อยู่ปลายทางไม่สามารถเข้าถึงได้เช่นที่อยู่ IP ตัวเลขที่รับประกันว่าจะไม่มีการใช้ข้อมูลจำเพาะ อย่าใช้โดเมนบางอย่างเช่น fakesubdomain.google.com หรือ somefakewebsite.com คุณจะยังคงส่งสแปมฝ่ายนั้น (ในปัจจุบันหรือในอนาคต) และส่งสแปมในกล่องเครือข่ายของคุณเองเช่นกันในกระบวนการ

วิธีการสะท้อนแสง

(โปรดทราบว่าสิ่งนี้ไม่ได้ตอบคำถาม OP ของที่อยู่ IP ในพื้นที่เช่น 192.168 ... มันให้ที่อยู่ IP สาธารณะของคุณซึ่งอาจเป็นที่ต้องการมากกว่านี้ขึ้นอยู่กับกรณีการใช้งาน)

คุณสามารถค้นหาบางไซต์เช่น whatismyip.com (แต่ใช้ API) เช่น:

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

หรือถ้าใช้ python2:

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

ข้อดี:

  • ข้อดีข้อหนึ่งของวิธีนี้คือข้ามแพลตฟอร์ม
  • มันทำงานจาก NATs หลังที่น่าเกลียด (เช่นเราเตอร์ที่บ้านของคุณ)

ข้อเสีย (และวิธีแก้ปัญหา):

  • รูปแบบที่จะไม่เปลี่ยนแปลง (เกือบจะไม่แน่นอน) และเซิร์ฟเวอร์ DNS ของคุณจะใช้งานได้ หนึ่งสามารถบรรเทาปัญหานี้ได้โดยการสอบถามตัวสะท้อนที่อยู่ IP ของบุคคลที่สามอื่น ๆ ในกรณีที่ล้มเหลว
  • เวกเตอร์จู่โจมที่เป็นไปได้ถ้าคุณไม่เคียวรีตัวสะท้อนสัญญาณหลายตัว (เพื่อป้องกันตัวสะท้อนแสงที่ไม่ปลอดภัยบอกคุณว่าที่อยู่ของคุณไม่ใช่สิ่งที่อยู่) หรือถ้าคุณไม่ใช้ HTTPS (เพื่อป้องกันการโจมตีแบบคนกลาง) เป็นเซิร์ฟเวอร์)

แก้ไข : ในขั้นต้นฉันคิดว่าวิธีการเหล่านี้ไม่ดีจริง ๆ (เว้นแต่คุณจะใช้ข้อผิดพลาดจำนวนมากรหัสอาจไม่เกี่ยวข้องหลายปีนับจากนี้) มันก่อให้เกิดคำถามว่า "อินเทอร์เน็ตคืออะไร" คอมพิวเตอร์อาจมีอินเทอร์เฟซมากมายชี้ไปที่เครือข่ายต่าง ๆ สำหรับคำอธิบายเพิ่มเติมเกี่ยวกับหัวข้ออย่างละเอียด google forgateways and routes. คอมพิวเตอร์อาจสามารถเข้าถึงเครือข่ายภายในผ่านเกตเวย์ภายในหรือเข้าถึงเว็บทั่วโลกผ่านเกตเวย์บนตัวอย่างเช่นเราเตอร์ (โดยปกติจะเป็นกรณี) ที่อยู่ IP ท้องถิ่นที่ OP ถามเกี่ยวกับมีการกำหนดอย่างดีเกี่ยวกับเลเยอร์ลิงก์เดียวดังนั้นคุณต้องระบุว่า ("มันคือการ์ดเครือข่ายหรือสายอีเธอร์เน็ตซึ่งเรากำลังพูดถึง?") . อาจมีหลายคำตอบที่ไม่ซ้ำกันสำหรับคำถามนี้ตามที่วางไว้ อย่างไรก็ตามที่อยู่ IP ทั่วโลกบนเว็บทั่วโลกน่าจะถูกกำหนดไว้อย่างดี (ในกรณีที่ไม่มีการกระจายตัวของเครือข่ายขนาดใหญ่): อาจเป็นเส้นทางย้อนกลับผ่านเกตเวย์ซึ่งสามารถเข้าถึง TLD ได้


นี่จะส่งคืนที่อยู่ LAN ของคุณหากคุณอยู่หลัง NAT หากคุณกำลังเชื่อมต่ออินเทอร์เน็ตคุณสามารถเชื่อมต่อกับบริการเว็บที่ส่งคืนหนึ่งในที่อยู่ IP สาธารณะของคุณ
Phihag

มันไม่ได้สร้างการเชื่อมต่อ TCP เพราะมันสร้างการเชื่อมต่อ UDP
Anuj Gupta

2
เป็นอีกทางเลือกหนึ่งในเวอร์ชันซ็อกเก็ต API ให้แทนที่ s.connect (('INSERT SOME TARGET WEBSITE.com', 0)) ด้วย s.setsockopt (socket.SOL_SOCKET, socket.O_BROADCAST, 1); s.connect ('< ออกอากาศ> ', 0)) เพื่อหลีกเลี่ยงการค้นหา DNS (ผมคิดว่าอาจจะมีปัญหากับการออกอากาศถ้ามีไฟร์วอลล์)
DLM

45

ถ้าคอมพิวเตอร์มีเส้นทางไปยังอินเทอร์เน็ตนี้จะเสมอการทำงานที่จะได้รับที่อยู่ในท้องถิ่นที่ต้องการแม้ว่า / etc / hosts ไม่ได้ตั้งค่าได้อย่างถูกต้อง

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
local_ip_address = s.getsockname()[0]

มันทำงานอย่างไร , 8.8.8.8เป็นเซิร์ฟเวอร์ของ Google DNS เราสามารถทำมันกับเซิร์ฟเวอร์ DNS ในประเทศหรือไม่
Ciasto piekarz

39

บน Linux:

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 

ดังนั้นนี่เป็นการเปิดซ็อกเก็ตอย่างมีประสิทธิภาพที่ไม่ทำอะไรเลยและคุณตรวจสอบข้อมูลดิบเกี่ยวกับซ็อกเก็ตนั้นเพื่อรับ IP ท้องถิ่นหรือไม่
เดฟ

1
ซ็อกเก็ตถูกเปิดเพื่อรับ fd เพื่อสื่อสารกับเคอร์เนล (ผ่านioctl) ซ็อกเก็ตไม่ได้ผูกอินเทอร์เฟซที่คุณต้องการข้อมูลเกี่ยวกับ addr มันเป็นเพียงกลไกการสื่อสารระหว่าง userspace และเคอร์เนล en.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c
tMC

2
ทำงานบน Python3 ได้ด้วยการดัดแปลงเพียงครั้งเดียว: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)ควรแทนที่ด้วยstruct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
pepoluan

1
@ChristianFischer ioctlเป็นอินเทอร์เฟซแบบดั้งเดิมฉันไม่เชื่อว่ารองรับ IPv6 และมีแนวโน้มที่จะไม่ ฉันคิดว่าวิธีที่ถูกต้องคือผ่าน Netlink ซึ่งไม่ได้ตรงไปตรงมามากใน Python ฉันคิดว่า libc ควรมีฟังก์ชั่นgetifaddrsที่สามารถเข้าถึงได้ผ่านctypesโมดูลpythons ซึ่งอาจใช้งานได้ - man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

1
@Maddy ioctl เป็นอินเทอร์เฟซแบบดั้งเดิมฉันไม่เชื่อว่ารองรับ IPv6 และมีแนวโน้มที่จะไม่ ฉันคิดว่าวิธีที่ 'ถูกต้อง' คือผ่าน Netlink ซึ่งไม่ได้ตรงไปตรงมามากใน Python ฉันคิดว่า libc ควรมีฟังก์ชั่น getifaddrs ซึ่งสามารถเข้าถึงได้ผ่านโมดูล pythons ctypes ซึ่งอาจใช้งานได้ - man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

27

ฉันใช้โมดูลต่อไปนี้:

#!/usr/bin/python
# module for getting the lan ip address of the computer

import os
import socket

if os.name != "nt":
    import fcntl
    import struct
    def get_interface_ip(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
                s.fileno(),
                0x8915,  # SIOCGIFADDR
                struct.pack('256s', bytes(ifname[:15], 'utf-8'))
                # Python 2.7: remove the second argument for the bytes call
            )[20:24])

def get_lan_ip():
    ip = socket.gethostbyname(socket.gethostname())
    if ip.startswith("127.") and os.name != "nt":
        interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
        for ifname in interfaces:
            try:
                ip = get_interface_ip(ifname)
                break;
            except IOError:
                pass
    return ip

ทดสอบกับ windows และ linux (และไม่จำเป็นต้องใช้โมดูลเพิ่มเติมสำหรับสิ่งเหล่านั้น) สำหรับใช้กับระบบที่อยู่ใน LAN แบบอิง IPv4

รายการคงที่ของชื่ออินเตอร์เฟสไม่สามารถใช้งานได้กับ linux รุ่นล่าสุดซึ่งได้นำการเปลี่ยนแปลง systemd v197 มาใช้เกี่ยวกับชื่ออินเตอร์เฟสที่สามารถคาดเดาได้ซึ่งชี้ให้เห็นโดย Alexanderอธิบาย ในกรณีเช่นนี้คุณจะต้องแทนที่ด้วยตนเองรายการที่มีชื่ออินเตอร์เฟซในระบบของคุณหรือใช้วิธีอื่นเช่นnetifaces


2
enp0s25นี้ไม่เข้ากันกับที่คาดการณ์ชื่ออินเตอร์เฟซลินุกซ์ใหม่เช่น สำหรับข้อมูลเพิ่มเติมดูwiki.archlinux.org/index.php/Network_Configuration#Device_names
Alexander

2
ฉันใช้ python 3.4 และส่วน 'struct.pack (... )' จำเป็นต้องเปลี่ยนเป็น 'struct.pack (' 256s ', ไบต์ (ifname [: 15],' utf-8 '))' ดูคำถามนี้: stackoverflow.com/q/27391167/76010
Bakanekobrain

1
บน Raspbian w / Python 2.7.3 - bytes () ไม่ชอบอาร์กิวเมนต์ที่ 2 แต่สิ่งนี้ใช้ได้: struct.pack('256s', bytes(ifname[:15]))
colm.anseo

24

ฉันใช้สิ่งนี้กับเครื่อง Ubuntu ของฉัน:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

มันใช้งานไม่ได้


ดีและเรียบง่าย ใช้งานได้กับ Linux AMI ของ Amazon เช่นกัน แต่ถ้าฉันรูต มิฉะนั้นฉันจะได้รับข้อผิดพลาด: 'sh: ifconfig: ไม่พบคำสั่ง'
IgorGanapolsky

ดังนั้นคุณควรใช้ "/ sbin / ifconfig" เช่น gavaletz กล่าว มันยังใช้งานได้กับ Red Hat 4.1.2-48
IgorGanapolsky

7
เลิกใช้ตั้งแต่ 2.6 ใช้โมดูลย่อยเพื่อเรียกใช้คำสั่ง
Colin Dunklau

5
และ ifconfig ก็เลิกเช่นกัน ใช้ iproute2
Helmut Grohne

รับ ips ทั้งหมด: import sh; [ip.split () [1] [5:] สำหรับ ip ในตัวกรอง (lambda x: 'inet addr' ใน x, sh.ifconfig (). split ("\ n"))]
Gabriel Littman

20

หากคุณไม่ต้องการใช้แพ็คเกจภายนอกและไม่ต้องการพึ่งพาเซิร์ฟเวอร์อินเทอร์เน็ตภายนอกสิ่งนี้อาจช่วยได้ เป็นตัวอย่างรหัสที่ฉันพบในGoogle Code Searchและปรับเปลี่ยนเพื่อส่งคืนข้อมูลที่ต้องการ:

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break

การใช้งาน:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

ในขณะที่มันอาศัยอยู่windllนี้จะทำงานเฉพาะบน Windows


วิธีแก้ปัญหาหนึ่งซับด้านบนมักใช้กับ windows ได้ มันเป็น Linux ที่มีปัญหา
ricree

14
+1 เทคนิคนี้อย่างน้อยพยายามที่จะส่งคืนที่อยู่ทั้งหมดบนเครื่อง
เจสันคูมบ์สอาร์

1
สคริปต์นี้ล้มเหลวในเครื่องของฉันหลังจากส่งคืนที่อยู่แรก ข้อผิดพลาดคือ "AttributeError: วัตถุ 'LP_IP_ADDR_STRING' ไม่มีแอตทริบิวต์ 'ipAddress'" ฉันสงสัยว่ามีบางอย่างเกี่ยวกับที่อยู่ IPv6
46432 Jason R. Coombs

1
มันกลับกลายเป็นว่าสิ่งใดก็ตามยกเว้นที่อยู่ IP แรก adNode ไม่ได้ถูกยกเลิกการลงทะเบียน เพิ่มอีกหนึ่งบรรทัดในตัวอย่างในขณะที่ลูปและใช้งานได้สำหรับฉัน: adNode = adNode.contents
Jason R. Coombs

18

บน Debian (ทดสอบ) และฉันสงสัยว่า Linux ส่วนใหญ่ ..

import commands

RetMyIP = commands.getoutput("hostname -I")

บน MS Windows (ทดสอบแล้ว)

import socket

socket.gethostbyname(socket.gethostname())

1
ใช้งานไม่ได้กับ macOS:hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
ดีเร็ก朕會功夫

18

รุ่นที่ฉันไม่เชื่อว่าโพสต์แล้ว ฉันทดสอบด้วย python 2.7 บน Ubuntu 12.04

พบวิธีแก้ปัญหานี้ได้ที่: http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

ตัวอย่างผลลัพธ์:

>>> get_ip_address('eth0')
'38.113.228.130'

2
ใช้งานได้กับ Python3, Ubuntu 18.04; สตริงต้องเป็นไบต์: >>> socket.inet_ntoa (fcntl.ioctl (s.fileno (), 0x8915, struct.pack ('256s', 'enp0s31f6' [: 15] .encode ('utf-8')) )) [20:24]) '192.168.1.1'
เอกสาร

12

ความหลากหลายของคำตอบของ ninjagecko สิ่งนี้ควรทำงานบน LAN ใด ๆ ที่อนุญาตการออกอากาศ UDP และไม่ต้องการการเข้าถึงที่อยู่บน LAN หรืออินเทอร์เน็ต

import socket
def getNetworkIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

print (getNetworkIp())

รอ<broadcast>ชื่อโฮสต์ที่ถูกต้องเป็นอย่างไร !! ชื่อโฮสต์ด้วยวาจาเหล่านี้มีจำนวนเท่าใด
Dev Aggarwal

สิ่งนี้ใช้ได้กับฉันใน Ubuntu 20.04 - รับ 192.168.0.24 ไม่ใช่ 127.0.0.1
Lewis Morris

8

ฉันเกรงว่าจะไม่มีวิธีที่ดีในการทำสิ่งนี้นอกเหนือจากการเชื่อมต่อกับคอมพิวเตอร์เครื่องอื่นและให้ส่งที่อยู่ IP ของคุณ ตัวอย่างเช่น: findmyipaddress findmyipaddressโปรดทราบว่าสิ่งนี้จะไม่ทำงานหากคุณต้องการที่อยู่ IP ที่อยู่หลัง NAT เว้นแต่คอมพิวเตอร์ที่คุณกำลังเชื่อมต่ออยู่จะอยู่หลัง NAT เช่นกัน

นี่คือหนึ่งในวิธีการแก้ปัญหาที่ทำงานในลินุกซ์: ได้รับที่อยู่ IP ที่เกี่ยวข้องกับการเชื่อมต่อเครือข่าย


8

วิธีง่ายๆในการสร้างเอาต์พุต "clean" ผ่าน utils ของบรรทัดรับคำสั่ง:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips

มันจะแสดงที่อยู่ IPv4 ทั้งหมดในระบบ


1
จะไม่แสดงที่อยู่ IPv4 ทั้งหมดเนื่องจาก ifconfig จะบอกคุณเกี่ยวกับที่อยู่หลักเท่านั้น คุณต้องใช้ "ip" จาก iproute2 เพื่อดูที่อยู่ทั้งหมด
Helmut Grohne

นั่นเป็นนรกจำนวนมากสำหรับคำถามที่ถามถึงห้องสมุดมาตรฐาน ... นอกจากนี้การแยก ifconfig นั้นไม่สามารถพกพาได้และจะไม่สามารถทำงานได้อย่างน่าเชื่อถือในเครื่องเดียว
Dominik George

7

FYI ฉันสามารถตรวจสอบว่าวิธีการ:

import socket
addr = socket.gethostbyname(socket.gethostname())

ทำงานใน OS X (10.6,10.5), Windows XP และบนเซิร์ฟเวอร์แผนก RHEL ที่ได้รับการดูแลเป็นอย่างดี มันไม่ได้ทำงานบน CentOS VM ที่น้อยมากที่ฉันเพิ่งทำแฮ็คเคอร์เนล ดังนั้นสำหรับตัวอย่างนั้นคุณสามารถตรวจสอบที่อยู่ 127.0.0.1 และในกรณีนั้นให้ทำดังต่อไปนี้:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

แล้วแยกที่อยู่ IP จากเอาท์พุท ควรสังเกตว่า ifconfig ไม่ได้อยู่ใน PATH ของผู้ใช้ปกติโดยค่าเริ่มต้นและนั่นคือเหตุผลที่ฉันให้เส้นทางเต็มในคำสั่ง ฉันหวังว่านี่จะช่วยได้.


7

นี่เป็นคำตอบที่แตกต่างจากคำตอบของ UnkwnTech - มันมีget_local_addr()ฟังก์ชั่นซึ่งจะส่งคืนที่อยู่ IP หลักของ LAN ของโฮสต์ ฉันโพสต์เพราะเพิ่มสิ่งต่าง ๆ : การสนับสนุน ipv6, การจัดการข้อผิดพลาด, ละเว้น localhost / linklocal addrs และใช้ TESTNET addr (rfc5737) เพื่อเชื่อมต่อ

# imports
import errno
import socket
import logging

# localhost prefixes
_local_networks = ("127.", "0:0:0:0:0:0:0:1")

# ignore these prefixes -- localhost, unspecified, and link-local
_ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:")

def detect_family(addr):
    if "." in addr:
        assert ":" not in addr
        return socket.AF_INET
    elif ":" in addr:
        return socket.AF_INET6
    else:
        raise ValueError("invalid ipv4/6 address: %r" % addr)

def expand_addr(addr):
    """convert address into canonical expanded form --
    no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups.
    """
    family = detect_family(addr)
    addr = socket.inet_ntop(family, socket.inet_pton(family, addr))
    if "::" in addr:
        count = 8-addr.count(":")
        addr = addr.replace("::", (":0" * count) + ":")
        if addr.startswith(":"):
            addr = "0" + addr
    return addr

def _get_local_addr(family, remote):
    try:
        s = socket.socket(family, socket.SOCK_DGRAM)
        try:
            s.connect((remote, 9))
            return s.getsockname()[0]
        finally:
            s.close()
    except socket.error:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        return None

def get_local_addr(remote=None, ipv6=True):
    """get LAN address of host

    :param remote:
        return  LAN address that host would use to access that specific remote address.
        by default, returns address it would use to access the public internet.

    :param ipv6:
        by default, attempts to find an ipv6 address first.
        if set to False, only checks ipv4.

    :returns:
        primary LAN address for host, or ``None`` if couldn't be determined.
    """
    if remote:
        family = detect_family(remote)
        local = _get_local_addr(family, remote)
        if not local:
            return None
        if family == socket.AF_INET6:
            # expand zero groups so the startswith() test works.
            local = expand_addr(local)
        if local.startswith(_local_networks):
            # border case where remote addr belongs to host
            return local
    else:
        # NOTE: the two addresses used here are TESTNET addresses,
        #       which should never exist in the real world.
        if ipv6:
            local = _get_local_addr(socket.AF_INET6, "2001:db8::1234")
            # expand zero groups so the startswith() test works.
            if local:
                local = expand_addr(local)
        else:
            local = None
        if not local:
            local = _get_local_addr(socket.AF_INET, "192.0.2.123")
            if not local:
                return None
    if local.startswith(_ignored_networks):
        return None
    return local

ฉันคิดว่านี่อาจเป็นคำตอบที่ดีจริงๆ .. แต่มันกลับมาเสมอNone
เจมี่ลินด์เซย์

@JamieLindsey คุณมีรายละเอียดบางอย่างเกี่ยวกับระบบปฏิบัติการของคุณการกำหนดค่าเครือข่ายหรือไม่? นอกจากนี้สิ่งที่ไม่ชอบget_local_addr(remove="www.google.com")ผลตอบแทนอะไร? การบันทึกการsocket.errorโยนโดย _get_local_addr () อาจช่วยในการวินิจฉัย
Eli Collins

6
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

1
อืม ... บนเซิร์ฟเวอร์ที่มี NIC สองตัวสิ่งนี้จะให้หนึ่งในที่อยู่ IP ที่กำหนด แต่ทำซ้ำสามครั้ง บนแล็ปท็อปของฉันให้ '127.0.1.1' (ทำซ้ำสามครั้ง ... ) ...
bryn

ให้ฉัน['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']บนเดสก์ท็อป Windows
Nakilon

5

สิ่งนี้จะใช้ได้กับกล่อง linux ส่วนใหญ่:

import socket, subprocess, re
def get_ipv4_address():
    """
    Returns IP address(es) of current machine.
    :return:
    """
    p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
    ifc_resp = p.communicate()
    patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    resp = patt.findall(ifc_resp[0])
    print resp

get_ipv4_address()

5

คำตอบนี้เป็นความพยายามส่วนตัวของฉันในการแก้ปัญหาในการรับ LAN IP ตั้งแต่socket.gethostbyname(socket.gethostname())กลับมาด้วย 127.0.0.1 วิธีนี้ไม่ต้องใช้อินเทอร์เน็ตเพียงเชื่อมต่อ LAN รหัสนี้ใช้สำหรับ Python 3.x แต่สามารถแปลงได้อย่างง่ายดายสำหรับ 2.x ใช้การออกอากาศ UDP:

import select
import socket
import threading
from queue import Queue, Empty

def get_local_ip():
        def udp_listening_server():
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.bind(('<broadcast>', 8888))
            s.setblocking(0)
            while True:
                result = select.select([s],[],[])
                msg, address = result[0][0].recvfrom(1024)
                msg = str(msg, 'UTF-8')
                if msg == 'What is my LAN IP address?':
                    break
            queue.put(address)

        queue = Queue()
        thread = threading.Thread(target=udp_listening_server)
        thread.queue = queue
        thread.start()
        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        waiting = True
        while waiting:
            s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888))
            try:
                address = queue.get(False)
            except Empty:
                pass
            else:
                waiting = False
        return address[0]

if __name__ == '__main__':
    print(get_local_ip())

1
จะเกิดอะไรขึ้นถ้าคุณรันสิ่งนี้พร้อมกันในสองเครื่องบนเครือข่ายเดียวกัน เมื่อคุณส่งข้อความของคุณบนเครือข่ายเครื่องทั้งหมดจะได้รับ 'ที่อยู่ IP ของฉัน LAN คืออะไร udp_listening_server ของคุณสามารถตอบ 'ที่อยู่ IP ของคุณคือ xxx' ถึงข้อความ
Nicolas Defranoux

4

127.0.1.1 เป็นที่อยู่ IP จริงของคุณ โดยทั่วไปคอมพิวเตอร์สามารถมีที่อยู่ IP จำนวนเท่าใดก็ได้ คุณสามารถกรองพวกเขาสำหรับเครือข่ายส่วนตัว - 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 และ 192.168.0.0/16

อย่างไรก็ตามไม่มีวิธีข้ามแพลตฟอร์มเพื่อรับที่อยู่ IP ทั้งหมด บน Linux คุณสามารถใช้SIOCGIFCONFioctl


2
เขาหมายถึง IP ที่มองเห็นจากภายนอก โดยทั่วไปช่วง 127. *. *. * หมายถึง localhost หรือเครือข่ายภายในซึ่งเห็นได้ชัดว่าไม่ใช่สิ่งที่เขาต้องการ
Cerin

4

การปรับแต่งเล็กน้อยของเวอร์ชันคำสั่งที่ใช้คำสั่ง IP และส่งคืนที่อยู่ IPv4 และ IPv6:

import commands,re,socket

#A generator that returns stripped lines of output from "ip address show"
iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n'))

#Turn that into a list of IPv4 and IPv6 address/mask strings
addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines))
#addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64']

#Get a list of IPv4 addresses as (IPstring,subnetsize) tuples
ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)]
#ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)]

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]

4

คุณสามารถใช้คำสั่ง "ip route" บน GNU / Linux เพื่อทราบที่อยู่ IP ปัจจุบันของคุณ

นี่แสดง IP ที่กำหนดให้กับอินเตอร์เฟสโดยเซิร์ฟเวอร์ DHCP ที่ทำงานบนเราเตอร์ / โมเด็ม โดยปกติ "192.168.1.1/24" เป็น IP สำหรับเครือข่ายท้องถิ่นโดยที่ "24" หมายถึงช่วงของที่อยู่ IP ที่เป็นไปได้ที่เซิร์ฟเวอร์ DHCP กำหนดภายในช่วงมาสก์

นี่คือตัวอย่าง: โปรดทราบว่า PyNotify เป็นเพียงส่วนเสริมเพื่อให้ตรงประเด็นและไม่จำเป็นเลย

#! /usr/bin/env python

import sys , pynotify

if sys.version_info[1] != 7:
   raise RuntimeError('Python 2.7 And Above Only')       

from subprocess import check_output # Available on Python 2.7+ | N/A 

IP = check_output(['ip', 'route'])
Split_Result = IP.split()

# print Split_Result[2] # Remove "#" to enable

pynotify.init("image")
notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
notify.show()    

ข้อดีของการทำเช่นนี้คือคุณไม่จำเป็นต้องระบุส่วนต่อประสานเครือข่าย มันมีประโยชน์มากเมื่อใช้ซ็อกเก็ตเซิร์ฟเวอร์

คุณสามารถติดตั้ง PyNotify โดยใช้ easy_install หรือ Pip:

easy_install py-notify

หรือ

pip install py-notify

หรือภายในสคริปต์ไพ ธ อน / ล่าม

from pip import main

main(['install', 'py-notify'])

4

หากคุณกำลังมองหาที่อยู่ IPV4 แตกต่างจากที่อยู่ IP ในพื้นที่ของคุณ127.0.0.1นี่คือรหัสงูหลามที่เรียบร้อย:

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]

ซึ่งสามารถเขียนในบรรทัดเดียว:

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]

แม้ว่าคุณจะใส่localhostใน/etc/hostnameรหัสจะยังคงให้อยู่ในท้องถิ่นของคุณ


4

สำหรับลินุกซ์, คุณก็สามารถใช้check_outputของhostname -Iคำสั่งระบบเช่นดังนั้น:

from subprocess import check_output
check_output(['hostname', '-I'])

สำหรับ googler ฉันรู้ว่าคำถามนี้สำหรับโซลูชันข้ามแพลตฟอร์ม
Kasper Skytte Andersen

3

หมายเหตุ: นี่ไม่ได้ใช้ไลบรารีมาตรฐาน แต่ค่อนข้างง่าย

$ pip ติดตั้ง pif

from pif import get_public_ip
get_public_ip()

3
คำถามเกี่ยวกับการค้นหา IP โดยใช้ stdlib
Alexandru Chirila

3

netifaces สามารถใช้ได้ผ่าน pip และ easy_install (ฉันรู้ว่ามันไม่ได้อยู่ในฐาน แต่มันอาจจะคุ้มค่ากับการติดตั้ง)

netifaces มีสิ่งแปลกประหลาดบางอย่างข้ามแพลตฟอร์ม:

  • อาจไม่รวมอินเทอร์เฟซ localhost / loop-back (Cygwin)
  • ที่อยู่มีการระบุไว้ต่อโพรโทคอล (เช่น IPv4, IPv6) และโพรโทคอลจะแสดงรายการต่ออินเทอร์เฟซ ในบางระบบ (Linux) แต่ละคู่ของโปรโตคอล - อินเตอร์เฟสมีอินเทอร์เฟซที่เกี่ยวข้อง (ใช้สัญกรณ์ interface_name: n) ในขณะที่บนระบบอื่น (Windows) อินเทอร์เฟซเดียวจะมีรายการที่อยู่สำหรับแต่ละโปรโตคอล ในทั้งสองกรณีมีรายการโปรโตคอล แต่อาจมีเพียงองค์ประกอบเดียว

นี่คือโค้ด netifaces ที่จะเล่นกับ:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()

# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]

# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]

iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.

รหัสด้านบนไม่ได้แมปที่อยู่กลับไปที่ชื่ออินเทอร์เฟซ (มีประโยชน์สำหรับการสร้างกฎ ebtables / iptables ได้ทันที) ดังนั้นนี่คือเวอร์ชันที่เก็บข้อมูลข้างต้นด้วยชื่ออินเตอร์เฟสใน tuple:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
ifaces = netifaces.interfaces()

# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]

# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]

iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]

และไม่ฉันไม่รักความเข้าใจในรายการ มันเป็นเพียงวิธีที่สมองของฉันทำงานวันนี้

ตัวอย่างต่อไปนี้จะพิมพ์ออกมาทั้งหมด:

from __future__ import print_function  # For 2.x folks
from pprint import pprint as pp

print('\nifaces = ', end='')
pp(ifaces)

print('\nif_addrs = ', end='')
pp(if_addrs)

print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)

print('\niface_addrs = ', end='')
pp(iface_addrs)

สนุก!


netifaces ทำให้ชีวิตง่ายขึ้นมากในขณะที่จัดการกับปัญหานี้
Drake Guan

3

Python รุ่น 3.4 ใช้แพ็คเกจ asyncio ที่เพิ่งเปิดตัวใหม่

async get_local_ip():
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        asyncio.DatagramProtocol,
        remote_addr=('8.8.8.8', 80))
    result = transport.get_extra_info('sockname')[0])
    transport.close()
    return result

นี้อยู่บนพื้นฐานของ UnkwnTech คำตอบที่ดี


3

เพื่อรับที่อยู่ ip คุณสามารถใช้คำสั่งเชลล์โดยตรงในไพ ธ อน :

import socket, subprocess

def getIpAndHostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = getIpAndHostname()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.