Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Lua, Computercraftin "DNS-palvelin" valittaa virhettä

juhaz [12.10.2012 17:43:25]

#

Yritän koodailla Computercraftissa Minecrafiin DNS-palvelinta tai vastaavaa ja tulee virhettä, kun suoritan tämän koodin:

function dns_load(filu)
-- lataa dns-tietokanta

 file = io.open(filu, "r")
 while true do
     line = file.read(file)
     table.insert(db, line)
     j = j + 1
     if not line then break end
 end
end

function dns_search(query)
-- etsi dns-tietokannasta

repeat
    if(string.find(db[i], query)) then
     tietue = db[i]
     loytyi = 1
    end
    i = i + 1
until loytyi == 1
return tietue
end

function split(string, delimiter)
  local result = { }
  local from = 1
  local delim_from, delim_to = string.find( string, delimiter, from )
  while delim_from do
    table.insert( result, string.sub( string, from , delim_from-1 ) )
    from = delim_to + 1
    delim_from, delim_to = string.find( string, delimiter, from )
  end
  table.insert( result, string.sub( string, from ) )
  return result
end

j = 1
loytyi = 0
i = 1
db = { }
dns_load("dns.txt")

rednet.open("top")
while true do
 viesti = rednet.receive(60)
 viestihajotettu = split(viesti, "!") -- id!osoite
 lahettaja = viestihajotettu[1] -- 22
 muuttuja = viestihajotettu[2] -- esim. google.com

 rikottu = split(dns_search(muuttuja), "!")
 osoite = rikottu[1]
 ip = rikottu[2]

 rednet.send(lahettaja, ip, true)

end
rednet.close("top")
dns:29: attempt to index ? (a nil value)

dns.txt tiedostossa lukee esim:

google.com!22

Asiakasohjelman testiversion koodi:

rednet.open("right")
my_id = os.computerID()

rednet.broadcast(my_id .. "!google.com")
print(rednet.receive(60))
rednet.close("right")

Miten saan virheen poistumaan ja ohjelman toimimaan?

Metabolix [12.10.2012 17:58:42]

#

Luetko edes virheilmoituksia, vai etsitkö aina vikaa summanmutikassa? Tuossahan lukee selvästi, että dns-nimisen jutun rivillä 29 yritetään indeksoida jotain, jonka arvo on nil. Kyseessä on nähtävästi split-funktion kolmas rivi, jossa kohdassa string.find on muuttuja string ja indeksi find. Näin ollen tiedetään, että virheilmoituksen syy on, että string-muuttujassa on arvo nil.

Älä käytä itse string-nimisiä muuttujia, koska string-muuttujassa ovat jo Luan tekstinkäsittelyfunktiot. Kun sijoitat string-muuttujaan jonkin vääränlaisen arvon, string.find ei enää toimi. Sen sijaan jos muuttujasi nimi olisi vaikka s, string.find toimisi oikein s-muuttujan arvosta riippumatta.

Kun vaihdat parametrin nimen, saat toisen virheilmoituksen: "bad argument #1 to 'find' (string expected, got nil)". Tämä tietenkin johtuu siitä, että parametrin arvo on edelleen nil ja nyt se syötetään funktiolle string.find. Yksi mahdollinen ratkaisu on tarkistaa split-funktion alussa, että parametri ei ole nil. Toinen ratkaisu on selvittää, mistä nil-arvo tulee, ja korjata asia.

juhaz [12.10.2012 18:16:43]

#

Puolustaudun sillä, että latasin split-funktion suoraan netistä koskematta siihen ja aloin tutustumaan Luaan vasta eilen. :D

Lisäsin split-funktioon tarkistuksen, että stringi (muutin muuttujan string nimeksi stringi) ei ole nil niin se jatkaa koodia ja nyt se valittaa rivillä 58 samaa vikaa eli " attempt to index ? (a nil value)" vaikka sen ei pitäisi olla nil. Nähtävästi se asiakasohjelma lähettää palvelimelle vain asiakasohjelman tietokoneen id:n eli muuttujan lahettaja, mutta ei sitä tietoa joka tulisi muuttujaan muuttuja.

Tämän siis huomaa siitä kun tulostaa muuttujan viesti niin se tulostaa vain tietokoneen ID-numeron vaikka sen pitäisi tulostaa jotain tyyliin "23!google.com". Ilmeisesti alkuperäinenkin vika johtui juurikin tästä.

Metabolix [12.10.2012 18:30:04]

#

"Rivi 58" ei kerro paljonkaan, kun kerran koodisi on muuttunut (ja ennen tuolla rivillä luki vain end). Oletan kuitenkin, että virhe liittyy split-funktion palauttamiin arvoihin.

Jos muutit split-funktiota niin, että se nil-syötteellä palauttaa nil-tuloksen, tietenkin pitää myös muuttaa split-funktion kutsumisen jälkeistä koodia niin, että se nil-tuloksen (tai myös 1-alkioisen taulun) kohdatessaan tekee jotain järkevää eikä yritä väkisin lukea siitä kahta arvoa.

juhaz [12.10.2012 18:37:56]

#

Pahoittelen. Rivillä 58 on siis:

osoite = rikottu[1]

Eli viesti = rednet.receive(60) odottaa 60s ajan viestejä ja sen kuuluisi saada viesti "23!google.com" asiakasohjelmalta, jossa 23 tarkoittaa asiakkaskoneen id:tä ja perässä oleva osoite google.com sitä minkä id:n asiakaskone haluaa tietää, jolloin palvelimen pitäisi hakea google.comin id ja palauttaa se asiakaskoneella. Tämä ei onnistu, koska viesti-muuttujassa lukee vain "23".

EDIT: Virhe korjattu ja toimii!

Metabolix [14.10.2012 22:34:18]

#

Mikä oli virhe?

juhaz [15.10.2012 00:13:17]

#

Metabolix kirjoitti:

Mikä oli virhe?

viesti = rednet.receive(60)

Korjattuna:

senderId, viesti, distance = rednet.receive(60)

Nähtävästi rednet.receive lähettää sen lähettäjäkoneen ID:n ja alkuperäisessä koodissa muuttuja viesti saa pelkästään sen lähettäjäkoneen ID:n. Korjatussa versiossa lähettäjäkoneen ID sisältyy jo muuttujaan senderId, joten sen lähettäminen viestin seassa on turhaa.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta