Bekerja dengan Antaramuka Rangkaian di Java

1. Gambaran keseluruhan

Dalam artikel ini, kami akan memfokuskan pada antarmuka rangkaian dan cara mengaksesnya secara terprogram di Java.

Ringkasnya, antara muka rangkaian adalah titik interkoneksi antara peranti dan mana-mana sambungan rangkaiannya .

Dalam bahasa sehari-hari, kita merujuknya dengan istilah Network Interface Cards (NIC) - tetapi semuanya tidak boleh berbentuk perkakasan.

Sebagai contoh, localhost IP 127.0.0.1 yang popular , yang banyak kita gunakan dalam menguji aplikasi web dan rangkaian adalah antara muka loopback - yang bukan antara muka perkakasan langsung.

Sudah tentu, sistem sering mempunyai banyak sambungan rangkaian aktif, seperti ethernet berwayar, WIFI, Bluetooth, dll.

Di Java, API utama yang dapat kita gunakan untuk berinteraksi secara langsung dengan mereka adalah kelas java.net.NetworkInterface . Oleh itu, untuk memulakan dengan cepat, mari kita import pakej lengkap:

import java.net.*;

2. Mengapa Mengakses Antaramuka Rangkaian?

Sebilangan besar program Java tidak mungkin berinteraksi dengan mereka secara langsung; namun ada senario khas apabila kita memerlukan akses tahap rendah seperti ini.

Yang paling luar biasa adalah di mana sistem mempunyai banyak kad dan anda ingin mempunyai kebebasan untuk memilih antara muka tertentu untuk menggunakan soket . Dalam senario seperti itu, kita biasanya mengetahui namanya tetapi tidak semestinya alamat IP.

Biasanya, apabila kita ingin membuat sambungan soket ke alamat pelayan tertentu:

Socket socket = new Socket(); socket.connect(new InetSocketAddress(address, port));

Dengan cara ini, sistem akan memilih alamat tempatan yang sesuai, mengikatnya dan berkomunikasi dengan pelayan melalui antara muka rangkaiannya. Walau bagaimanapun, pendekatan ini tidak membenarkan kita memilih pilihan kita sendiri.

Kami akan membuat andaian di sini; kami tidak tahu alamatnya tetapi kami tahu namanya. Hanya untuk tujuan demonstrasi, mari kita andaikan kita mahu sambungan lebih antara muka gelung balik, oleh konvensyen, namanya adalah lo , sekurang-kurangnya pada sistem Linux dan Windows, OSX pada ia adalah lo0 :

NetworkInterface nif = NetworkInterface.getByName("lo"); Enumeration nifAddresses = nif.getInetAddresses(); Socket socket = new Socket(); socket.bind(new InetSocketAddress(nifAddresses.nextElement(), 0)); socket.connect(new InetSocketAddress(address, port));

Oleh itu, kami mengambil antara muka rangkaian yang dilampirkan ke lo dulu, mengambil alamat yang dilampirkan padanya, membuat soket, mengikatnya ke mana-mana alamat yang dihitung yang tidak kita ketahui pada waktu penyusunan dan kemudian menyambung.

A NetworkInterface objek mengandungi nama dan satu set alamat IP yang diberikan kepadanya. Oleh itu, mengikat mana-mana alamat ini akan menjamin komunikasi melalui antara muka ini.

Ini sebenarnya tidak mengatakan apa-apa yang istimewa mengenai API. Kami tahu bahawa jika kami mahu alamat tempatan kami menjadi hos tempatan, coretan pertama akan mencukupi sekiranya kami hanya menambahkan kod pengikat.

Selain itu, kita tidak semestinya perlu melalui beberapa langkah kerana localhost mempunyai satu alamat yang terkenal, 127.0.0.1 dan kita boleh mengikat soket dengan mudah.

Namun, dalam kes anda, lo mungkin mungkin mewakili antara muka lain seperti Bluetooth - net1 , rangkaian tanpa wayar - net0 atau ethernet - eth0 . Dalam kes seperti itu, anda tidak akan mengetahui alamat IP pada waktu kompilasi.

3. Mengambil Antaramuka Rangkaian

Di bahagian ini, kami akan meneroka API lain yang tersedia untuk mendapatkan antara muka yang tersedia. Pada bahagian sebelumnya, kami melihat salah satu daripada pendekatan ini; yang getByName () kaedah statik.

Perlu diperhatikan bahawa kelas NetworkInterface tidak mempunyai konstruktor awam, jadi kita tentu saja tidak dapat membuat contoh baru. Sebagai gantinya, kami akan menggunakan API yang tersedia untuk mendapatkannya.

API yang kami lihat sejauh ini digunakan untuk mencari antara muka rangkaian dengan nama yang ditentukan:

@Test public void givenName_whenReturnsNetworkInterface_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); assertNotNull(nif); }

Ia mengembalikan nol jika tiada nama:

@Test public void givenInExistentName_whenReturnsNull_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("inexistent_name"); assertNull(nif); }

API kedua adalah getByInetAddress () , ia juga memerlukan kami memberikan parameter yang diketahui, kali ini kami dapat memberikan alamat IP:

@Test public void givenIP_whenReturnsNetworkInterface_thenCorrect() { byte[] ip = new byte[] { 127, 0, 0, 1 }; NetworkInterface nif = NetworkInterface.getByInetAddress( InetAddress.getByAddress(ip)); assertNotNull(nif); }

Atau nama hos:

@Test public void givenHostName_whenReturnsNetworkInterface_thenCorrect() { NetworkInterface nif = NetworkInterface.getByInetAddress( InetAddress.getByName("localhost")); assertNotNull(nif); }

Atau jika anda khusus mengenai localhost:

@Test public void givenLocalHost_whenReturnsNetworkInterface_thenCorrect() { NetworkInterface nif = NetworkInterface.getByInetAddress( InetAddress.getLocalHost()); assertNotNull(nif); }

Alternatif lain juga untuk menggunakan antara muka loopback secara eksplisit:

@Test public void givenLoopBack_whenReturnsNetworkInterface_thenCorrect() { NetworkInterface nif = NetworkInterface.getByInetAddress( InetAddress.getLoopbackAddress()); assertNotNull(nif); }

Pendekatan ketiga yang hanya tersedia sejak Java 7 adalah mendapatkan antara muka rangkaian dengan indeksnya:

NetworkInterface nif = NetworkInterface.getByIndex(int index);

Pendekatan terakhir melibatkan penggunaan getNetworkInterfaces API. Ia mengembalikan Penghitungan semua antara muka rangkaian yang ada dalam sistem. Kita mesti mengambil objek yang dikembalikan dalam satu gelung, simpulan bahasa standard menggunakan Senarai :

Enumeration nets = NetworkInterface.getNetworkInterfaces(); for (NetworkInterface nif: Collections.list(nets)) { //do something with the network interface }

4. Parameter Antara Muka Rangkaian

Terdapat banyak maklumat berharga yang dapat kita perolehi dari satu setelah mengambil objeknya. Salah satu yang paling berguna adalah senarai alamat IP yang diberikan kepadanya .

Kita boleh mendapatkan alamat IP menggunakan dua API. API pertama ialah getInetAddresses () . Ia mengembalikan Penghitungan daripada InetAddress peristiwa yang kami boleh memproses yang kami anggap patut:

@Test public void givenInterface_whenReturnsInetAddresses_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); Enumeration addressEnum = nif.getInetAddresses(); InetAddress address = addressEnum.nextElement(); assertEquals("127.0.0.1", address.getHostAddress()); }

API kedua ialah getInterfaceAddresses () . Ia mengembalikan List of InterfaceAddress keadaan yang lebih berkuasa daripada InetAddress keadaan. Sebagai contoh, selain dari alamat IP, anda mungkin berminat dengan alamat siaran:

@Test public void givenInterface_whenReturnsInterfaceAddresses_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); List addressEnum = nif.getInterfaceAddresses(); InterfaceAddress address = addressEnum.get(0); InetAddress localAddress=address.getAddress(); InetAddress broadCastAddress = address.getBroadcast(); assertEquals("127.0.0.1", localAddress.getHostAddress()); assertEquals("127.255.255.255",broadCastAddress.getHostAddress()); }

Kita dapat mengakses parameter rangkaian mengenai antara muka di luar nama dan alamat IP yang diberikan kepadanya. Untuk memeriksa sama ada ia berfungsi dan berjalan:

@Test public void givenInterface_whenChecksIfUp_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); assertTrue(nif.isUp()); }

Untuk memeriksa apakah itu antara muka loopback:

@Test public void givenInterface_whenChecksIfLoopback_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); assertTrue(nif.isLoopback()); }

Untuk memeriksa sama ada ia mewakili sambungan rangkaian titik ke titik:

@Test public void givenInterface_whenChecksIfPointToPoint_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); assertFalse(nif.isPointToPoint()); }

Atau jika ia antara muka maya:

@Test public void givenInterface_whenChecksIfVirtual_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); assertFalse(nif.isVirtual()); }

Untuk memeriksa sama ada multicasting disokong:

@Test public void givenInterface_whenChecksMulticastSupport_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); assertTrue(nif.supportsMulticast()); }

Atau untuk mendapatkan semula alamat fizikalnya, biasanya disebut alamat MAC:

@Test public void givenInterface_whenGetsMacAddress_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("lo"); byte[] bytes = nif.getHardwareAddress(); assertNotNull(bytes); }

Parameter lain ialah Unit Penghantaran Maksimum yang menentukan ukuran paket terbesar yang dapat dihantar melalui antara muka ini:

@Test public void givenInterface_whenGetsMTU_thenCorrect() { NetworkInterface nif = NetworkInterface.getByName("net0"); int mtu = nif.getMTU(); assertEquals(1500, mtu); }

5. Kesimpulan

Dalam artikel ini, kami telah menunjukkan antara muka rangkaian, cara mengaksesnya secara terprogram dan mengapa kami perlu mengaksesnya.

Kod sumber lengkap dan sampel yang digunakan dalam artikel ini terdapat dalam projek Github.