[Cozuldu] Ip Location Lookup

Başlatan mustafayilmaz, 20 Kasım 2011 - 02:00:38

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

mustafayilmaz

Selamlar;

Bash ile bir Ip location lookup script'i yazmaya çalışıyorum.

Ip'lerin tutulduğu bir dosya var. ip.txt 
201.16.14.15
103.43.53.65
54.65.76.87
..
..
..

diye gidiyor.

Bir de internetten bulduğum Ip-location dosyaları var. Hemen onun da örneğini vereyim;
"16777216,""17367039"",""AU"",""AUS"",""AUSTRALIA"""

"17367040,""17432575"",""MY"",""MYS"",""MALAYSIA"""

"17432576,""17498111"",""AU"",""AUS"",""AUSTRALIA"""

"17498112,""17563647"",""KR"",""KOR"",""REPUBLIC OF KOREA"""

"17563648,""17825791"",""CN"",""CHN"",""CHINA"""

"17825792,""18087935"",""KR"",""KOR"",""REPUBLIC OF KOREA"""

"18087936,""18153471"",""AU"",""AUS"",""AUSTRALIA"""

"18153472,""18219007"",""JP"",""JPN"",""JAPAN"""     diye gidiyor...


Bu dosyadaki numaralar decimal'e çevrilmiş halleri..
İlk değer ile ikinci değer arasında kalan aralık o ülkeye ait oluyor.

Gelelim sorularıma : )

ben bütün ip.txt içindeki ip'leri nasıl decimal'e çeviririm ve çevirdikten sonra nasıl ip-location dosyasıyla eşleştirip, ekrana ip'nin hangi ülkeye ait olduğunu yazdırabilirim..

Fikir ve önerilerinizi bekliyorum.. : )

ironic

#1
Merhaba, bir şeyler yapmaya çalıştım. Tam olarak doğru değerleri eşliyor mu bakamadım . Umarım çalışır. :)


#!/bin/bash

# not: dosyalar betikle aynı dizinde değilse, dosyalar tam konumuyla beraber girilmeli.
IP_DOSYASI=ip.txt
DECIMAL_DOSYASI=ip_dec.txt
GECICI_DOSYA=/tmp/dec_list # betik decimal dosyasını düzenleyip oluşturacak.

declare -a ip_dec_list ip_list # ip lere ait decimal değerleri ve  ip dizisi

ip_list=(  $(sed '/^$/d' "${IP_DOSYASI}") ) # ip adreslerini listeye ekledik.

for ((i=0; i<${#ip_list[@]}; i++))
{
  IP=${ip_list[$i]//./ }
  set -- $IP
  ip_dec_list+=( $(( 16777216 * $1 + 65536 * $2 + 256 * $3 + $4 )) )
}

# sed ile tırnak işaretlerini ve boş satırları temizledik
#ülke adlarındaki boşlukları '_' ile değiştirdik ve geçici dosyayı oluşturduk.
sed -e '/^$/d' -e 's:\"::g;s: :_:g' < "${DECIMAL_DOSYASI}" > "${GECICI_DOSYA}"

# ip nin decimal değerini decimal dosyasındaki değerlerle  satır satır karşılaştırıyoruz.
# çakışma varsa bilgileri ekrana yazacak.
while read -r bilgi
do
  # decimal dosyasındaki ulke bilgilerini vs. yeni değişkenlere atadık.
  export $(awk 'BEGIN {FS=",";} \
    {printf "ip_ara1=%s\nip_ara2=%s\nulke_kod1=%s\nulke_kod2=%s\nulke_kod3=%s\n", $1,$2,$3,$4, $5 ;}' <<<$bilgi)
  for ((i=0; i<${#ip_dec_list[@]}; i++))
  {
    if  [[ ${ip_dec_list[$i]} -ge $ip_ara1 ]]  &&  [[ ${ip_dec_list[$i]} -le $ip_ara2 ]]
    then
      printf '\n%s\n%-12s%s\n%-12s%s\n%-12s%s\n%s\n ' \
          '*******************************************' \
        "IP  " "= ${ip_list[$i]}" \
        "IP Decimal"  "= ${ip_dec_list[$i]} " \
        "Ulke  " "= ${ulke_kod3//_/ } - ${ulke_kod1} (${ulke_kod2}) " \
        '*******************************************'
    fi
  }
done < "${GECICI_DOSYA}"

örnek çıktı: (ip ve decimal değerleri doğru değil :) )



*******************************************
IP          = 103.43.53.65
IP Decimal  = 1730884929
Ulke        = AUSTRALIA - AU (AUS)
*******************************************

*******************************************
IP          = 201.16.14.15
IP Decimal  = 3373272591
Ulke        = REPUBLIC OF KOREA - KR (KOR)
*******************************************

mustafayilmaz

Üstad çok teşekkür ederim.. Yazdığın script acayip işime yaradı.. 

Hakikaten ne kadar teşekkür etsem az..

Ama problem de yok değil : )  İnanılmaz yavaş işliyor script.. Tek satırlık bir işlem bile bayağı vakit alıyor.. Bunu iyileştirmek için bir öneriniz var mı ? Aslında yavaş çalışması çok önemli değil şimdilik fakat ileride belki bir seferde 1000'in üzerinde ip ayıklaması gerekecek. Bu da epey bir vakit alır..

Önerilerinizi bekliyorum..
@ironic sana da tekrar tekrar teşekkürler.. : )

ironic

İşlemcim çok kuvvetli olmamasına rağmen  (tek çekirdek, 2.0 GHz) bende hissedilir düzeyde bir yavaşlık yoktu. Kodlar üzerinde bugün bayağı iyileştirmeler yaptım. Birkaç yerde hatalar yapmışım onları düzelttim. Yaptığım denemelerde sonuçları doğru buldu.

Bir önceki iletimi güncelledim yeni kodları ordan alabilirsiniz.

kolay gelsin.

mustafayilmaz

Hocam

Ben de bugün uğraşırken farkettim decimal sayıları yanlış hesaplıyordu. Ben de bir başka yöntemle bu yazıyı yazmadan az önce çözdüm bu sıkıntıyı.
Biraz daha uğraştıktan sonra burada da paylaşacağım. 
Sizin güncellediğiniz script'i indirip denedim.
Sorun sanırım kullandığımız döngülerden kaynaklı.. Kusura bakmayın ben programlama mantığından pek anlamıyorum. Ama 3.2.1.4 ip sini arattığımda 5-6 saniyede ekrana basıyor ancak 200.230.65.32 gibi decimal değeri büyük olan bir ip girdiğimde 10 dakikayı geçiyor bulup ekrana yazdırması..
Decimal IP listesinde 111799 satır var. Bulana kadar tek tek girip çıkması sanırım biraz yavaşlatıyor işlemi.  Dediğim gibi programlama mantığından pek anlamam, böyle bir analiz de haddime düşmez ama daha farklı bir döngü yapısı kurabilir miyiz diye merak ediyorum : )

Ama tabiki emeğinize sağlık. Teşekkür ederim.

ironic

Yoğun matematiksel işlemlerin kullanıldığı kısım ip leri decimal e çeviren kısım. Ordaki 3 döngüyü teke indirdim. Daha da pratiği olur mu benim bilgimle söylemesi zor. :)
Bash bu tür ağır matematiksel işlemler için zaten uygun bir dil değil. Liste o kadar uzunsa farklı bir dile bakmak daha mantıklı. New Lisp sanırım bu konuda iddialıydı.

ip listemde 3, decimal listemde de 12 girdi var. Ekrana sonuçları basma süresi şöyle:


real    0m0.105s
user    0m0.030s
sys     0m0.017s



mustafayilmaz

#6
Valla sizdeki çalışma süresi gayet iyimiş. Ben başlattım şimdi bir de timer koydum sonucu yazacağım bitince : )


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 21 Kasım 2011 - 22:10:56

Buyrun : )

Executing script function took: 9m42s



Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 21 Kasım 2011 - 22:19:04

Galiba sizin decimal list'in küçük boyutlu olmasından kaynaklı sürenin kısa sürmesi..

Benim decimal listesinde 111799 satır var : )

Umarım normaldir süre yoksa bash'ten olduğunu düşüneceğim :)


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 21 Kasım 2011 - 22:28:20

Bir soru daha : )

Script'te set kullanmışsınız. Daha öncekinde de export ve eval gibi benim için tanıdık olmayan komutlar vardı. Biraz araştırdım ama tam olarak anlayamadım. Çevresel değişken deniyormuş bunlara galiba. Ama tama olarak nedir bu çevresel değişken dedikleri : )

ironic

#7
100 bin küsür için bence çok anormal değil.  :) En hızlı dili de kullansak işlemci devrine bağlı olarak yine birkaç dakika sürer tahminim. İşlemi biraz hızlandırmak adına, geçici dosya işlemi kullanmayalım. Sed ile her çalıştırmada içeriği yeniden düzenlemek yerine bir kere düzenleyelim. O dosyayı artık decimal dosyası olarak kullanalım.

Aşağıdaki komutla decimal dosyasını betikte kullanacağımız şekle sokalım.


sed -e '/^$/d' -e 's:\"::g;s: :_:g' < eski_decimal_dosyası > oluşacak_yeni_decimal_dosyası


Betiğin son  hali de şu şekilde olacak.

#!/bin/bash

# not: dosyalar betikle aynı dizinde değilse, dosyalar tam konumuyla beraber girilmeli.
IP_DOSYASI=ip.txt
DECIMAL_DOSYASI=ip_dec.txt

declare -a ip_dec_list ip_list # ip lere ait decimal değerleri ve  ip dizisi

ip_list=(  $(sed '/^$/d' "${IP_DOSYASI}") ) # ip adreslerini listeye ekledik.

for ((i=0; i<${#ip_list[@]}; i++))
{
  IP=${ip_list[$i]//./ }
  set -- $IP
  ip_dec_list+=( $(( 16777216 * $1 + 65536 * $2 + 256 * $3 + $4 )) )
}

# ip nin decimal değerini decimal dosyasındaki değerlerle  satır satır karşılaştırıyoruz.
# çakışma varsa bilgileri ekrana yazacak.
while read -r bilgi
do
  # decimal dosyasındaki ulke bilgilerini vs. yeni değişkenlere atadık.
  export $(awk 'BEGIN {FS=",";} \
    {printf "ip_ara1=%s\nip_ara2=%s\nulke_kod1=%s\nulke_kod2=%s\nulke_kod3=%s\n", $1,$2,$3,$4, $5;}' <<<$bilgi)
  for ((i=0; i<${#ip_dec_list[@]}; i++))
  {
    if  [[ ${ip_dec_list[$i]} -ge $ip_ara1 ]]  &&  [[ ${ip_dec_list[$i]} -le $ip_ara2 ]]
    then
      printf '\n%s\n%-12s%s\n%-12s%s\n%-12s%s\n%s\n ' \
          '*******************************************' \
        "IP  " "= ${ip_list[$i]}" \
        "IP Decimal"  "= ${ip_dec_list[$i]} " \
        "Ulke  " "= ${ulke_kod3//_/ } - ${ulke_kod1} (${ulke_kod2}) " \
        '*******************************************'
    fi
  }
done < "${DECIMAL_DOSYASI}"



Diğer soruya gelirsek dosyadan aldığımız veriyi awk ile  yeni değişkenlere atarken bunu export komutu ile bash a bildiriyoruz. Aksi takdirde değeri bash tanımaz.   Çevresel değişken bir nevi global değerler oluyor. Betik oturumu boyunca değer yeni bir değerle değişmediği sürece bash o değeri bellekte saklayacak.

set -- pozisyonel değerleri sıfırlamaya yarıyor. Yani $1, $2 .. gibi . Betikteki kısımda set -- $IP ile ıp değeri içindeki sayı gruplarını pozisyonel değişken olarak belirledik (tabi eğer $1, $2 bir değer tutuyorsa üstüne yazacak). Yani IP nin içindeki 111 222 333 444 grupları sırasıyla $1, $2,$3,$4 yerine geçti.

mustafayilmaz

Eyvallah üstad..

Çok teşekkür ederim. Ben de zaten oluşturulan /tmp/decimal'i dosyanın içine çekip sadece ondan aratıyordum "sed" komutunu kaldırdım yani. : )

Bunun için en mantıklı seçenek sanırım Country Code'ların bulunduğu dosyayı 1000er 1000er bölmek olabilir. bir case içine sokup seçtirmek olabilir. Tabi süreyi ne kadar kısaltır bilmiyorum ama hızlanmak gerekirse denenebilir : )

Sorun çözüldü konuyu kapatabiliriz :)