• Nem Talált Eredményt

1. Üzenetküldés címzése

1.2. Beállítások beolvasása

string gepNeve = Dns.GetHostName();

Kérjük le az ezen névhez tartozó IP-címeket! Ehhez továbbra is a Dns osztály függvényét kell használnunk, név szerint a GetHostEntry függvényt. A függvény általános feladatú, egy adott DNS névhez tartozó IP-címet (címeket) keresi ki. Adjuk meg neki a saját gépünk nevét, cserébe megkapjuk az összes létező IP-címet, amely a gépünk valamely hálózati csatolójához tartozik. Ne lepődjünk meg, ha ezen felsorolásban nemcsak a hagyományosabb IPv4 címeket, de az újabban egyre szélesebb körben elterjedő IPv6 címeket is megtaláljuk!

IPHostEntry cimek = Dns.GetHostEntry(gepNeve);

foreach (IPAddress ip in cimek.AddressList) Console.WriteLine("IP␣cím:␣[{0}]", ip);

7.1. ábra. A listázás kimenete

A portnyitáshoz csakis ezek az IP-címek állnak rendelkezésre, mivel csakis a listában szereplő IP-címek tartoznak ahhoz a számítógéphez, amelyen az alkalmazásunk fut. Ha több hálózati csatolónk is van, nem célszerű közülük random választani, mivel ezek eltérő fizikai adottságokkal is rendelkezhetnek. Pl. ha van egy gyors vezetékes csatolónk, nem érdemes a relatíve lassú WIFI-s csatolónkon portot nyitni (hacsak nem indokolja ezt valami erősen).

A különböző csatolóink különböző IP címtartományba is eshetnek (ez erősen jellemző a bridge funkciókat is ellátó vállalati szerverek esetén). Ez esetben egy kliens gép számára csak az ő számára definiált IP címtartomány, és az ehhez tartozó szerver hálózati csatoló látható. A szerver valamely másik csatolóján nyitott port nem elérhető.

1.2. Beállítások beolvasása

A programunk hordozhatósága érdekében javasolt egyfajta beállításokat tartalmazó fájlba írni a választandó IP címet (és a választandó portot is). A beállításokat korábbi hagyományok szerint .ini fájlokban, újabb módszerek szerint .xml fájlokban érdemes tartani.

Az ini fájlok egyszerű text fájlok, melyekben név-érték párosok szerepelnek, melyeket kis csoportokba, szekciókba szervezünk. A szekciók neveit szögletes zárójelek közé szokás tenni.

7.2. ábra. Egy ini fájl a notepad++ szerkesztőben

Az ini fájlok kezeléséhez sajnos a Framework nem tartalmaz kész osztályt (bár az XML alapú konfigurációt akarják standarddá tenni), de kezelésük roppant egyszerű. Az interneten számtalan ini kezelő class tölthető le forráskódban, és a WinAPI tartalmaz natív metódusokat is, melyek használatával ugyan már kikerülünk a .NET védett világából, de elérhetjük a Windows-ban már definiált ini kezelő library függvényeket.

Ha saját megoldást készítünk, tudnunk kell, hogy az ini fájlok valójában sororientált szöveges fájlok, egyszerűen meg kell nyitni őket mint szöveges fájlt, és soronként beolvasni. Ehhez a StreamReader osztályt érdemes használni. A konstruktorban kell megadni az .ini fájl nevét, illetve az .ini fájl kódlapját. Választható többek között az UTF-8 kódolás, illetve a telepített Windows operációs rendszerünk beállított kódlapja (default kódlap).

A StreamReader osztály a System.IO névtérben, az Encoding felsorolás viszont a System.Text névtérben található, ezért érdemes ezt a két kódlapot is behúzni a forráskód elején a using segítségével. Ne feledjük, hogy a string literálok belsejében a \ karakter speciális jelentésű! Vagy meg kell duplázni őket a string belsejében ("c:\\temp\\beallitasok.ini"), vagy a string literált a @ jellel kell kezdeni (@"c:\temp\beallitasok.ini").

StreamReader r =

new StreamReader(@"c:\temp\beallitasok.ini",Encoding.Default);

Valójában nem szokás fix alkönyvtárneveket beégetni a programok forráskódjába, ez rontja a hordozhatóságot, nehezebb ekkor más alkönyvtárba telepíteni a kódot. Helyette egyszerűen adjuk meg az ini fájl nevét:

StreamReader r = new StreamReader("beallitasok.ini",Encoding.Default);

Kérdéses, hogy ez esetben mely alkönyvtárban fogja keresni az operációs rendszer ezt a fájlt. Ez egy fontos kérdés, és sok fejlesztő elnagyolva tudja erre a választ. Képzeljük el azonban azt a szituációt, hogy a programunkhoz készítünk egy indító ikont a windows munkaasztalon (7.3 ábra)! Ott nemcsak az indítandó program nevét, de egy indítás helye alkönyvtárnevet is meg lehet adni. Ez az alkönyvtár lesz a program indítása után alapértelmezett alkönyvtár – a fenti esetben a beallitasok.ini fájlt ebben az alkönyvtárban fogja keresni az operációs rendszer.

7.3. ábra. Programindító ikon beállítása

Természetesen a futtatható program alkönyvtára és az indítás helyét megadó alkönyvtár eltérhet egymástól, mely esetben a programunk nem fogja megtalálni a szóban forgó fájlt. Ezen .ini fájl jellemzően a futtatható programmal egy alkönyvtárban található – így célszerű ezt megadni a megnyitáskor.

Viszont nem tudhatjuk, a programunk melyik alkönyvtárba került feltelepítésre, le kell azt kérdeznünk futás közben a kódból. Ehhez tudnunk kell, hogy a futó programot a .NET úgy tekinti, hogy az egy (vonathoz hasonló) szerelvény4, melynek elején dübörög az .exe, mint mozdony, és tartozik hozzá néhány .dll fájl is. Ebből a meséből most az assembly volt a kulcsszó, mert erre lesz szükségünk az .exe alkönyvtárának lekérdezéséhez.

A szükséges osztály neve Assembly, mely a System.Reflection névtérben található. Számunkra a legfontosabb függvénye a GetExecutingAssembly, mely magáról a futó programról ad vissza sok információt. Ezen információhalmaz része a Location, mely a futó program teljes neve az őt tartalmazó alkönyvtár nevével együtt.

string teljesNev = Assembly.GetExecutingAssembly().Location;

Console.WriteLine("A␣futo␣program␣neve\n␣␣\"{0}\"", teljesNev);

7.4. ábra. A futó program teljes neve

Egy ilyen fájlnévből, mint a futó program teljes neve, egyszerű leválasztani az alkönyvtár nevét.

Megkereshetjük a névben előforduló utolsó \ (per) jel pozícióját, és a ing művelettel kivághatjuk azt a stringből.

4assembly = szerelvény

De ennél specifikusabb módszer a Path osztály GetDirectoryName függvényét erre a célra használni. Ennek oka, hogy egyrészt ennek a függvénynek direkt ez a feladata, másrészt egyéb operációs rendszereken (pl. a Linux) az alkönyvtárneveket nem a \ (per) hanem a / (rep) jel választja el egymástól. Ezt a GetDirectoryName függvény tudni fogja, nekünk ezzel nem kell foglalkozni.

string teljesNev = Assembly.GetExecutingAssembly().Location;

Console.WriteLine("A␣futo␣program␣neve\n␣␣\"{0}\"", teljesNev);

string alkonyvtar = Path.GetDirectoryName(teljesNev);

Console.WriteLine("A␣futo␣program␣alkonyvtara\n␣␣\"{0}\"", alkonyvtar);

7.5. ábra. A futó program alkönyvtára

Ezen alkönyvtárhoz kell a beállításokat tartalmazó .ini fájl nevét hozzáfűzni. Ez is megoldható egyszerű string append művelettel az alábbiak szerint. Vegyük észre, hogy a alkonyvtar változó tartalma szerint nem zárul per jellel, így a hozzá fűzendő fájlnév ezzel a jellel kell, hogy kezdődjön:

string iniFileNeve = Path.Combine(alkonyvtar,"beallitasok.ini");

Console.WriteLine("A␣beallitas␣file␣neve\n␣␣\"{0}\"", iniFileNeve);

7.6. ábra. A beállítás fájl neve

Ennél ravaszabb módszer, ha a beállítás fájl neve megegyezik a futó program, az .exe nevével, csak nem .exe a név vége, hanem .ini. Ekkor sokat egyszerűsödik a beállítás fájl nevének előállítása:

string teljesNev = Assembly.GetExecutingAssembly().Location;

string iniFileNeve = Path.ChangeExtension(teljesNev,".ini");

7.7. ábra. A beállítás fájl neve – 2. verzió

Ennek megfelelően a StreamReader-ben hivatkozott .ini fájlnév képzéséhez ezt az utóbbi módszert fogjuk alkalmazni.

string teljesNev = Assembly.GetExecutingAssembly().Location;

string iniFileNeve = Path.ChangeExtension(teljesNev,".ini");

StreamReader r = new StreamReader(iniFileNeve,Encoding.Default);

A sikeres megnyitás után következhet a beállítások beolvasása a fájlból. Soronként olvassuk a fájl tartalmát, amíg az utolsó sort is be nem olvastuk! Mivel nem tudhatjuk előre, hány sort tartalmaz a beállítás fájl, így ehhez egy while ciklust fogunk alkalmazni. A sikeres fájlnyitás után az r megnyitott fájlhoz tartozik egy EndOfStream logikai tulajdonság, amely true értékű, ha már elértük az olvasás során a fájl végét (az utolsó sort is beolvastuk) – ellenkező esetben false. A fájl egy sorának beolvasását a Console.ReadLine() függvényhez hasonló r.ReadLine() függvény végzi el. A feldolgozás végén a megnyitott fájlt le kell zárni a Close metódussal.

Az s változó a fájl valamely sorát fogja tartalmazni. Ez lehet szekciónév, lehet egyszerű üres sor, és lehet név-érték páros is. Valamint szokás olyan szabályt bevezetni, hogy ha a sor első karaktere # (hashmark), akkor a szóban forgó sor komment, megjegyzés. Aránylag könnyű eldönteni melyik sor melyik típusba tartozik.

string s = r.ReadLine();

if (s.StartsWith("#")) /* komment sor */;

if (s.StartsWith"[")) /* szekcionev */;

if (s.IndexOf(’=’) > -1) /* név-érték páros */;

Jelen esetben a szerver nevű szekció IP-cim és port beállítását kívánjuk kiolvasni. Az alábbi feldolgozó ciklus ki fogja ezt választani. A aktSzekcio változó tartalmazza, hogy melyik szekció tartalmát olvassuk éppen a feldolgozás során. A feldolgozás eredménye, hogy az ipCim és a portSzam változókat kitölti (amennyiben a beállítások fájlban megtalálhatóak ezek az értékek). Ha a feldolgozás során ezekkel a beállításokkal nem találkozna a ciklus, úgy az alapértelmezett String.Empty értékek maradnak a változókban.

string nev = s.Substring(0, e);

string ertek = s.Substring(e + 1);

if (aktSzekcio == "szerver") {

switch (nev) {

case "IP-cim":

ipCim = ertek;

break;

case "port":

portSzam = ertek;

break;

} } } }