Académique Documents
Professionnel Documents
Culture Documents
A sztalos Mr k
B n y sz G b or
L e v e n dov szky T ih am r
Alkalmazott informatika sorozat
Asztalos Mrk
Bnysz Gbor Levendovszky
Tihamr
programozs
Asztalos Mrk Bnysz Gbor Levendovszky Tihamr
L in ux pr ogr am ozs
Msodik, tdolgozott kiads
Asztalos Mrk
Bnysz Gbor
Levendovszky Tihamr
L in ux programozs
Msodik, tdolgozott kiads
2012
Linux programozs
Msodik, tdolgozott kiads
Asztalos Mrk, Bnysz Gbor, Levendovszky Tihamr
Alkalmazott informatika sorozat
Budapesti Mszaki s Gazdasgtudomnyi Egyetem
Villamosmrnki s Informatikai Kar
Automatizlsi s Alkalmazott Informatikai Tanszk
Alkalmazott Informatika Csoport
C Asztalos Mrk, Bnysz Gbor, Levendovszky Tihamr, 2012.
Sorozatszerkeszt: Charaf Hassan
Lektor: Vlgyesi Pter
ISBN 978-963-9863-29-3
ISSN 1785-363X
Minden jog fenntartva. Jelen knyvet, illetve annak rszeit a kiad enge-
dlye nlkl tilos reproduklni, adatrgzt rendszerben trolni, brmi-
lyen formban vagy eszkzzel elektronikus ton vagy ms mdon kzlni.
SZAK Kiad Kft. Az 1795-ben alaptott Magyar Knyvkiadk s Knyvterj esztk
Egyeslsnek a tagj a 2060 Bicske, Difa u. 3.
Tel.: 36-22-565-310 Fax: 36-22-565-311 www.szak.hu
e-mail: info@szak.hu http://www.facebook.com/szakkiado
Kiadvezet: Kis dm, e-mail adam.kis@szak.hu Fszerkesz-
t: Kis Balzs, e-mail: balazs.kis@szak.hu
Tartalomjegyzk
Elsz a msodik kiadshoz ....................................... xv
1. Bevezets .......................................................... 1
1.1. A Linux ................................................................................................. 1
1.2. A szabad szoftver s a Linux trtnete ........................................ 2
1.2.1. FSF ................................................................................................ 2
1.2.2. GPL ................................................................................................ 3
1.2.3. GNU ............................................................................................... 4
1.2.4. Linux-kernel .................................................................................. 4
1.2.5. A Linux rendszer .......................................................................... 6
1.2.6. Linux-disztribcik ....................................................................... 6
1.3. Informciforrsok ........................................................................... 8
2. Betekints a Linux-kernelbe ................................. 11
2.1. A Linux-kernel felptse .............................................................. 11
2.2. A Linux elindulsa .......................................................................... 13
2.3. Processzek ......................................................................................... 14
2.3.1. A Linux-processzekhez kapcsold informcik ....................... 15
2.3.2. A processz llapotai .................................................................... 17
2.3.3. Azonostk ................................................................................... 18
2.3.4. Processzek ltrehozsa s terminlsa ..................................... 19
2.3.5. A programok futtatsa ............................................................... 20
2.3.6. temezs ..................................................................................... 21
2.3.6.1. Klasszikus temezs .......................................................... 21
2.3.6.2. Az O(1) temezs ................................................................ 23
2.3.6.3. Teljesen igazsgos temez ............................................... 24
2.3.6.4. Multiprocesszoros temezs .............................................. 25
2.3.7. Megszaktskezels .................................................................... 25
2.3.8. Valsidejsg .............................................................................. 26
2.3.9. Id s idztk ............................................................................. 26
2.4. Memriakezels ............................................................................... 27
2.4.1. A virtulismemria-kezels ........................................................ 27
2.4.2. Lapozs ........................................................................................ 28
Tartalomjegyzk
vi
2.4.3. A lapozs implementcija a Linuxon ....................................... 29
2.4.4. Igny szerinti lapozs ................................................................. 31
2.4.5. Lapcsere ...................................................................................... 32
2.4.6. Megosztott virtulis memria .................................................... 34
2.4.7. Msols rskor (COW technika) ............................................... 34
2.4.8. A hozzfrs vezrlse ................................................................ 35
2.4.9. A lapkezels gyorstsa .............................................................. 35
2.5. A virtulis llomnyrendszer ....................................................... 36
2.5.1. Az llomnyabsztrakci .............................................................. 36
2.5.2. Specilis llomnyok .................................................................. 38
2.5.2.1. Eszkzllomnyok .............................................................. 38
2.5.2.2. Knyvtr ............................................................................. 40
2.5.2.3. Szimbolikus hivatkozs ...................................................... 40
2.5.2.4. Csvezetk .......................................................................... 40
2.5.2.5. Socket .................................................................................. 41
2.5.3. Az inode ....................................................................................... 41
2.5.4. Az llomnylerk ....................................................................... 44
2.6. A Linux programozsi fellete ..................................................... 44
3. Programknyvtrak ksztse ............................... 47
3.1 . Statikus programknyvtrak ...................................................... 47
3.2. Megosztott programknyvtrak .................................................. 55
3.2.1. Megosztott programknyvtr ksztse ..................................... 56
3.2.2. Megosztott programknyvtrak hasznlata ............................. 60
3.2.3. Megosztott programknyvtrak dinamikus betltse .............. 63
3.3. Megosztott knyvtrak C++ nyelven .......................................... 69
3.3.1. Programknyvtrbeli C++-osztlyok hasznlata ...................... 69
3.3.2. C++-objektumok dinamikus betltse
programknyvtrbl ................................................................... 72
3.4. A megosztott knyvtrak mkdsi mechanizmusai ............. 77
3.4.1. A betlttt program .................................................................... 78
3.4.2. Statikus knyvtrat tartalmaz program linkelse s
betltse ...................................................................................... 80
3.4.3. Megosztott knyvtr linkelse s betltse ............................... 83
3.4.3.1. A cmtartomny kezelse ................................................... 83
3.4.3.2. A megosztott knyvtrak megvalstsnak
alapkoncepcii ..................................................................... 85
3.4.3.3. A megosztott knyvtrakkal kapcsolatos
linkels s betlts .............................................................. 87
3.4.3.4. Dinamikusan linkelt megosztott knyvtr
linkelse s betltse .......................................................... 89
3.4.4. A programknyvtrak hasznlatnak optimalizlsa ............. 89
Tartalomjegyzk
vii
4. llomny- s I/O kezels ..................................... 95
4.1. Egyszer llomnykezels ............................................................ 95
4.1.1. Az llomnyler ......................................................................... 96
4.1.2. llomnyok megnyitsa ............................................................. 97
4.1.3. llomnyok bezrsa .................................................................. 98
4.1.4. rs, olvass s pozicionls az llomnyban ........................... 99
4.1.5. Rszleges s teljes olvass ........................................................ 101
4.1.6. Az rsmvelet finomhangolsa ............................................... 103
4.1.7. llomnyok rvidtse .............................................................. 106
4.1.8. llomnyok tirnytsa .......................................................... 106
4.2. Inode-informcik ........................................................................ 108
4.2.1. Inode-informcik lekrdezse ................................................. 109
4.2.2. Jogok lekrdezse ..................................................................... 110
4.2.3. Jogok lltsa ............................................................................ 111
4.2.4. Tulajdonos s csoport belltsa .............................................. 112
4.2.5. Az idblyeg belltsa ............................................................. 112
4.3. Tovbbi llomnymveletek...................................................... 113
4.3.1. Eszkzllomnyok s pipe bejegyzsek ltrehozsa ............... 113
4.3.2. Merev hivatkozs ltrehozsa .................................................. 114
4.3.3. Szimbolikus hivatkozs ltrehozsa ........................................ 115
4.3.4. llomnyok trlse ................................................................... 116
4.3.5. llomnyok tnevezse ............................................................ 116
4.4. Knyvtrmveletek ..................................................................... 117
4.5. Csvezetkek ................................................................................. 120
4.5.1. Nvtelen csvezetkek .............................................................. 121
4.5.2. Megnevezett csvezetkek ........................................................ 123
4.6. Blokkolt s nem blokkolt I/O ..................................................... 126
4.7. A multiplexelt I/O mdszerei ..................................................... 129
4.7.1. Multiplexels a select() fggvnnyel ........................................ 129
4.7.2. Multiplexels a poll() fggvnnyel ........................................... 134
4.7.3. A multiplexelsi mdszerek sszehasonltsa ......................... 139
4.8. llomnyok lekpezse a memriba ...................................... 139
4.9. llomnyzrols ........................................................................... 143
4.9.1. Zrolllomnyok ..................................................................... 144
4.9.2. Rekordzrols ........................................................................... 145
4.9.3. Ktelez zrols ........................................................................ 148
4.10. Kapcsolat a magas szint llomnykezelssel .................... 149
4.11. Soros kommunikci ................................................................. 150
4.11.1. Kanonikus feldolgozs ............................................................ 151
4.11.2. Nem kanonikus feldolgozs .................................................... 154
Tartalomjegyzk
viii
5. Prhuzamos programozs .................................. 157
5.1. Processzek ...................................................................................... 157
5.2. Processzek kztti kommunikci (IPC) ................................ 165
5.2.1. Szemaforok ................................................................................ 166
5.2.2. zenetsorok .............................................................................. 178
5.2.3. Megosztott memria ................................................................. 185
5.3. Processzek a Linux rendszerben .............................................. 189
5.3.1. Feladatvezrls ......................................................................... 191
5.3.2. Dmonok .................................................................................... 193
5.3.3. Programok indtsa shellbl ..................................................... 197
5.3.4. Jogosultsgok ............................................................................ 198
5.3.5. Felhasznli nevek s csoportnevek ........................................ 200
5.4. Szlak .............................................................................................. 202
5.4.1. Szlak ltrehozsa .................................................................... 203
5.4.2. Szlak ltrehozsa C++ nyelven .............................................. 207
5.4.3. Szlak attribtumai ................................................................. 210
5.4.4. Szlbiztos fggvnyek .............................................................. 212
5.4.5. Szl lelltsa ............................................................................ 217
5.4.6. Szlak s a fork/exec hvsok .................................................. 220
5.5. POSIX-szinkronizci .................................................................. 221
5.5.1. Klcsns kizrs (mutex) ........................................................ 221
5.5.2. Feltteles vltozk .................................................................... 227
5.5.3. Szemaforok ................................................................................ 233
5.5.4. Spinlock ..................................................................................... 236
5.5.5. Tovbbi lehetsgek: POSIX megosztott memria s
zenetsorok ............................................................................... 238
5.6. Jelzsek ........................................................................................... 238
5.6.1. A jelzsklds s -fogads folyamata ....................................... 239
5.6.2. Jelzsek megvalstsa ............................................................. 245
5.6.3. A jelzskezel s a fprogram egymsra hatsa ..................... 247
5.6.4. Jelzsek s a tbbszl processz .............................................. 250
5.6.5. Jelzsek programozsa ............................................................. 250
5.6.5.1. Jelzsek kldse ............................................................... 251
5.6.5.2. Jelzsek letiltsa s engedlyezse.
Fggben lv jelzsek ..................................................... 253
5.6.5.3. A jelzsek kezelse ........................................................... 254
5.6.5.4. Szinkron jelzskezels ...................................................... 258
5.6.6. A SIGCHLD jelzs .................................................................... 262
Tartalomjegyzk
ix
6. Hlzati kommunikci ..................................... 265
6.1. A socket ........................................................................................... 265
6.2. Az sszekttets-alap kommunikci ................................... 267
6.2.1. A kapcsolat felptse ............................................................... 268
6.2.2. A socket cmhez ktse ............................................................. 268
6.2.3. Vrakozs a kapcsoldsra ...................................................... 269
6.2.4. Kapcsolds a szerverhez ......................................................... 269
6.2.5. A kommunikci ....................................................................... 270
6.2.6. A kapcsolat bontsa .................................................................. 270
6.2.7. Tovbbi kapcsolatok kezelse a szerverben ............................ 271
6.3. Az sszekttets nlkli kommunikci ................................. 272
6.3.1. A kommunikci ....................................................................... 273
6.3.2. A connect() hasznlata .............................................................. 274
6.3.3. A socket lezrsa ...................................................................... 275
6.4. Unix domain socket ..................................................................... 275
6.4.1. Unix domain socket cmek ....................................................... 275
6.4.2. Unix domain socket adatfolyam szerveralkalmazs .............. 276
6.4.3. Unix domain socket adatfolyam kliensalkalmazs ................. 278
6.4.4. Unix domain socket datagram kommunikci ........................ 280
6.4.5. Nvtelen Unix domain socket .................................................. 280
6.4.6. A Linux absztrakt nvtere ....................................................... 280
6.5. IP ...................................................................................................... 282
6.5.1. Rviden az IP-hlzatokrl ...................................................... 282
6.5.2. Az IP protokoll rtegzdse ...................................................... 284
6.5.3. IPv4-es cmzs ........................................................................... 285
6.5.4. IPv4-es cmosztlyok ................................................................ 286
6.5.5. IPv4-es specilis cmek ............................................................. 287
6.5.6. IPv6-os cmzs ........................................................................... 288
6.5.7. Portok ........................................................................................ 289
6.5.8. A hardverfgg klnbsgek feloldsa .................................... 290
6.5.9. A socketcm megadsa .............................................................. 290
6.5.10. Loklis cm megadsa ............................................................ 293
6.5.11. Nv- s cmfelolds ................................................................. 294
6.5.11.1. A getaddrinfo() fggvny ................................................ 294
6.5.11.2. A getnameinfo() fggvny ............................................... 298
6.5.12. sszekttets-alap kommunikci ...................................... 302
6.5.12.1. TCP kliens-szerver plda ............................................... 304
6.5.12.2. TCP szerver alkalmazs ................................................ 308
6.5.12.3. TCP-kliensalkalmazs ................................................... 315
6.5.13. sszekttets nlkli kommunikci .................................... 317
6.5.13.1. UDP-kommunikci-plda ............................................. 317
6.5.13.2. Tbbes klds ................................................................. 320
Tartalomjegyzk
x
6.6. Socketbelltsok ......................................................................... 326
6.7. Segdprogramok ........................................................................... 330
6.8. Tvoli eljrshvs ....................................................................... 331
6.8.1. Az RPC-modell .......................................................................... 332
6.8.2. Verzik s szmok ..................................................................... 332
6.8.3. Portmap ..................................................................................... 333
6.8.4. Szllts ..................................................................................... 333
6.8.5. XDR ........................................................................................... 333
6.8.6. rpcinfo ........................................................................................ 334
6.8.7. rpcgen ........................................................................................ 334
6.8.8. Helyi eljrs talaktsa tvoli eljrss ................................ 335
7. Fejleszts a Linux-kernelben .............................. 339
7.1. Verzifggsg .............................................................................. 340
7.2. A kernel- s az alkalmazsfejleszts eltrsei ....................... 341
7.2.1. Felhasznli zemmd kernelzemmd ............................. 342
7.3. Kernelmodulok ............................................................................. 343
7.3.1. Hello modul vilg ...................................................................... 344
7.3.2. Fordts ..................................................................................... 346
7.3.3. A modulok betltse s eltvoltsa ......................................... 347
7.3.3.1. insmod/rmmod ................................................................. 347
7.3.3.2. modprobe ........................................................................... 347
7.3.4. Egymsra pl modulok ......................................................... 348
7.4. Paramtertads a modulok szmra ..................................... 351
7.5. Karakteres eszkzvezrl ........................................................... 353
7.5.1. F- s mellkazonost (major s minor number) ................... 354
7.5.2. Az eszkzllomnyok dinamikus ltrehozsa ......................... 355
7.5.3. llomnymveletek .................................................................. 356
7.5.4. Hasznlatszmll .................................................................... 357
7.5.5. Hello vilg driver ................................................................... 358
7.5.6. Az open s a release fggvnyek ............................................... 362
7.5.7. A mellkazonost (minor number) hasznlata ...................... 363
7.5.8. Az ioctl() implementcija ........................................................ 366
7.6. A /proc llomnyrendszer ........................................................... 370
7.7. A hibakeress mdszerei ............................................................ 375
7.7.1. A printk() hasznlata ................................................................ 375
7.7.2. A /proc hasznlata ................................................................... 376
7.7.3. Kernelopcik ............................................................................. 377
7.7.4. Az Oops zenet .......................................................................... 378
7.7.4.1. Az Oops zenet rtelmezse kernel esetben............... 379
7.7.4.2. Az Oops zenet rtelmezse kernelmodul
esetben ............................................................................. 380
Tartalomjegyzk
xi
7.7.5. Magic SysRq .............................................................................. 381
7.7.6. A gdb program hasznlata ....................................................... 382
7.7.7. A kgdb hasznlata .................................................................... 382
7.7.8. Tovbbi hibakeressi mdszerek ............................................. 383
7.8. Memriakezels a kernelben ..................................................... 384
7.8.1. Cmtpusok ................................................................................ 384
7.8.2. Memriaallokci ...................................................................... 384
7.9. A prhuzamossg kezelse ......................................................... 386
7.9.1. Atomi mveletek ....................................................................... 387
7.9.2. Ciklikus zrols (spinlock) ....................................................... 389
7.9.3. Szemafor (semaphore) .............................................................. 391
7.9.4. Mutex ......................................................................................... 392
7.9.5. Olvas/r ciklikus zrols (spinlock) s szemafor
(semaphore) ............................................................................... 393
7.9.6. A nagy kernelzrols ................................................................ 394
7.10. I/O mveletek blokkolsa ......................................................... 395
7.10.1. Elaltats .................................................................................. 396
7.10.2. Felbreszts ............................................................................. 397
7.10.3. Plda ........................................................................................ 398
7.11. A select() s a poll() tmogatsa .............................................. 403
7.12. Az mmap tmogatsa ................................................................. 404
7.13. I/O portok kezelse ..................................................................... 407
7.14. I/O memria kezelse ................................................................. 408
7.15. Megszaktskezels .................................................................... 410
7.15.1. Megszaktsok megosztsa .................................................... 412
7.15.2. A megszaktskezel fggvnyek megktsei ....................... 412
7.15.3. A megszakts tiltsa s engedlyezse ................................ 412
7.15.4. A szoftvermegszakts ............................................................ 413
7.15.5. A BH-mechanizmus ................................................................ 414
7.15.5.1. A kisfeladat (tasklet) ...................................................... 414
7.15.5.2. Munkasor ........................................................................ 417
7.16. A kernelszlak ............................................................................. 421
7.17. Vrakozs ..................................................................................... 423
7.17.1. Rvid vrakozsok .................................................................. 423
7.17.2. Hossz vrakozs ................................................................... 424
7.18. Idztk ......................................................................................... 425
7.19. Eszkzvezrl modell ................................................................ 426
7.19.1. A busz ...................................................................................... 426
7.19.2. Eszkz- s eszkzvezrl lista ................................................ 428
7.19.3. sysfs .......................................................................................... 429
7.19.4. Buszattribtumok exportlsa .............................................. 429
Tartalomjegyzk
xii
7.19.5. Az eszkzvezrl ..................................................................... 430
7.19.6. Eszkzvezrl attribtumok exportlsa .............................. 433
7.19.7. Az eszkz ................................................................................. 433
7.19.8. Az eszkz attribtumainak exportlsa ................................ 435
7.19.9. Plda ........................................................................................ 436
7.20. Tovbbi informcik ................................................................. 438
8. A Qt keretrendszer programozsa ........................ 439
8.1. Az X Window rendszer ................................................................. 439
8.1.1. Az X Window rendszer felptse ............................................. 439
8.1.2. X Windows kliensalkalmazsok ............................................... 440
8.1.3. Asztali krnyezet ...................................................................... 441
8.2. Fejleszts Qt alatt ......................................................................... 442
8.2.1. Hello Vilg! ................................................................................ 443
8.2.2. Projektllomnyok .................................................................... 447
8.2.3. A QObject szolgltatsai ........................................................... 448
8.2.4. A QtCore modul ......................................................................... 449
8.3. A Qt esemnykezels-modellje .................................................. 450
8.3.1. Szignlok ltrehozsa ............................................................... 452
8.3.2. Szlotfggvnyek ltrehozsa .................................................... 454
8.3.3. Szignlok s szlotok sszekapcsolsa ...................................... 455
8.3.4. Szlot az tmeneti objektumokban ............................................ 457
8.3.5. A Meta Object Compiler ........................................................... 458
8.4. Ablakok s vezrlk ..................................................................... 459
8.4.1. Dialgusablakok ksztse ....................................................... 460
8.4.2. A Qt vezrlkszlete ................................................................. 466
8.4.3. Sajt alkalmazsablakok ......................................................... 467
8.4.4. A fablak programozsa ........................................................... 469
8.4.5. Lokalizci ................................................................................ 479
8.4.6. Sajt vezrlk ksztse ............................................................ 483
8.5. A dokumentum/nzet architektra .......................................... 489
8.5.1. Az alkalmazs szerepe .............................................................. 491
8.5.2. A dokumentumosztly .............................................................. 493
8.5.3. A nzetosztlyok ....................................................................... 497
8.5.4. Tovbbi osztlyok ..................................................................... 503
8.6. Tovbbi technolgik .................................................................. 509
8.6.1. Tbbszl alkalmazsfejleszts ............................................... 509
8.6.2. Adatbziskezels ....................................................................... 516
8.6.3. Hlzati kommunikci ............................................................ 521
8.7. sszefoglals ................................................................................. 530
Tartalomjegyzk
xiii
A fggelk: Fejleszteszkzk ................................. 533
A.1. Szvegszerkesztk ....................................................................... 533
A.1.1. Emacs ........................................................................................ 533
A.1.2. vi (vim) ...................................................................................... 534
A.1.3. nano (pico) ................................................................................ 534
A.1.4. joe .............................................................................................. 534
A.1.5. mc .............................................................................................. 534
A.1.6. Grafikus szvegszerkesztk ..................................................... 535
A.2. Fordtk ......................................................................................... 535
A.2.1. GNU Compiler Collection ........................................................ 536
A.2.1. gcc .............................................................................................. 536
A.2.3. LLVM ........................................................................................ 540
A.3. Make ................................................................................................ 541
A.3.1. Megjegyzsek ............................................................................ 542
A.3.2. Explicit szablyok .................................................................... 542
A.3.3. Hamis trgy .............................................................................. 544
A.3.4. Vltozdefincik ...................................................................... 545
A.3.5. A vltoz rtkadsnak specilis esetei ................................ 546
A.3.6. Tbbsoros vltozk definilsa ................................................ 547
A.3.7. A vltoz hivatkozsnak specilis esetei .............................. 547
A.3.8. Automatikus vltozk .............................................................. 548
A.3.9. Tbbszrs cl ........................................................................... 549
A.3.10. Mintaszablyok ...................................................................... 550
A.3.11. Klasszikus ragozsi szablyok .............................................. 551
A.3.12. Implicit szablyok .................................................................. 552
A.3.13. Specilis trgyak .................................................................... 553
A.3.14. Direktvk ............................................................................... 554
A.4. Make alternatvk ........................................................................ 554
A.4.1. Autotools ................................................................................... 555
A.4.2. CMake ....................................................................................... 555
A.4.3. qmake ........................................................................................ 555
A.4.4. SCons ........................................................................................ 556
A.5. IDE ................................................................................................... 556
B fggelk: Hibakeress ......................................... 557
B.1. gdb ................................................................................................... 557
B.1.1. Plda a gdb hasznlatra ........................................................ 558
B.1.2. A gdb leggyakrabban hasznlt parancsai ............................... 561
B.1.3. A gdb indtsa .......................................................................... 561
B.1.4. Trspontok: breakpoint, watchpoint, catchpoint ................... 562
B.1.5. Data Display Debugger (DDD) ................................................ 566
B.1.6. Az IDE-k beptett hibakeresje ............................................. 567
Tartalomjegyzk
xiv
B.2. Memriakezelsi hibk .............................................................. 568
B.2.1. Malloc hibakeresk .................................................................. 569
B.2.1.1. Memriaterlet tlrsa .................................................. 570
B.2.1.2. Elrs .............................................................................. 571
B.2.1.3. Felszabadtott terlet hasznlata ................................... 571
B.2.1.4. Memriaszivrgs ............................................................ 571
B.2.1.5. A malloc hibakeresk korltai ........................................ 571
B.2.2. Electric Fence ............................................................................ 572
B.2.2.1. Az Electric Fence hasznlata ........................................... 572
B.2.2.2. A Memory Alignment kapcsol ........................................ 574
B.2.2.3. Az elrs .......................................................................... 574
B.2.2.4. Az Electric Fence tovbbi lehetsgei ............................. 575
B.2.2.5. Erforrsignyek .............................................................. 575
B.2.3. DUMA ....................................................................................... 576
B.3. Valgrind ......................................................................................... 576
B.3.1. Memcheck .................................................................................. 577
B.3.1.1. A memcheck modul mkdse ......................................... 578
B.3.2. Helgrind .................................................................................... 580
B.4. Rendszerhvsok monitorozsa: strace .................................. 582
B.5. Knyvtrfggvnyhvsok monitorozsa: ltrace ................. 582
B.6. Tovbbi hasznos segdeszkzk .............................................. 582
Trgymutat ........................................................ 585
Irodalomjegyzk ................................................... 593
Elszamsodikkiadshoz
Knyvnk els kiadsa ta a Linux fejldse tretlen. A begyazott szoftver-
rendszerek egyre nagyobb trhdtsnak ksznheten a Linux npszersge
is egyre n, ezen bell szmos mobileszkz kztk okostelefonok opercis
rendszerv vlt. Ezzel egytt az opercis rendszer programozsi fellete is
sokat fejldtt. Ezrt dntttnk gy, hogy a knyv els kiadsa alapos tdol-
gozsra, illetve kiegsztsre szorul. Munknk sorn csaknem minden fejeze-
tet trtunk, aktuliss tettnk, a kernel programozsval kapcsolatos rszt
teljesen jrartuk.
A Linux a kzelmltban volt hszves, az interneten nagyon sok cikk, pl-
daprogram s kzssgi oldalak llnak rendelkezsre. A Linux nagyon sokban
kveti a POSIX-szabvnyt, amely szmos tovbbi dokumentciforrst jelent.
gy vlemnynk szerint egy Linuxrl szl knyv akkor a leghasznosabb, ha
rendszerezi a programozshoz szksges ismereteket, a rendszer mkdst
mutatja be, s a programozs logikja vezeti a trgyalst. Knyvnkben gy
prblunk hathats segtsget nyjtani: az olvast bevezetjk a rendszer m-
kdsbe, nemcsak a mit? s hogyan? krdsekre adunk vlaszt programrszle-
tekkel illusztrlva, hanem a mirt? krdsre fektetjk a hangslyt, s arra
ptve mutatjuk be a tbbit. A legtbb esetben egy plda motivlja a bemuta-
tand megoldst, amelyet kln kiemelnk.
Feladat Ksztsnk megosztott knyvtrat a kerektst vgz fggvnynkkel.
A klnsen fontos kvetkeztetseket, j tancsokat tmutatkban ssze-
gezzk.
tmutat Ha a programozs szmunkra tbb mint ksz pldakdok sszefslse, majd azok
prblkozssal trtn kijavtsa, s idt sznunk a mkds megrtsre, sokkal bonyolul-
tabb hibkat sokkal elbb szrevesznk, ez kpess tesz minket Linux alatti szoftver terve-
zsre is.
Az els hat fejezet a Linux rendszer C nyelven hvhat alapfunkciit trgyalja,
egy fejezet a kernelmodulok ksztsrl szl, mg az utols fejezet az XWindow
rendszer programozst mutatja be C++ nyelven Qt-krnyezetben. A knyv
alapjt a Budapesti Mszaki s Gazdasgtudomnyi Egyetem Villamosmr-
nki s Informatikai Karn vlaszthat Linux-programozs tantrgy el-
Elszamsodikkiadshoz
xvi
adsai s laborfoglalkozsai kpezik. A knyv els fejezetei azt felttelezik,
hogy az olvas tisztban van a C s C++ nyelvek alapjaival, az alapvet adat-
struktrkkal, s rendelkezik az elemi programozstechnikai ismeretekkel,
amelyek pldul az [1,2,3] irodalmi hivatkozsnak megfelel knyv feldolgo-
zsnak eredmnyeknt szerezhetk meg. Olyan olvaskra is szmtunk,
akik Linux alatt prblnak elszr komolyabban programozni, ezrt a fonto-
sabb fejleszteszkzket s magt az opercis rendszert teljesen az alapoktl
trgyaljuk, s a fggvnyhvsokat olyan rszletessggel mutatjuk be, hogy
azokat kzvetlenl fel lehessen hasznlni. Ahol csak tehettk, az egyes funk-
cikat egyszer pldkkal illusztrltuk. Remnyeink szerint azok, akik fel-
dolgozzk a knyv els hat fejezett, kpesek lesznek arra, hogy nllan
megtalljk s rtelmezzk azokat a tovbbi Linuxszal kapcsolatos inform-
cikat, amelyekre szksgk van a fejleszts sorn. Ebben a kiadsban kl-
nsen a szoftvertervezket prbljuk segteni: bemutatjuk, hogy a Linux ltal
biztostott megoldsok milyen logikt kvetnek, melyek a jrhat utak, s
mik ezek elnyei/htrnyai, valamint melyik mdszer mikor hatkony.
Azok szmra, akik ipari projektet indtannak, bemutatunk nhny
olyan eszkzt (grafikus fejleszti krnyezet A fggelk, a memriaszivr-
gst feldert programok, hibakeresk B fggelk), amelyek nlkl hosz-
szabb programok rsa nehzkes s hosszan tart volna.
A grafikus fejleszts bemutatsakor dntennk kellett, hiszen a szmos
eszkzkszlet mindegyikt nem mutathatjuk be. Vlasztsunk a Qt-re esett
mivel elterjedt mind asztali, mind begyazott krnyezetben, valamint jl
strukturlt fejleszti eszkzkszlet.
gy gondoljuk, hogy a grafikus felhasznli fellet programozsa s terve-
zse ma mr kiforrottnak mondhat, gy ha valaki egy krnyezetet megismer,
gyakorlatt minimlis vltoztatsokkal ms rendszerekben is alkalmazni tud-
ja. A Qt alatti programozssal foglalkoz rszek halad C++-programozi szin-
tet feltteleznek. A C++ nyelv szksges elemeit a [2] irodalmi hivatkozs els
12 fejezete, illetve a [3] hivatkozs ismerteti.
A knyvet tanknyvknt hasznlk szmra a kvetkez fejezetek feldol-
gozst javasoljuk:
Linuxot hasznl C kurzus: A fggelk, (bevezets a nyelvi elemek-
be, szabvnyos knyvtri fggvnyek, pldul [1] alapjn): 4, 5, 6.
Opercis rendszerek alapjai kurzus gyakorlati illusztrlsa: 15.
Linux-programozsi kurzus: A fggelk , B fggelk, 18.
Tovbbra is igyekeztnk, hogy az egyes fejezetek a lehetsgekhez mrten s
a tma jellegtl fggen nll egszet alkossanak, esetleges rvidebb ismt-
lsek rn is.
Az itt lert tananyag szmonkrse a tma jellege miatt klnsen nehz-
kes. Ezt megknnytend a szmon krhet fogalmakra, valamint a fontosabb
mondanivalra vastag betkkel hvtuk fel a figyelmet. A foly szvegben
Elszamsodikkiadshoz
xvii
gyakran hivatkozunk a programkdban szerepl vltozkra, konstansokra,
makrkra stb. Ezeket dlt betkkel szedtk az elklnthetsg miatt. A prog-
ramrszleteket, a parancssorba beviend parancsokat s szkripteket szrke
httr jelzi.
A szerzk trekedtek arra, hogy a knyvben szerepl kdrszek elektroni-
kusan is hozzfrhetk legyenek, ezek a pldk az albbi oldalon rhetk el:
http://szak.hu/linux.
Jelen munkban felhasznltuk a Linux sajt dokumentciit, gy az info
s a man oldalakat, a POSIX-szabvnyokat. Az egyes forrsokat a knyv jel-
lege s a trgyals folyamatossga miatt nem jelltk kln, az irodalomjegy-
zkben sszegeztk ket.
Az egyes j fogalmaknak magyar megfeleli mellett kerek zrjelben k-
zljk azok angol megfelelit a tovbbi tjkozds megknnytshez.
Elsknt szeretnnk megksznni Vlgyesi Pternek klnsen gondos
lektori munkjt s rtkes tancsait. Ksznjk Lattman Zsolt, Szilvsi
Sndor, Horvth Pter s Babjk Benjamin visszajelzseit s a kzirat
egyes rszeinek tolvasst. Ksznjk tovbb Laczk Krisztina olvas-
szerkeszti munkjt, amely jelentsen nvelte a kzirat szvegnek ignyes-
sgt s rthetsgt, valamint Mamira Gyrgynek a kzirat trdelst.
Ksznetnket szeretnnk kifejezni Szilvsi Sndornak a fedlbort
kls megjelensnek az elksztsrt, az Institute for Software Integrated
Systems kutatintzetnek (Vanderbilt Egyetem, Nashville, Tennessee, USA),
valamint az Automatizlsi s Alkalmazott Informatikai Tanszk (Budapesti
Mszaki s Gazdasgtudomnyi Egyetem) Alkalmazott Informatika Csoport-
jnak, hallgatinknak s a SZAK Kiad munkatrsainak.
Vgl pedig tovbbra is bzunk abban, hogy ez a knyv sokak szmra
lesz megbzhat segtsg tanulmnyaik s munkik sorn, s remnyeink
szerint akad nhny olyan olvas, aki szabadidejt nem kml, lelkes tagja
lesz a szabad szoftverek nkntes fejlesztgrdjnak.
Budapest, 2012. oktber
A szerzk
ELS FEJEZET
Bevezets
1.1. A Linux
A Linux sznak tbb jelentse is van. Mszaki rtelemben pontos defincija
a kvetkez:
A Linux szabadon terjeszthet, Unix1-szer opercisrendszer -kernel.
A legtbb ember a Linux sz hallatn azonban a Linux-kernelen alapul tel-
jes opercis rendszerre gondol. gy ltalban az albbiakat rtjk rajta:
A Linux szabadon terjeszthet, Unix-szer opercis rendszer, amely
tartalmazza a kernelt, a rendszereszkzket, a programokat s a teljes
fejleszti krnyezetet.
A tovbbiakban mi is a msodik jelentst vesszk alapul, vagyis a Linuxot
mint opercis rendszert mutatjuk be.
A Linux kivl, ingyenes platformot ad a programok fejlesztshez.
Az alapvet fejleszteszkzk a rendszer rszt kpezik. Unix-szersgbl ad-
dan programjainkat knnyen tvihetjk majdnem minden Unix- s Unix-szer
rendszerre. Tovbbi elnyei a kvetkezk:
A teljes opercis rendszer forrskdja szabadon hozzfrhet, hasz-
nlhat, vizsglhat s szksg esetn mdosthat.
Ebbe a krbe beletartozik a kernel is, gy komolyabb, a kernel mdos-
tst ignyl problmk megoldsra is lehetsgnk nylik.
A Unix egy 1960-as vekben keletkezett tbbfelhasznls opercis rendszer, amelynek
nagy rszt C nyelven rtk az AT&T cgnl. vtizedekig a legnpszerbb opercis
rendszerek egyike volt. A System V az AT&T ltal fejlesztett Unix alapverzijnak a ne-
ve. A msik jelents vltozat a kaliforniai Berkeley Egyetemhez ktdik, ez a Berkeley
Software Distribution, rviden BSD.
1. fejezet: Bevezets
A Linux fejlesztse nem profitorientlt fejlesztk kezben van, gy fej-
ldsekor csak mszaki szempontok dntenek, marketinghatsok
nem befolysoljk.
A Linux-felhasznlk s -fejlesztk tbora szles s lelkes. Ennek k-
vetkeztben az interneten nagy mennyisg segtsg s dokumentci
tallhat.
Az elnyei mellett termszetesen meg kell emltennk a htrnyait is. A de-
centralizlt fejleszts s a marketinghatsok hinybl addan a Linux nem
rendelkezik olyan egysges, felhasznlbart kezeli fellettel, mint a ver-
senytrsai, belertve a fejleszti eszkzk fellett is. Ennek ellenslyozsra
az egyes disztribcik kszti tbbnyire trekednek arra, hogy a kezkbl
kiadott rendszer egysges, jl hasznlhat felletet nyjtson. m a disztrib-
cik mennyisge ugyanakkor megneheztheti a fejlesztk dolgt, ha minden
rendszeren tmogatni szeretnk a programcsomagjukat.
2
Mindezek figyelembevtelvel azonban a Linux gy is kivl lehetsgeket
nyjt a fejlesztsekhez, elssorban a grafikus felhasznli fellettel nem ren-
delkez programok terletn, de hathats tmogatst biztost grafikus kli-
ensalkalmazsok szmra is.
A Linux rendszerek hasznlata a begyazott eszkzk terletn a legjelen-
tsebb. Szmos olyan eszkzt tallhatunk manapsg az otthonokban, amelyek-
rl sokszor nem is tudjuk, hogy rajtuk egy Linux rendszer teszi a httrben a
dolgt (pldul otthoni router, DVD felvev/lejtsz, fnykpezgpek stb.).
A begyazott alkalmazsok egy kln csoportjt alkotjk a mobiltelefo-
nok. A Linux rendszer szmos mobiltelefon opercis rendszernek is az alapja.
Ezek egy rsze lnyegben csak a kernelt s a fbb fejleszti knyvtrakat
hasznlja (pldul az Android), de tallhatunk olyat is, amelyik szinte egy
teljes linuxos szmtgpnek felel meg.
1.2. A szabad szoftver s a Linux trtnete
1.2.1. FSF
A szmtstechnika hajnaln a cgek kis jelentsget tulajdontottak a szoft-
vereknek. Elssorban a hardvert akartk eladni, a szoftvereket csak jrul-
kosan adtk hozz, zleti jelentsget nem tulajdontottak neki. Ez azt ered-
mnyezte, hogy a forrskdok, az algoritmusok szabadon terjedhettek.
2
A klnbz disztribcik okozta problmban segtsget nyjt a ksbb emltett LSB-
projekt.
2
1.2. A szabad szoftver s a Linux trtnete
m ez az idszak nem tartott sokig, a gyrtk hamar rjttek a szoftver-
ben rejl zleti lehetsgekre, s ezzel beksznttt a zrt forrskd progra-
mok korszaka. Ez lnyegben azt jelenti, hogy a szoftverek forrskdjt, mint
szellemi termkeket, a cgek levdik, s zleti titokknt szigoran rzik.
Ezek a vltozsok nem nyertk el az akkoriban a Massachusettsi Msza-
ki Egyetemen (Massachusetts Institute of Technology, MIT) dolgoz Richard
Stallman tetszst. gy megalaptotta a Free Software Foundation (FSF) el-
nevezs szervezetet a massachusettsi Cambridge-ben. Az FSF clja a szaba-
don terjeszthet szoftverek fejlesztse lett.
1.2.2. GPL
Az FSF nevben a free" szabadsgot jelent, nem ingyenessget. Stallman hi-
te szerint a szoftvernek s a hozztartoz dokumentcinak, forrskdnak
szabadon hozzfrhetnek s terjeszthetnek kell lennie. Ennek elsegtsre
megalkotta (nmi segtsggel) a General Public License-t (GPL, magyarul: l-
talnos felhasznli licenc), amelyet 1989-tl hasznltak.
A GPL hrom f irnyelve a kvetkez:
1. Mindenkinek, aki GPL-es szoftvert kap, megvan a joga arra, hogy in-
gyenesen tovbbadja a forrskdjt. (Leszmtva a terjesztsi klts-
geket.)
2 . Minden szoftver, amely GPL-es szoftverbl szrmazik, szintn GPL-es
kell, hogy legyen.
3. A GPL-es szoftver birtokosnak megvan a joga ahhoz, hogy a szoftve-
reit olyan felttelekkel terjessze, amelyek nem llnak konfliktusban a
GPL-lel.
A GPL egyik jellemzje, hogy nem nyilatkozik az rrl. Vagyis a GPL-es szoft-
vertermkeinket szabadon rtkesthetjk. Egyetlen kikts az, hogy a forrs-
kd ingyenesen jr a szoftverhez. A vev ezutn azonban szabadon terjesztheti
a programot s a forrskdjt. Az internet elterjedsvel ez azt eredmnyezte,
hogy a GPL-es szoftvertermkek ra alacsony lett (sok esetben ingyenesek),
de lehetsg nylik ugyanakkor arra is, hogy a termkhez kapcsold szolgl-
tatsokat, tmogatst trts ellenben nyjtsk.
A GPL licenc 2 -es verzija 1991 nyarn szletett meg, s a szoftverek je-
lents rsze ezt hasznlja.
Mivel a megktsek nagyon szigornak bizonyultak a fejleszti knyvt-
rakkal kapcsolatban, ezrt megszletett az LGPL licenc (eredetileg Library
General Public License, ksbb GNU Lesser General Public License) krlbell
a GPLv2 -vel egy idben. Az LPGL els vltozata a 2 -es verziszmot kapta.
3
1. fejezet: Bevezets
Idkzben azonban megjelentek olyan gyrtk, akik kreatvan" rtelmez-
tk a GPLv2 licencet. A szveget betartottk, m az alapelvet megsrtettk.
3
A problmk orvoslsra 2 007 nyarn jelent meg a GPLv3. A GPLv3 fogadta-
tsa azonban vegyes volt, ezrt sokan maradtak a GPLv2 -nl.
A GPLv3-mal prhuzamosan egy j licenc is szletett reaglva a kor kih-
vsaira, nevezetesen a hlzaton fut alkalmazsokra, ilyenek pldul a webes
alkalmazsok. Ez az j licenc az AGPLv3 (Affero General Public License).
1.2.3. GNU
Az FSF ltal tmogatott legfbb mozgalom a GNU's Not Unix (rviden GNU)
projekt, amelynek az a clja, hogy szabadon terjeszthet Unix-szer opercis
rendszert hozzon ltre. Ez a projekt nagyon sokat adott hozz a Linux rend-
szerhez. Csak a legfontosabbakat emltve: a C fejleszti knyvtr, a GNU
Compiler Collection, amely a legelterjedtebb fordt eszkzcsomag, a GDB,
amely a f hibakeres program, tovbb szmos, a rendszer alapjaknt szol-
gl segdprogram.
1.2.4. Linux-kernel
A Linux-kernel trtnete 1991-re nylik vissza. Linus Torvalds, a helsinki
egyetem dikja ekkor kezdett bele a projektbe. Eredetileg az Andrew S. Ta-
nenbaum ltal tanulmnyi clokra ksztett Minix opercis rendszert hasz-
nlta a gpn. A Minix az opercis rendszerek mkdst, felptst volt
hivatott bemutatni, ezrt egyszernek, knnyen rtelmezhetnek kellett ma-
radnia Emiatt nem tudta kielgteni Linus Torvalds ignyeit, aki ezrt bele-
vgott egy sajt, Unix-szer opercis rendszer fejlesztsbe.
Eredetileg a Linux-kernelt gyenge licenccel ltta el, amely csak annyi
korltozst tartalmazott, hogy a Linux-kernel nem hasznlhat fel zleti c-
lokra. m ezt rvidesen GPL-re cserlte. A GPL felttelei lehetv tettk ms
fejlesztknek is, hogy csatlakozzanak a projekthez.
4
A MINIX kzssg jelen-
ts mrtkben tmogatta a munkt. Abban az idben nagy szksg volt egy
szabad kernelre, mivel a GNU-projekt kernelrsze mg nem kszlt el, a BSD
rendszerrel kapcsolatban pedig jogi problmk merltek fel. A pereskeds k-
zel kt vig gtolta a szabad BSD-vltozatok fejlesztst. Ez a krnyezet
nagyban hozzjrult a Linux megszletshez.
Egyes cgek, br betartottk a GPLv2 licencet, s kiadtk az ez al tartoz forrskdo-
kat, a hardverben azonban olyan trkkket alkalmaztak, mint a digitlis alrst, amely-
lyel megakadlyoztk, hogy rajtuk kvl brki ms j szoftververzit fordthasson s
telepthessen az eszkzre. A szakzsargonban ez a mdszer tivoization" nven terjedt el,
mivel a TiVo cg alkalmazta elszr.
4
A Linux-kernel jelenleg a GPLv2 licencet hasznlja.
4
1.2. A szabad szoftver s a Linux trtnete
A Linux-kernel fejldsnek llomsai a kvetkezk:
1991. szeptember: a Linux 0.01-es verzija megjelent az ftp.funet.fi
szerveren, amely a finn egyetemi hlzat llomnyszervere.
1991. oktber: Linux 0.02 .
1991. december: Linux 0.11 az els nhord Linux. Vagyis a Linux-
kernel ettl kezdve fordthat a Linux rendszeren. A korbbi fejlesz-
tsek Minix alatt trtntek.
1992 . februr: Linux 0.12 az els GPL licences kernel.
1992 . mrcius: Linux 0.95 az X Windows rendszert tltettk Li-
nuxra, gy mr grafikus felletet is kapott.
1994 . mrcius: Linux 1.0.0 a gyors fejldst ltva hamarabb vrta
mindenki, de kellett mg nhny fejleszti verzi, mire elg rett
vlt a rendszer. Ez a kernel is mg csak egy processzort s csak i386-
os architektrt tmogatott.
1995. mrcius: Linux 1.2 .0 a Linux megrkezett ms architektrk-
ra is. Az Alpha, az SPARC s a MIPS rendszerek is bekerltek a t-
mogatott platformok kz.
1996. jnius 9: Linux 2 .0.0 megjelent a tbbprocesszoros rendszerek
tmogatsa (SMP).
1999. janur 2 5: Linux 2 .2 .0 javult az SMP tmogatsa, megjelent a
tmogatott rendszerek kztt az m68k s a PowerPC.
2 001. janur 4 : Linux 2 .4 .0 megjelent az ISA PnP-, az USB- s a PC-
krtya- (PC card) tmogats. Tovbb a tmogatott architektrk k-
z bekerlt a PA-RISC. Ez a verzi abban is ms a korbbiaknl, hogy
a felgyorsult fejlds hatsra mr a stabil vltozatnak is egyre tbb
jdonsgot kellett tvennie, ilyen pldul a Bluetooth, az LVM, a
RAID, az ext3 llomnyrendszer.
2 003. december 17: Linux 2 .6.0 megvltozott, felgyorsult a fejleszt-
si modell. Nincs kln stabil s fejleszti vonal, hanem sokkal rvi-
debb ciklusokban ebbe a vonulatba kerl bele minden jts. Emellett
szmos jtst s j architektrk tmogatst hozta ez a verzi,
ezrt ezek felsorolsra jelen keretek kzt nem vllalkozunk.
2 011. jlius 2 2 : Linux 3.0 a Linux 2 0 ves vfordulja alkalmbl je-
lent meg. A verzivlts jelkpes, mivel a fejlesztsek folyamatosan
belekerltek a 2 .6.x kernelekbe. gy az j verzi technikai jtst nem
hozott a 2 .6.39-es verzihoz kpest. Megvltozott a verziszm felp-
tse, mivel a fejlesztsi modell szksgtelenn tette a hrom szintet.
5
1. fejezet: Bevezets
1.2.5. A Linux rendszer
A Linux-projekt mr a kezdetektl szorosan sszefondott a GNU-projekttel.
A GNU-projekt forrskdjai fontosak voltak a Linux-kzssg szmra a
rendszerk felptshez. A rendszer tovbbi jelents rszletei a kaliforniai
Berkley Egyetem nylt Unix-forrskdjaibl, illetve az X konzorciumtl szr-
maznak.
A klnbz Unix-fajtk egysgestett programozi felletnek ltrehoz-
sra szletett meg a C nyelven definilt POSIX- (Portable Operating System
Interface) szabvny a sz vgn az X a Unix vilgra utal , amelyet a Li-
nux implementlsakor is messzemenkig figyelembe vettek.
Szintn a Unix-fajtk egysgestsre jtt ltre a SUS (Single UNIX Spec-
ification), amely egy szabvnygyjtemny. A SUS aktulis verziinak a mag-
jt a POSIX-szabvnyok alkotjk. A SUS definilja a headerllomnyokat, a
rendszerhvsokat, a knyvtri fggvnyeket s az alapvet segdprogramo-
kat, amelyeket egy Unix rendszernek nyjtania kell. Emellett informcikat
tartalmaz a szabvnyok mgtt ll megfontolsokrl is.
6
A Linux hasonlan ms nylt opercis rendszerekhez nem rendelkezik a
SUS Unix tanstvnyval. Ennek oka rszben a tanstvny megszerzs-
nek kltsge, msrszt a Linux gyors fejldse, amely tovbbi extrakltsget
jelentene a tanstvny megtartshoz. Ugyanakkor a rendszer fejleszti tre-
kednek a SUS-szabvnyok teljestsre. Ezen okokbl a Linuxra a Unix-szer
(Unix-like) jelzt hasznljuk.
1.2.6. Linux-disztribcik
Az els Linux-disztribci (terjesztsi csomag) megjelense eltt, ha valaki
Linux-hasznl akart lenni, akkor jl kellett ismernie a Unix rendszereket, a
Linux felptst, konfigurlst, elindulsnak a folyamatt. Ennek az az
oka, hogy a hasznlnak kellett a komponensekbl felptenie a rendszert.
Belthatjuk, hogy ez jelents akadlyt jelentett a rendszer elterjedsben, hi-
szen a kezdknek nem sok eslyk volt megismerni a rendszert.
Ezrt, amint a Linux rendszert a Linux-fejlesztin kvl msok is elkezdtk
hasznlni, megj elentek az els disztribcik. A korai disztribcik tbbnyire
lelkes egynek csomagjai voltak. Nhny a korai disztribcikbl: Boot-root,
MCC Interim Linux, TAMU, SLS, Yggdrasil Linux/GNU/X.
5
Jelenleg a POSIX-szabvny az IEEE Std 1003.1-2 008 szabvnyt jelenti, amelyet POSIX.1-
2 008-knt rvidtenek. A POSIX-implementcik eltrhetnek, ugyanis a szabvny csak fe-
lletet hatroz meg, nem megvalstst. Legegyszerbben a man oldalak vgn talljuk
meg egy adott fggvny POSIX-kompatibilitst.
6
Jelenleg a SUS 3-as verzija a legelterjedtebb, amely a POSIX:2 001-es szabvnyon alapul.
Az a rendszer amelyik ezt teljesti az jogosult a UNIX 03 cmke hasznlatra. A POSIX:2 008 a
SUSv4 alapjt szolgltatja.
6
1.2. A szabad szoftver s a Linux trtnete
Az els jelents disztribci az 1993-ban megjelent Slackware volt, amelyet
az SLS-disztribcibl alaktott ki Patrick Volkerding. A Slackware tekinthet
az els olyan csomagnak, amelyet mr komolyabb httrtuds nlkl is lehetett
installlni s hasznlni. Megszletse nagyban elsegtette a Linux terjedst,
npszersgnek a nvekedst.? A Slackware egyben az alapjt szolgltatta
tbb ksbbi rendszernek is, pldul a Red Hatnek s a SuSE-nek.
A Slackware mellett azonban az SLS miatti elgedetlensg egy msik
disztribci megszletshez is hozzjrult. Ian Murdock elindtotta a Debian
projektet (a disztribci neve a felesge, Debra s sajt keresztnevnek ssze-
olvasztsa). A Debian szintn 1993-ban szletett, m az els 1.x verzi csak
1996 nyarn jelent meg. A Debian szmos tovbbi disztribci alapjaknt
szolglt s szolgl mai is.
A Red Hat Linux-disztribci 1994 novemberben jelent meg az 1.0-s ver-
zival. Ez volt az els olyan disztribci, amely az RPM csomagkezeljt
hasznlta. Ez nagy elrelpst jelentett, ugyanis sokkal knnyebb tette a
szoftvercsomagok adminisztrlst, teleptst, frisstst. Ez is hozzjrult
a Linux tovbbi elterjedshez, mert felhasznlbart, teljes rendszert bizto-
stott. Emellett a Red Hat cg olyan szint tmogats nyjtott a termkhez,
amely lehetv tette, hogy a cgek is komolyan fontolra vegyk a rendszer
hasznlatt. 2 003-ban a Red Hat Linux ebben a formjban megsznt. He-
lyette a Red Hat Enterprise Linux (RHEL) rendszert ajnlja a cg vllalati
krnyezetbe, illetve letre hvta s tmogatja a Fedora Projectet, amely a Fe-
dora disztribcit tartja karban. Az zleti vilgban az RHEL az egyik legnp-
szerbb disztribci.
Napjaink egyik leggyakrabban hasznlt Linux-disztribcija a Debian-
alap Ubuntu. A disztribci egy dl-afrikai humanista filozfirl kapta a
nevt, amelynek lnyege a msok irnti embersgessg: azrt vagyok az, aki
vagyok, amirt mi mindannyian azok vagyunk, akik vagyunk". A rendszert
a dl-afrikai Mark Shuttleworth alaptotta Canonical Ltd. fejleszti, amely a
termktmogatst pnzrt rulja, ugyanakkor az opercis rendszer ingye-
nes. Az els verzi 2 004 oktberben jelent meg.
Az eddig emltett disztribcikat szmos jabb is kvette, amelyek kln-
bz clok mentn fejldtek. gy lehetsgnk van kicsi s gyors, nagy s ltv-
nyos, stabil s kevsb aktulis vagy nem annyira stabil, de minden jdonsgot
tartalmaz rendszert is vlasztani. A disztribcik listja rendkvl hossz, gy
nem is vllalkozunk a felsorolsukra. Az interneten megtallhatjuk a neknk
legszimpatikusabbat.
m ha magyar nyelv s magyarok ltal gondozott disztribcit szeret-
nnk, akkor erre is van lehetsgnk az UHU Linux- (http: / / uhulinux.hu)
disztribci rvn. Az oktatsi intzmnyek szmra kifejlesztett SuliX
(http: / / www.sulix.hu) szintn ebbe a kategriba tartozik.
7
Jelen rs szerzje is a Slackware disztribcija rvn tallkozott elszr a Linux rend-
szerrel 1993 vgn.
7
1. fejezet: Bevezets
A Linux-disztribcik ltalban a fejleszti knyvtrakat, a fordtkat, az
rtelmezket, a parancsrtelmezket, az alkalmazsokat, a segdprogramo-
kat, a konfigurcis s csomagkezel eszkzket s mg sok ms komponenst
is tartalmaznak a Linux-kernel mellett. Az alapelemek tbbnyire megegyeznek
a disztribcikban, csak eltr verzikkal, illetve kisebb-nagyobb mdostsok-
kal tallkozhatunk. Az opcionlis fejleszti knyvtrak mr nem minden diszt-
ribciban lelhetk fel, de forrsbl lefordthatjuk ket hozzjuk.
8
Mivel a klnbz Linux-disztribcik nagymrtkben eltrhetnek egyms-
tl, ezrt felhasznlk s a fejlesztk szmra jelents problmt jelenthet a
klnbzsgek kezelse. Felismerve a problmt a Linux-disztribcik ksz-
ti ltrehoztk az LSB (Linux Standard Base) projektet, amelynek clja a rend-
szerstruktra egysgestse s szabvnyostsa. Ennek eredmnye az is, hogy
a klnbz Linux rendszereken nagyjbl egysges knyvtrstruktrkkal ta-
llkozunk. Az LSB a korbban emltett POSIX- s SUS-specifikcikat veszi
alapul, illetve ezek mellett szmos nylt szabvnyra is pt. Fejlesztknt
az LSB-projekt hatalmas segtsget nyjt neknk, mivel gy egysgesen kezel-
hetjk a Linux rendszert, s a szoftvereink szmos disztribcin lesznek m-
kdkpesek.
A knyv tematikjnak kialaktsakor trekedtnk arra, hogy lehetsg
szerint disztribcifggetlenek legynk. gy a trgyalt tmakrk minden
disztribci esetn alkalmazhatk, illetve a fejleszti eszkzket is gy v-
lasztottuk ki, hogy lehetleg ltalnosan elrhetk legyenek. m a pldaprog-
ramok fordtsakor idnknt tallkozhatunk azzal a problmval, hogy egyes
disztribcik esetben a knyvtrstruktra eltrhet. Viszont az LSB-t kvet
disztribciknl ennek minimlis az eslye.
1.3. Informciforrsok
A Linux trtnete sorn mindig is ktdtt az internethez. Internetes kzs-
sg ksztette, fejlesztette, terjesztette, gy a dokumentcik nagy rsze is az
interneten tallhat. Ezrt a legfbb informciforrsnak is az internetet te-
kinthetjk.
A Linux-vilg egyik klasszikus informciforrsa a Linux Documentation
Project (Linux dokumentcis projekt, LDP). Az LDP elsdleges feladata magas
szint, ingyenes dokumentcik fejlesztse a GNU/Linux opercis rendszer
szmra. Cljuk minden Linuxszal kapcsolatos tmakr lefedse a megfelel
dokumentumokkal. Br sok dokumentum nem teljesen aktulis, ennek elle-
8
Gyakran elhangzik a krds: melyik a legjobb disztribci? Szerintnk ilyen nincs, csak
olyan, amely elg kzel ll a felhasznl egyni ignyeihez, s mr nem kell olyan sokat
dolgoznia rajta, hogy teljesen a sajt kpre alaktsa. Ha rosszul vlaszt kiindulsi ala-
pot, akkor tbb munkja lesz vele.
8
1.3. Informciforrsok
nre is az egyik legjelentsebb informciforrsnak tekinthet. Az egyes Li-
nux-disztribtorok sokszor nagyon komoly s jl hasznlhat dokumentcit
ksztenek. m ezek a dokumentcik tbbnyire az adott disztribci haszn-
latrl, adminisztrlsrl szlnak. Szoftverfejlesztsrl ritkn tallunk do-
kumentcikat. Az LDP ltal elksztett dokumentumok a kvetkez cmen
tallhatk meg: http:/ / www.tldp.org / .
A kziknyvoldalak (manual page, rvidtve man page) a Unix klasszi-
kus elektronikus dokumentcis formja, amelyet a Linux is rklt. Ezek az
oldalak eredetileg a man segdprogrammal jelenthetk meg, de manapsg
HTML s egyb formtumban is elrhet. Emiatt magyarul szmos elnevez-
sk van, legtbben az angol elnevezst hasznljk, rott formban sokszor csak
kziknyv" hasznlatos. Az els kziknyveket a Unix szerzi rtk a hetvenes
vek legelejn. A tagolsa egysges, a POSIX-szabvny is ezzel a felptssel r-
ja le az egyes interfszeket, ezek a lersok kziknyvek formjban is ren-
delkezsre llnak sokszor kiegsztve az adott platformra jellemz tovbbi
informcival, esetleg eltrsekkel. Ez a mai napig az egyik legfontosabb do-
kumentci. Az info formtumot a GNU vezette be, ez kpes linkeket s egyb
formzsokat is kezelni.
A HOWTO-k egy-egy konkrt problma megoldst nyjtjk. Szmos
formtumban (HTML, PostScript, PDF, egyszer szveg) elrhetk. Az t-
mutat (guide) kifejezs az LDP ltal ksztett knyveket jelli. Ezek egy-egy
tmakr bvebb kifejtst tartalmazzk.
Fejlesztknt a fejleszti knyvtrak dokumentciinak vehetjk a leg-
nagyobb hasznt. Minden fejleszti knyvtr honlapjn tallunk minimlisan
egy API-dokumentcit. Gyakran tallkozhatunk azonban komoly lersok-
kal, gyakorlpldkkal is.
Az LWN (http:/ / lwn.net) a Linux-vilg hrlapja. Igyekszik sszegyjteni
minden jdonsgot a Linux vilgbl. Az ltalnos hrek mellett a Develop-
ment rovatbl tjkozdhatunk a legjabb fejleszti hrekrl, mg a Kernel
rovat a kernelfejleszts irnt rdekldknek szolgl friss informcikkal.
Ha a feladatunkkal elakadnnk, szmos frumot tallhatunk az interneten
, ahol feltehetjk a krdseinket. Radsul sokszor az is elfordul, hogy
msok mr feltettk a krdst, s mr meg is vlaszoltk. gy ha elakadunk,
akkor gyakran a legnagyobb segtsget a webes keresk jelentik, amelyek
megtalljk a kvnt frumbejegyzseket, st a kziknyvek s a howtok k-
ztt is kpesek keresni.
9
MSODIK FEJEZET
Betekints a Linux-
kernelbe
Ebben a fejezetben a Linux-kernel egyes rszeivel ismerkednk meg. A kvet-
kez ismeretek nem elengedhetetlenek ahhoz, hogy a knyv tovbbi fejezetei-
ben tallhat pldaprogramokat kzvetlenl felhasznljuk, a fejezetek megr-
tshez azonban igen. Ezek a tudnivalk megvilgtjk, hogy mi zajlik le a
rendszer bels magjban a programunk futsa kzben, gy hasznos httr-
informcit szolgltathatnak a fejlesztk szmra. Ez a fejezet teht egyfajta
ttekintst kvn nyjtani. A tovbbi, specializlt rszekben sokszor rszlete-
sebben trgyaljuk az itt bemutatottakat.
2.1. A Linux-kernel felptse
Egy opercis rendszer magjnak strukturlis felptsnl kt alapvet szls-
sges vlasztsunk van. Vlaszthatunk a mikrokernel- s a monolitikus-
kernel-struktra
kztt. A lnyegi klnbsg a kett kztt az, hogy milyen
szolgltatsokat valstanak meg a felhasznli cmtrben, illetve a kernel
cmterben. A mikrokernel csak a legszksgesebb opercisrendszer-szolgl-
tatsokat futtatja a kernelben, mg a tbbit a rugalmassg rdekben a fel-
hasznli cmtartomnyban implementlja. Ezzel szemben a monolitikus
kernelben a legtbb szolgltats a kernel rszeknt fut a nagyobb teljest-
mny rdekben. A kett kztt flton a hibrid kernel tallhat. Vegytiszta
megoldsok egyre kevsb vannak: a mikrokernel-architektrkon a jobb tel-
jestmny miatt bizonyos alacsony szint szolgltatsokat thelyeznek a ker-
nelbe (pl. a grafikusvezrlk). A monolitikus kernel esetben rszben a
rugalmassg, rszben a teljestmnymaximalizls rdekben tesznek t
funkcikat a felhasznli tartomnyba. A Linux a monolitikuskernel-megkze-
ltshez ll kzelebb, a gykerei oda nylnak vissza.
2 . fejezet: Betekints a Linux-kernelbe
A mikrokernel s monolitikus kernel kategritl fggetlenl a modern
opercis rendszerek kernele dinamikusan betlthet modulokbl pl fel, gy
hasznlat kzben az ignyeknek megfelelen bvthet vagy cskkenthet.
A struktrk alapjainak megismerse utn nzzk meg, milyen rszekre
oszthatjuk fel a Linux-kernelt. (Ez a feloszts vzlatos, a knnyebb rthetsg
rdekben nem tr ki a rendszer minden rszletre.)
Felhasznli processzek
Fejleszti knyvtrak (pl glibc)
Kernel
Rendszerhvsok
Processzkezel
llomnyrendszerek
temez
Hlzati rteg
Memria-
kezel
Egyb alrendszerek )
IPC
Perifrik kezelse
Hardver
2.1. bra. A kernel vzlatos felptse
A felhasznli programok a rendszerhvsokon keresztl krhetik a kerneltl
a kvnt szolgltatsokat. Ezeket a rendszerhvsokat a programok ltalban
a rendszerknyvtrak segtsgvel rik el.
A fjlrendszerek magasabb szint absztrakcit nyjtanak a perifrik
kezelsre. Ennek az alrendszernek a segtsgvel kezelhetnk llomnyokat,
knyvtrakat az egyes eszkzkn (ilyen llomnyrendszerek az ext4 , a proc,
az MSDOS, az NTFS, az iso-9660, az NFS stb.), de a fjlkezes mveleteivel
frhetnk hozz pldul a soros portokhoz is.
A hlzati rteg a klnbz hlzati protokollok implementcijt tar-
talmazza (IPv4 , IPv6 IPX, Ethernet stb.).
12
2.2. A Linux elindulsa
A perifriakezel
alrendszer az eszkzk alacsony szint kezelst va-
lstja meg. Hozztartozik a httrtrolk, az I/O eszkzk, a soros/prhuza-
mos s az egyb portok kezelse.
A folyamatkezel alrendszer tbb, a processzek kezelsvel kapcsolatos
funkcit valst meg:
A Linux tbbfeladatos (multitask) rendszer, ez azt jelenti, hogy tbb
processzt futtat prhuzamosan (tbbprocesszoros rendszer) vagy kv-
zi prhuzamosan, vltogatva (egyprocesszoros rendszer). Azt, hogy az
egyes processzek mikor jussanak a processzorhoz, az temez dnti el.
A processzeknek ltalban szksgk van arra, hogy egymssal kom-
munikljanak. Ezt az IPC- (Interprocess Communication, processzek
kztti kommunikci) alrendszer teszi lehetv.
A fizikai memria kiosztst a processzek kztt a memriakezel al-
rendszer vgzi el.
A kvetkez fejezetekben fknt a processzkezel alrendszer egyes rszeivel, az
temezs mkdsvel, illetve a memriakezels elmletvel ismerkednk meg.
Az IPC-alrendszerre nem trnk ki; lehetsgeit, hasznlatt ksbb trgyaljuk.
2.2. A Linux elindulsa
Egy opercis rendszer betltdse, elindulsa els pillantsra mindig kicsit
rejtlyes dolognak tnik. ltalban ha egy, a httrtroln lv programot
szeretnnk betlteni, lefuttatni, akkor berjuk a nevt a parancsrtelmezbe,
vagy rkattintunk az ikonjra, s az opercis rendszer elindtja. m hogyan
trtnik mindez, amikor a gp indulsakor magt az opercis rendszert sze-
retnnk betlteni, elindtani?
A Linux-kernel betltst s elindtst az gynevezett kernelbetlt vg-
zi el. Ilyen program a LILO (The Linux Loader), a LOADLIN, a Grub s mg
sorolhatnnk. A program betltshez szksg van egy kis hardveres segt-
sgre is. ltalban a gp csak olvashat memrijban van egy kis program
(az x86-os architektra esetben ennek a neve BIOS vagy (U)EFI), amely
megtallja, betlti s futtatja ezt a kernelbetltt. Vagyis sszegezve: egy
rvid, begetett program lefut, s elindt egy valamivel nagyobb betltprog-
ramot. Ez a betltprogram pedig elindt egy mg nagyobb programot, neve-
zetesen az opercis rendszer kernelprogramjt.
9
9
Lehetsg van arra, hogy a betltprogramokat mg tovbb lncoljuk. Ezltal lehetv
vlik a tbb opercis rendszert tartalmaz gpeken, hogy indulskor kivlaszthassuk a
szmunkra szksgeset.
13
2. fejezet: Betekints a Linux-kernelbe
A kernel manapsg ltalban tmrtett formban van a lemezeken, s
kpes nmagt kitmrteni. gy az els lps a kernel kitmrtse, majd
a kd feldolgozsa a kitmrtett kernel kezdcmtl folytatdik. Ezt kveti a
hardver inicializlsa (memriakezel, megszaktstblk stb.), majd az els
C-fggvny (start_kernel()) meghvsa. Ez a fggvny, amely egyben a 0-s
azonostj processz belpsi pontja, inicializlja a kernel egyes rszeit.
Az inicializci vgn a 0-s processz elindt egy kernelszlat (a neve nit),
majd egy resjrati ciklusba (idle loop) kezd, gy a tovbbiakban a 0-s pro-
cessz szerepe mr elhanyagolhat.
Az nit kernelszlnak vagy processznek a processzazonostja az 1. Ez a
rendszer els igazi processze. Elvgez mg nhny belltst (elindtja a fjl-
rendszert szinkronizl s lapcserekezel folyamatokat, felleszti a rendszer-
konzolt, felcsatolja [mount] a gykr-llomnyrendszert [root file system]),
majd lefuttatja a rendszerinicializl programot (nem keverend a korbban
emltett processzel). Ez a program az adott disztribcitl fggen a kvetke-
zk valamelyike: /etc/init, /bin/init, /sbin/init.
10
Az nit program az /etc/ inittab11
konfigurcis llomny segtsgvel j, immr felhasznli processze-
ket hoz ltre, s ezek tovbbi j processzeket. Pldul a getty processz ltrehozza
a login processzt, amikor a felhasznl bejelentkezik. Ezek a processzek mind
az nit kernelszl leszrmazottai.
2.3. Processzek
A processz egy mkds kzbeni program. Ebbl addan a programkdot s
a hozztartoz erforrsokat tartalmazza.
A processzek meghatrozott feladatokat hajtanak vgre az opercis
rendszeren bell. A feladat lersa az a program, amely gpi kd utastsok
s adatok egyttesbl ll. Ezeket a lemezeken troljuk, gy a program nma-
gban passzv entits.
Ezzel szemben a processz mr dinamikus entits. Folyamatosan vltozik,
ahogy a processzor egyms utn futtatja az egyes utastsokat. A program
kdja s adatai mellett a processz tartalmazza a programszmllt, a CPU-
regisztereket, tovbb a processz vermt, amely az tmeneti adatokat (fgg-
vnyparamterek, visszatrsi cmek, elmentett vltozk) trolja.
10
Ha egyik helyen sem tallja meg a rendszer az nit programot, akkor megprblja feldol-
gozni az /etc/rc llomnyt, s elindt egy shellt, hogy a rendszergazda megjavthassa a
rendszert.
11
A Linux rendszereken elterjedben van az esemnyalap, upstart nev nit implement-
ci. Ez a megolds a hagyomnyos System V nit programhoz kpest eltr konfigurcis
megoldsokat alkalmaz.
14
2.3. Processzek
A Linux tbbfeladatos (multitask) opercis rendszer, a processzek sajt
jogokkal rendelkez elklntett feladatok (task), amelyeket a Linux prhu-
zamosan futtat. Egy processz sszeomlsa nem okozza a rendszer ms pro-
cesszeinek az sszeomlst. Minden klnll processz a sajt virtulis cm-
tartomnyban fut, s nem kpes ms processzekre hatni. Kivtelt kpeznek
ez all a biztonsgos, kernel ltal kezelt mechanizmusok, amelyekkel a pro-
cesszek magvalsthatjk az egyms kztti kommunikcit.
letciklusa sorn egy processz szmos rendszererforrst hasznlhat
(CPU, memria, llomnyok, fizikai eszkzk stb.). A Linux feladata az, hogy
ezeket a hozzfrseket knyvelje, kezelje, s igazsgosan elossza a konkurl
processzek kztt.
2.3.1. A Linux-processzekhez kapcsold informcik
A Linux minden processzhez hozzrendel egy ler adatstruktrt,
12
az eb-
ben szerepl adatok jellemzik az adott processzt, s befolysoljk a mkdst.
Ez a feladatokat ler adatstruktra nagy s komplex, m feloszthat nhny
funkcionlis terletre:
llapot
A processz a futsa sorn a krlmnyektl fggen klnbz llapo-
tokba kerlhet, ezeket az llapotokat a 2.3.2. alfejezetben trgyaljuk.
Azonostk
A rendszerben minden processznek van egyedi azonostja. Ezen tl
minden processz rendelkezik felhasznli s csoportazonostkkal.
Ezek szablyozzk az llomnyokhoz s az eszkzkhz val hozzf-
rst a rendszerben. (Bvebben lsd a 2.3.3. alfejezetben.)
Kapcsolatok
A Linuxban egyetlen processz sem fggetlen a tbbitl. Az nit pro-
cesszt leszmtva minden processznek van szlje. Az j processzek
nem ltrejnnek, hanem a korbbiakbl msoldnak, klnozdnak.
Minden processzler adatstruktra tartalmaz hivatkozsokat a sz-
lprocesszre s a leszrmazottakra. Ezt a kapcsoldsi ft a pstree pa-
ranccsal nzhetjk meg.
temezsi informci
Az temeznek szksge van bizonyos informcikra: priorits, sta-
tisztikai informcik stb., hogy igazsgosan dnthessen, hogy melyik
processz kerljn sorra. Az temezst a 2.3.6. alfejezet trgyalja.
1,
A ler adatstruktra tpusa megtallhat a kernelforrsban. A neve task_struct, s az
include/linux/sched.h llomnyban tallhat.
15
2. fejezet: Betekints a Linux-kernelbe
Memriainformcik
A processz memriafoglalsval kapcsolatos informcik (kd-, adat-,
veremszegmensek) tartoznak ide.
Fjlrendszer
A processzek megnyithatnak s bezrhatnak llomnyokat. A pro-
cesszler adatstruktra tartalmazza az sszes megnyitott llomny
lerjt, tovbb az aktulis, gynevezett munkaknyvtrnak
(working directory) a mutatjt.
Processzek kztti kommunikci
A Linux tmogatja a klasszikus Unix IPC-mechanizmusokat (jelz-
sek, csvezetkek, szemaforok) s a System V IPC-mechanizmusokat
is (megosztott memria, szemafor, zenetsor). Egy kifejezetten a Unix
opercis rendszerekre jellemz processzek kzti aszinkron kommu-
nikcis forma a jelzs (signal). A jelzst kld processz nem vrako-
zik a kzbestsre, klds utn folytatja futst. Jelzs rkezsekor a
fogad processz norml futsa megszakad, s vagy a processz ltal
megadott, vagy az alaprtelmezett jelzskezel fggvny fut le. Ezek
utn a processz ott folytatja a futst, ahol abbahagyta. A futs meg-
szaktst, a jelzskezel futtatst, majd a futs folytatst a kernel
teljes mrtkben kezeli. A jelzshez tartozik egy egsz szm, amely a
jelzs kivltsnak okt adja meg. Ezt az egsz szmot szimbolikus
konstanssal adjuk meg, rtke a signal.h llomnyban tallhat.
A szimbolikus konstansok SIG eltaggal kezddnek. Pldul nullval
val oszts esetn a kernel SIGFPE jelzst kld a mveletet futtat
processznek, illetve akkor, ha egy processz futst azonnal meg sze-
retnnk szaktani, SIGKILL jelzst kldnk neki.
Id s idztk
A kernel naplzza a processzek ltrehozsi s CPU-felhasznlsi ide-
jt. A Linux tmogatja tovbb az intervallumidztk hasznlatt a
processzekben, amelyeket belltva jelzseket kaphatunk bizonyos id
elteltvel. Ezek lehetnek egyszeri vagy periodikusan ismtld rtes-
tsek. (Bvebben lsd a 2.3.8. alfejezetben.)
Processzorspecifikus adatok (Context)
A folyamat a futsa sorn hasznlja a processzor regisztereit, a ver-
met stb. Ez a processz krnyezete, s amikor feladatvltsra kerl
sor, ezeket az adatokat le kell menteni a processzt ler adatstrukt-
rba. Amikor a processz jraindul, innen lltdnak vissza az adatok.
16
Esemny
bekvetkezik
Esemnyre
vr
Ltrehozs
Jelzs Jelzs
Megsznik
Futs
vge
2.3. Processzek
2.3.2. A processz llapotai
A futs sorn a processzek klnbz llapotokba juthatnak. Az llapot fgg-
het a processz aktulis teendjtl s a kls hatsoktl. A processz aktulis
llapott a processzhez rendelt ler struktra llapotler vltozja trolja.
Linux alatt egy processz lehetsges llapotai a kvetkezk:
A processz ppen fut az egyik processzoron. (Az llapotvltoz rtke:
RUNNING.)
A processz futsra ksz, de msik foglalja a processzort, ezrt vra-
kozik a listban. (Az llapotvltoz rtke ilyenkor is: RUNNING.)
A processz egy erforrsra vagy esemnyre vrakozik. Ilyenkor attl
fggen kap rtket az llapotvltoz, hogy a vrakozst megszakthat-
ja egy jelzs (INTERRUPTABLE), vagy sem (UNINTERUPTABLE).
A jelzssel nem megszakthat llapot egyik alesete az, amikor a kriti-
kus, a folyamat lellst eredmnyez jelzsek mg megszakthatjk a
vrakozst (KILLABLE).
A processz felfggesztve n, ltalban a SIGSTOP jelzs kvetkezt-
ben. Ez az llapot hibajavtskor jellemz, de a terminlban futtatott
folyamatnl a CTRL + Z billenty kombincival szintn elrhetjk.
(Az llapotvltoz rtke: STOPPED.)
A processz ksz az elmlsra (mr nem l, de mg nem halott: zom-
bi), de valami oknl fogva mg mindig foglalja a ler adat struktr-
jt. (Az llapotvltoz rtke: ZOMBIE.)
Az llapotok kapcsolatait a 2.2. bra szemllteti:
2.2. bra. A processz llapotatmenet -diagramja
17
2. fejezet: Betekints a Linux-kernelbe
A processzeket a fenti llapotdiagram szerint az temez (scheduler) kezeli.
Az temezsi algoritmusokat s a processzekhez tartoz adatterleteket a
2.3.6. alfejezetben trgyaljuk bvebben.
2.3.3. Azonostk
A Linux-kernel minden processzhez egy egyedi azonostt rendel: pid (process
ID). Ksbb ezzel az azonostszmmal hivatkozhatunk a processzre.
Minden folyamat egy processzcsoport tagja, amelynek azonostjt a pgid
(process group ID) mez tartalmazza. Amikor a folyamat ltrejn, a szlfo-
lyamat pgid azonostjt rkli, m ez ksbb mdosthat. A processzcsoport
arra hasznlhat, hogy tagjainak egyszerre kldjnk jelzseket, vagy valame-
lyik tagjnak befejezdsre vrakozzunk.
A konvenci szerint a pgid azonost szmrtke a csoport els tagjnak
pid rtkvel egyezik meg. j csoportot is gy tudunk ltrehozni, ha a pgid
rtkt a folyamat pid rtkre lltjuk. Ekkor a folyamatunk a csoport veze-
tje lesz. A csoport vezetjnek szerepe annyiban specilis, hogy ha vget r,
akkor a csoport tbbi tagja egy SIGHUP jelzst kap. (Bvebben lsd az 5.6.
Jelzsek cm alfejezetben.) A jelzs hatsra a folyamatok dnthetnek arrl,
hogy lellnak-e (alaprtelmezett), vagy folytatjk a futsukat.
Tbb processzcsoport sszekombinlhat egy munkamenett (session).
Minden folyamatnak a munkameneten bell azonos a sessionid rtke.
Linux alatt a szlak specilis folyamatoknak szmtanak. Ezrt fontos a
rendszer szmra annak knyvelse, hogy mely szlak tartoznak egybe, egy
folyamathoz. Az sszetartoz szlakat a szlcsoportok tartalmazzk. A folya-
mat szlcsoport-azonostja a tgid.
A Linux, mint minden ms Unix rendszer, felhasznli- s csoportazono-
stkat hasznl az llomnyok hozzfrsi jogosultsgnak az ellenrzsre.
A Linux rendszerben minden llomnynak van tulajdonosa s jogosultsgi
belltsai. A legegyszerbb jogok a read, a write s az execute. Ezeket rendel-
jk hozz a felhasznlk hrom osztlyhoz: ezek a tulajdonos, a csoport s a
rendszer tbbi felhasznlja. A felhasznlk mindhrom osztlyra kln be-
llthat mindhrom jog.
Termszetesen ezek a jogok valjban nem a felhasznlra, hanem a fel-
hasznl azonostjval fut processzekre rvnyesek. Ebbl kvetkezen a
processzek az albbi azonostkkal rendelkeznek:
uid, gid
A felhasznl felhasznli s csoportazonosti, amelyekkel a pro-
cessz fut.
Effektv uid s gid
Ezeket az azonostkat hasznlja a rendszer annak vizsglatra, hogy
a processz hozzfrhet-e az llomnyhoz. Klnbzhetnek a valdi
felhasznltl s csoporttl. Ezeket a programokat nevezzk setuidos,
18
2 .3. Processzek
illetve csoportllts esetn setgides programoknak. Segtsgkkel
korltozott hozzfrst nyjthatunk a rendszer egyes vdett, csak a
rendszergazda szmra hozzfrhet rszeihez.
Fjlrendszer-uid s -gid
Ezek norml esetben megegyeznek a valdi azonostkkal, s a fjl-
rendszerhez val hozzfrsi jogosultsgokat szablyozzk. Elssorban
az NFS-fjlrendszereknl
13
van rjuk szksg, amikor a felhasznli
zemmd NFS-szervernek klnbz llomnyokhoz kell hozzfr-
nie az adott felhasznl nevben. Ebben az esetben csak a fjlrend-
szer-azonostk vltoznak.
Mentett uid s gid
Olyan programok hasznljk, amelyek a processz azonostit rendszer-
hvsok ltal megvltoztatjk. A valdi uid s gid elmentsre szol-
glnak, hogy ksbb visszallthatk legyenek.
2.3.4. Processzek ltrehozsa s terminlsa
j processzt egy korbbi processz lemsolsval hozhatunk ltre. Ez a fork
rendszerhvssal valsthat meg. A msolat teljesen megegyezik az eredetivel,
csak a processzazonostban klnbznek. Az eredeti processzt szlprocessz-
nek, a msolatot, a leszrmazottat gyerekprocessznek nevezzk. Termszete-
sen, ha ksbb az egyes processzek mdostanak a bels vltozikon, akkor ez
a msik processznl mr nem rvnyesl.
A valsgban a gyerekfolyamat ltrehozsakor nem trtnik tnyleges
msols. Helyette a Linux a COW metdust hasznlja (lsd ksbb a 2.4.7. al-
fejezetben).
Ha egy program egy msik programot akar futtatni, akkor sincs ms t: a
processznek le kell msolnia magt, s a gyerekprocessz tlti be a futtatand
msik programot. Ezrt gyakori az a forgatknyv, hogy az j folyamat ltre-
hozsa utn egy rendszerhvssal azonnal betltnk egy j programot, s azt
futtatjuk. Ilyenkor az eredeti folyamat memrijnak a lemsolsa felesleges.
Erre az esetre szolgl a vfork fggvny, amelyben a memria msolsa he-
lyett a rendszer megosztja a memrit a szl s a gyerek kztt addig, amg
a gyerek betlt egy j programkdot. Erre az tmeneti idre a szlfolyamat
blokkoldik. Amita a Linux a COW metdust hasznlja a fork rendszerh-
vsnl, azta a vfork elnye valjban mr elhanyagolhat, gy nem jellemz
a hasznlata.
13
Az NFS (Network File System) elssorban Unix rendszereknl hasznlt hlzati fjl-
rendszer.
19
2 . fejezet: Betekints a Linux-kernelbe
A Linux mind a fork, mind a vfork rendszerhvst valjban a clone rend-
szerhvssal valstja meg. A clone ltrehoz egy j folyamatot a szlfolyamat-
bl, s lehetv teszi, hogy megadjunk, mely memriaterleteken osztozzon a
kt folyamat. Mint lthat, a fork s a vfork fggvnyek valjban a clone
specializlt esetei. A clone teszi lehetv a kernelszint szlkezels imple-
mentcijt is Linux alatt.
14
A gyerekfolyamat a szl teljes msa, csak a pid s a ppid rtkekben tr
el tle. Ezen kvl nem rkldnek mg az llomnyzrolsok s az aktulis
jelzsek.
Ha a gyerekfolyamat a programkdjnak a vgre rt, vagy terminl jelle-
g jelzst kap, akkor ezt a tnyt egy SIGCHLD jelzssel jelzi a szl szmra,
befejezi a futst, s zombi llapotba kerl. Addig zombi llapotban marad,
amg a szljnek tadja az eredmnyt. Ameddig a szl ezt nem veszi t t-
le, addig a gyerekfolyamat zombi llapotban vrakozik.
Felvetdik a krds, mi trtnik akkor, ha a szl fejezi be hamarabb a
futst, s nem a gyerek. A gyerek ilyenkor rva lesz, s az nit veszi t a sz-
l szerept. Amikor a gyerekfolyamat vgzett, akkor az nit tveszi tle a visz-
szatrsi rtkt, gy teljesen megsznhet.
2.3.5. A programok futtatsa
A Linuxban, mint a tbbi Unix rendszerben, a programokat s a parancsokat
ltalban a parancsrtelmez futtatja. A parancsrtelmez egy felhasznli
processz, amelynek a neve shell.
Linuxos rendszereken tbb parancsrtelmez kzl vlaszthatunk (sh,
bash, tcsh stb.). A parancsrtelmezk tartalmaznak nhny beptett paran-
csot. A tbbi begpelt utastst mint programnevet rtelmezik. A parancsknt
megadott llomnynvvel keresnek egy futtathat llomnyt a PATH kr-
nyezeti vltoz ltal megadott knyvtrakban. Ha megtalljk, akkor betltik
s lefuttatjk. A parancsrtelmez a fent emltett fork metdussal lemsolja
magt, s a megtallt llomny az j, leszrmazott processzben fut. Norml
esetben a parancsrtelmez megvrja a gyerekprocessz futsnak a vgt, s
csak ezutn adja vissza a vezrlst a felhasznlnak, de lehetsg van a pro-
cesszt a httrben is futtatni.
A futtathat fjl tbbfle binris vagy szveges parancsllomny (script) le-
het. A parancsllomnyt az els sorban megadott program (amely ltalban
egy parancsrtelmez), ennek hinyban az ppen hasznlt parancsrtelmez
rtelmezi.
14
Mint lthat, Linux alatt a szlak nincsenek szigoran megklnbztetve a processzektl .
A szlak valjban kzs memrin osztoz processzek sajt processzazonostval.
2 0
2 .3. Processzek
A binris llomnyok informcikat tartalmaznak az opercis rendszer
szmra, hogy rtelmezni s futtatni tudja ket, tovbb tartalmazzk a
programkdot s az adatokat. A Linux alatt a leggyakrabban hasznlt binris
formtum az ELF.
15
A tmogatott binris formtumokat a kernel fordtsakor vlaszthatjuk
ki, vagy utlag modulknt illeszthetjk be az rtelmezsket. Az ltalnosan
hasznlt formtumok az a.out, az ELF, de pldul a Java class fjlok felisme-
rst is bekapcsolhatjuk.
2.3.6. temezs
A Linux rendszerek prhuzamosan tbb folyamatot futtathatnak. Ritka az az
eset, amikor a processzorok szmt nem haladja meg a folyamatok szma.
Ezrt, hogy az egyes processzek tbb-kevsb prhuzamosan futhassanak,
az opercis rendszernek folyamatosan vltogatnia kell, hogy melyik processz
kapja meg a processzort. Az temez feladata az, hogy szablyozza a procesz-
szorid kiosztst az egyes folyamatok szmra.
Ahhoz, hogy az temezs felhasznli szempontbl knyelmes legyen,
szksg van arra, hogy a felhasznl az egyes folyamatok prioritst szab-
lyozhassa, s az szemszgbl nzve a processzek prhuzamosan fussanak.
A rossz temezsi algoritmus az opercis rendszert dcgss, lassv tehe-
ti, az egyes processzek tlzott hatssal lehetnek egymsra a processzorid el-
osztsa sorn. Ezrt a Linux fejleszti nagy figyelmet fordtottak az temez
kialaktsra.
A processzek vltogatsval kapcsolatban kt krds merl fel.
Mikor cserljnk le egy processzt?
Ha mr eldntttk, hogy lecserlnk egy processzt, melyik legyen az
a processz, amelyik a kvetkez lpsben megkaphatja a CPU-t?
Ezekre a krdsekre adunk vlaszt a tovbbiakban.
2.3.6.1. Klasszikus temezs
A klasszikus Linux-temezs idosztsos rendszert hasznl. Ez azt jelenti, hogy
az temez az idt kis szeletekre osztja (time-slice), s ezekben az idszeletekben
valamilyen kivlaszt algoritmus alapjn adja meg az egyes processzeknek a fu-
ts lehetsgt. m az egyes processzeknek nem kell kihasznlniuk az egsz
15
Az ELF (Executable and Linkable Format, futtathat s linkelhet formtum) binris
formtumot eredetileg a System V Release 4 UNIX-verziban vezettk be. Ksbb a Li-
nux fejleszti is tvettk, mert a bels felptse sokkal flexibilisebb, mint a rgebbi a.out
formtum. Ezen kvl egy hatkony debug formtuma is ltezik, amelynek neve DWARF
(Debugging With Attribute Record Format), amely dinamikusan egy lncolt listban t-
rolja a hibakeresshez szksges informcit.
2 1
2. fejezet: Betekints a Linux-kernelbe
idszeletet, akr le is mondhatnak a processzorrl, ha ppen valamilyen rend-
szeresemnyre kell vrakozniuk. Ezek a vrakozsok a rendszerhvsokon
bell vannak, amikor a processz ppen kernelzemmdban fut.
16
A Linuxban a nem fut processzeknek nincs eljoga az ppen fut pro-
cesszekkel szemben, nem szakthatjk meg a fut folyamatokat annak rde-
kben, hogy tvegyk a processzort. Vagyis az idszeleten bell csak a fut
folyamatok mondhatnak le a processzorrl nkntes alapon, s adhatjk t
egymsnak a futs lehetsgt.
A fenti kt alapelv gondoskodik arrl, hogy megfelel idpontban kvet-
kezzen be a vlts. A msik feladat a kvetkez processz kivlasztsa a fu-
tsra kszek kzl. Ezt a vlasztsi algoritmust a kernelen bell a schedule()
fggvny implementlja.
A klasszikus temezs hrom stratgit (policy) tmogat: a szoksos Unix
temezsi mdszert s kt, vals idej (real-time) processzek temezsre
szolgl algoritmust. A vals idej processz a szoksos rtelmezs szerint azt
jelenten, hogy az opercis rendszer garantlja, hogy az adott processz egy
megadott, rvid idn bell megkapja a processzort, amikor szksge van r,
gy reaglhat a kls esemnyekre. Ezt hvjuk hard real-time"-nak. m
a Linux csak egy gynevezett soft real-time" megkzeltst tmogat, amely a
vals idej processzeket a kivlaszts sorn elre veszi, gy a lehetsg szerinti
legkisebb ksleltetssel juttatja processzorhoz. Mg a klasszikus temezsnl
jelents az eltrs a Linux soft real-time megoldsa s egy hard real-time rend-
szer kztt, a manapsg hasznlatos megoldsoknl mr nem olyan les a ha-
trvonal. (Ezt a tmakrt rszletesen lsd a 2.3.8. alfejezetben.)
A Linux a kvetkez futtatand processz kivlasztshoz prioritsos te-
mezalgoritmust hasznl. A norml processzek kt prioritsrtkkel rendel-
keznek: statikus s dinamikus prioritssal. A vals idej processzekhez a
Linux trol mg egy prioritsrtket is, a vals idej prioritst (real time
priority). Ezek a prioritsrtkek egyszer egsz szmok, amelyeknek a segt-
sgvel a kivlasztalgoritmus slyozza az egyes processzeket.
A statikus priorits
A nvben szerepl statikus sz jelentse az, hogy rtke nem vltozik
az id fggvnyben, csak a felhasznl mdosthatja. A processzin-
formcik kztt a neve nice, amely arra utal, hogy az temez milyen
kedves" lesz a processzel, s mennyire knlja processzoridvel.
16
Minden processz rszben felhasznli zemmdban, rszben kernelzemmdban fut.
A felhasznli zemmdban jval kevesebb lehetsge van a processznek, mint kernel-
zemmdban, ezrt bizonyos erforrsok, rendszerszolgltatsok ignybevtelhez t kell
kapcsolnia. Ilyenkor az tkapcsolshoz a processz egy rendszerhvst hajt vgre (a Linux
felhasznli kziknyv [manual] 2 . szekcija tartalmazza ezeket, pldul: read()). Ezen a
ponton a kernel futtatja a processz tovbbi rszt.
2 2
2.3. Processzek
A dinamikus priorits
A dinamikus priorits lnyegben egy szmll, rtke a processz fu-
tsnak fggvnyben vltozik. Segtsgvel az temez nyilvntart-
ja, hogy a processz mennyi futsi idt hasznlt el a neki kiutaltbl.
Ha pldul egy adott processz sokig nem jutott hozz a CPU-hoz, ak-
kor a dinamikus prioritsi rtke magas lesz. A processzinformcik
kztt a neve counter, vagyis szmll.
A vals idej priorits
Jelzi, hogy a processz vals idej, gy minden norml processzt ht-
trbe szort a vlasztskor. Tovbbi funkcija, hogy a vals idej pro-
cesszek kztti prioritsviszonyt megmutassa. A processzinformcik
kztt a neve rt_priority.
Norml processzek esetben a Linux temezsi algoritmusa az idt korsza-
kokra (epoch) bontja. A korszak elejn minden processz kap egy meghatrozott
mennyisg idegysget, vagyis a kernel a szmlljt egy, a statikus priorit-
sbl meghatrozott rtkre lltja Amikor egy processz fut, ezeket az idegy-
sgeket hasznlja el, vagyis a szmllja cskken. Ha elfogyott az idegysge,
akkor mr csak a kvetkez ciklusban futhat legkzelebb. Egy korszaknak ak-
kor van vge, amikor minden RUNNING llapot processznek elfogyott az
idegysge (teht a vrakoz processzek nem szmtanak). Ilyenkor j kor-
szak kezddik a processzek letben. Ezzel a mdszerrel elrhet, hogy sszer
idn bell minden processz kapjon tbb-kevesebb futsidt, vagyis egyiket se
heztessk ki.
A FIFO vals idej temezs esetn csak a vals idej prioritsnak van
szerepe az temezsben. A legnagyobb priorits processzek kzl a sorban a
legels futhat egszen addig, amg t nem adja msnak a futs lehetsgt
(vrakoznia kell, vagy vget rt), vagy nagyobb priorits processz nem
ignyli a processzort.
A krbeforg (round-robin) vals idej temezsi algoritmus a FIFO to-
vbbfejlesztett vltozata. Mkdse hasonlt a FIFO temezshez, m egy pro-
cessz csak addig futhat, amg a neki kiutalt idegysge el nem fogy, vagyis a
szmlljnak az rtke el nem ri a 0-t. Ilyenkor a sor vgre kerl, s a rend-
szer megint kiutal szmra idegysgeket. Ezltal lehetv teszi a CPU igazs-
gos elosztst az azonos vals idej prioritssal rendelkez processzek kztt.
2.3.6.2. Az 0(1) temezs
Az 0(1) temezs a 2 .6-os kernellel egytt jelent meg. A Java virtulis gpek
miatt volt r szksg a sok prhuzamosan fut szl kvetkeztben. Mivel a
korbbi temezalgoritmus futsi ideje egyenes arnyban llt a processzek/
szlak szmval, ezrt nagy mennyisg szl esetn a hatkonysga jelent-
sen cskkent. Az 0(1) temez erre a problmra jelentett megoldst, mivel
az temezsi algoritmus futsideje nem nvekszik a processzek szmval. Ezt a
Linux gy oldja meg, hogy prioritsi szintekbe rendezi a processzeket, amely
23
2. fejezet: Betekints a Linux-kernelbe
egy ktszeresen lncolt lista. Egy bittrkp alapjn az temez nagyon gyorsan
meg tudja tallni azt a legmagasabb prioritsi szintet, ahol processz vrakozik.
Ezutn az ezen a prioritsi szinten elhelyezked els processzt kell futtatnia.
A bittrkp mrete csak a prioritsi szintek szmtl fgg, a processzek szm-
tl nem.
2.3.6.3. Teljesen igazsgos temez
A teljesen igazsgos temez (Completely Fair Scheduler, CFS) a 2 .6.2 3-as
kerneltl kezdden az ltalnos kernel alaprtelmezett temezalgoritmusa.
A klasszikus temezsi algoritmushoz kpest az egyik legjelentsebb eltrse,
hogy a futsi id arnyra koncentrl. A CFS olyan krkrs priorits te-
mez, amely a processzek idszeletnek arnyt prblja igazsgoss tenni.
Idelis esetben, ha van N darab processznk, mindegyik a rendelkezsre ll
id 1 /N-ed rszben fut. Ezt a szmtst egy adott idtartamra kalkulljuk
ki, a neve cllappangsi id (target latency). Ha ez az id 30 ms, s hrom
processznk van, N = 3, mindegyik processzre 1/3 arnyban jut id, vagyis
mindegyik 10 ms-ig fut. A processzek kztti vlts idignye elhanyagolhat.
Ha azonban tl sok processz fut a rendszerben, ttelezzk fel, hogy 100, ak-
kor 0,3 ms-onknt kellene vltani, ez pedig mr nem kifizetd. Ezrt ennek
az algoritmusnak van egy minimlis felbontsa (minimum granularity),
amely al nem megy az temezs. Ha ez az rtk 1 ms, akkor mind a 100 pro-
cessz 1 ms-ig fut. Termszetesen ebben az esetben az algoritmus mr nem is
nevezhet igazsgosnak mg az idarny tekintetben sem.
A nice
rtkek abszolt rtke nem szmt, a relatv rtkek alapjn az
algoritmus egy arnyszmot szmol. Kt processz esetn nulla, s egy 5 nice
rtk ugyanolyan arnyban fut, mint egy 10 s 15 rtk.
Az algoritmus implementcija azt az idt trolja, amennyit a processz
legutoljra futott, pontosabban ezt mg elosztja a processzek szmval. Ezt
az rtket virtulis futsidnek (virtual runtime) nevezzk, amely nanosze-
kundum felbonts. Ezt az rtket az temez folyamatosan karbantartja. Ide-
lis esetben ez az rtk ugyanannyi lenne minden azonos priorits processz
esetben. Egy vals processzornl ezt gy lehet ellenslyozni, hogy mindig a
legkisebb virtulis futsidej processzt futtatjuk. A CFS is pontosan gy tesz.
Ahhoz, hogy megtallja a legkisebb rtket, a vrakozsi listt egy telje-
sen kiegyenslyozott piros-fekete binris fban trolja. Ennek a leggyakrab-
ban hasznlt bal oldali elemt gyorsttrazza is a hatkonysg rdekben.
Az temezs ennl az algoritmusnl O(log n) komplexits, m tnyleges
rtke kisebb, mint a korbbi temeznl volt. A taszkok vltsa konstans
id, viszont a levltott taszk beillesztse a binris fba O(log
n) idt ignyel.
Az temez tovbbi jtsa a korbbakkal szemben, hogy az temezsi
stratgik implementcija modulris felpts lett. gy szabadon bvthet
tovbbi algoritmusokkal. Ugyanakkor tartalmaz egy j stratgit is, amely-
nek neve batch". Ez lehetv teszi olyan alkalmazsok futtatst, amelyeket
24
2.3. Processzek
hosszabban rdemes futtatni a processzoron, ugyanakkor nem ignylik a
gyakori meghvst, mert nem kell felhasznli esemnyekre reaglniuk. Ezek
tbbnyire szerveralkalmazsok.
A CFS-temezben is az trtnik, hogy a vals idej folyamatok megel-
zik a norml temezseket. Ugyanakkor, mivel nincsenek idszeletek, ezrt
a rendszer szinte azonnal vlthat, ha egy vals idej folyamat futsra kssz
vlik. A gyorsttrazs miatt a taszkvlts is rvid id alatt vgrehajtdik.
2.3.6.4. Multiprocesszoros temezs
Szimmetrikus multiprocesszoros (SMP) krnyezetben az temezsi metdust
kicsit mdostani kell. Ilyenkor minden processzor kln, sajt magnak fut-
tatja az temez funkcit, m a processzoroknak clszer informcikat cse-
rlnik a rendszer teljestmnynek a nvelse rdekben.
Amikor az temez kiszmolja az adott processz slyozst, azt is figye-
lembe kell vennie, hogy korbban a processz ugyanazon a processzoron futott-e,
vagy egy msikon. Azok a processzek, amelyek az adott CPU-n futottak, mindig
elnyt lveznek, mivel a CPU-hardver gyorsttra mg mindig tartalmazhat
rjuk vonatkoz informcikat. Ezzel a mdszerrel az opercis rendszer n-
velni tudja a tallatok szmt a gyorsttrakban.
Ezzel kapcsolatban azonban felvetdik egy problma. Tegyk fel, hogy az
temez tallkozik azzal az esettel, hogy egy processz prioritsa nagyobb,
mint a tbbi, m korbban egy msik processzoron futott. Ilyenkor vagy el-
vesztjk gyorsttrakban visszamarad informcik lehetsgt, vagy nem
hasznljuk ki az SMP-architektrbl add lehetsget, hogy a rr pro-
cesszoron futtassuk a processzt.
A Linux-SMP a dilemma feloldsra egy adaptv empirikus szablyt alkal-
maz. Ez egy olyan kompromisszum, amely fgg a processzorok gyorsttrnak
a mrettl. Ha a gyorsttr nagyobb, akkor a rendszer jobban ragaszkodik
ahhoz, hogy egy processz mindig ugyanazon a processzoron fusson.
2.3.7. Megszaktskezels
A Linuxban kt megszaktskezel-tpust klnbztetnk meg. A gyors"
megszaktskezel letiltja a megszaktsokat, ezrt gyorsra kell elkszte-
nnk. A lass" megszaktskezel nem tiltja le a megszaktsokat, mert az
ltala ignyelt hosszabb futsidre ez nem lenne j tlet.
Azrt, hogy a megszaktskezel rutinok gyorsan lefuthassanak, a Linux-
fejlesztk egy olyan megoldst alkalmaznak, amely a feladatot kt rszre v-
lasztja szt:
Fels rsz (Top hal f)
Ez a tnyleges megszaktskezel rutin. A feladata az, hogy az adato-
kat gyorsan letrolja az utlagos feldolgozshoz, majd bejegyezze a
msik fl futtatsra vonatkoz krelmt.
25
2. fejezet: Betekints a Linux-kernelbe
Als rsz (Bottom hal})
Ez a rsz tnylegesen mr nem a megszaktskezelben fut le, hanem
utna kicsivel. A komolyabb, idignyesebb szmtsokat itt vgezzk
el. Technikailag kt eszkz kzl vlaszthatunk az als rsz imple-
mentcija sorn: kisfeladat (Tasklet), munkasor (Work queue).
2.3.8. Valsidejsg
Jelenleg mr arnylag kevs eltrs van a norml s a vals idej kernel k-
ztt. gy nem kritikus helyeken a norml kernelt is nyugodtan vlaszthatjuk
a begyazott rendszereinkhez Nzzk meg, melyek azok az elemek, amelyek
mindezt lehetv teszik.
Mint lthattuk, a CFS-temez nanoszekundum felbonts, gy na-
gyon gyors reakcit tesz lehetv, s a taszkvlts is konstans idt
ignyel.
A kernelszlak a 2 .6-os kernelben megszakthatk, gy egy hosszabb
mvelet sem tudja lefogni a processzort.
A szinkronizlsokat optimalizltk a kernelben, hogy a lehet legke-
vsb akadlyozzk egymst a fut processzek.
A vals idej (RT) kernelt a norml kernelbl egy javtfolt- (patch) halmaz
segtsgvel llthatjuk el. A vals idej kernel az albbi tovbbi funkcikkal
rendelkezik:
Tartalmaz egy direkt hozzfrsi lehetsget a fizikai memrihoz.
Tartalmaz nhny memriakezelsbeli mdostst.
A gyenge pontok feldertsre pedig tartalmaz egy ksleltetsmonito-
roz eszkzt (Latency tracer).
2.3.9. Id s idztk
A kernel knyveli a processzek ltrehozsi idpontjt, s az letk sorn fel-
hasznlt CPU-idt. Ezeknek az idknek a mrtkegysge trtnelmileg a
jiffy (pillanat), amelynek norml mrtkegysgben rtelmezett rtke a ker-
nel belltstl fgg. A rendszer knyveli a processznek a kernel-, illetve fel-
hasznli zemmdban tlttt idejt.
Ezek mellett a knyvelsek mellett a Linux tmogatja az intervallumidzt-
ket is. A processz ezeket felhasznlhatja, hogy klnbz jelzseket kldessen
magnak, amikor lejrnak. Hromfle intervallumidztt klnbztetnk meg:
26
2.4. Memriakezels
Real
Az idzt vals idben dolgozik, s lejrtakor egy SIGALRM jelzst
kld.
Virtual
Az idzt csak akkor mkdik, amikor a processz fut, s lejrtakor
egy SIGVTALRM jelzst kld.
Profile
Az idzt egyrszt a processz futsi idejben mkdik, msrszt ak-
kor, amikor a rendszer a processzhez tartoz mveleteket hajt vgre.
Lejrtakor egy SIGPROF jelzst kld. Elssorban arra hasznljk,
hogy lemrjk, a processz mennyi idt tlt a felhasznli, illetve a
kernelzemmdban.
Egy vagy akr tbb idztt is hasznlhatunk egyszerre. Bellthatjuk ket
egy-egy jelzsre vagy ismtldre is. A Linux kezeli az sszes szksges in-
formcit a processz adatstruktrjban. Rendszerhvsokkal konfigurlhat-
juk, indthatjuk, lellthatjuk s olvashatjuk ket.
2.4. Memriakezels
A memria a CPU utn a msik legfontosabb erforrs, gy a memriakezel
alrendszer az opercis rendszerek egyik legfontosabb eleme.
2.4.1. A virtulismemria-kezels
A kezdetek ta gyakran felmerl a problma, hogy tbb memrira van szks-
gnk, mint amennyit a gpnk fizikailag tartalmaz. Ugyanakkor a rendelkez-
snkre ll a merevlemez, amely ugyan lassabban kezelhet, de nagy kapacitssal
rendelkezik. Ezrt j lenne, hogy amikor kifutunk a szabad memriaterletbl,
akkor a memria egyes, nem hasznlt rszeit tmenetileg a merevlemezre he-
lyezhetnnk, gy felszabadulhatna a szksges hely a programok szmra.
A virtulismemria-kezels az a mdszer, amely ezt biztostja szmunkra
a memria s a merevlemez felhasznlsval nagyobb memriaterlet elrst
teszi lehetv a processzeknek, mint amennyi szabad fizikai memria valjban
rendelkezsnkre ll. Mindezt radsul gy oldjuk meg, hogy a processz szmra
az egsz memriaterlet egysgesen kezelhet s tltsz legyen.
27
2. fejezet: Betekints a Linux-kernelbe
2.4.2. Lapozs
A virtulismemria-kezels megvalstsnak egyik, jelenleg legelterjedteb-
ben hasznlt mdszere a memrialapozs technikja. A rendszer memrijt
tartomnyokra, gynevezett lapokra (page) osztjuk. Ezeket a lapokat a ker-
nel egymstl fggetlenl mozgathatja a memria s a merevlemez kztt.
Termszetesen a lapok kezelse tbbletadminisztrcival jr. A rendszernek
nyilvn kell tartania, hogy az egyes lapok ppen hol helyezkednek el. Szksg
esetn a lapokat ki kell rnia a httrtrolra, vagy betltenie, s az egszet
le kell kpeznie a processz szmra hasznlhat formra.
De a lapozs a memriakorltok lekzdsnl tbbet is nyjt. A lapszer-
vezs memrit vdelmi clokra is felhasznlhatjuk. A rendszerben minden
processz sajt virtulismemria-terlettel rendelkezik. Ezek a cmtartomnyok
teljesen elklnlnek egymstl, gy az egyik fut folyamatnak nem lehet hat-
sa a msikra. Tovbb a hardver virtulismemria-kezel mechanizmusa le-
hetv teszi, hogy a lapokhoz vdelmi attribtumokat rendeljnk, gy
egyes memriaterleteket teljesen rsvdett tehessnk.
Nzzk meg, hogyan is mkdik a lapozs (paging) mdszere a gyakor-
latban. A 2.3 bra egy egyszerstett pldt mutat be, amelyben kt processz
virtulismemria-terlett kpezzk le a fizikai memrira. (A Linux ennl
bonyolultabb, tbblpcss lekpezst hasznl, errl ksbb lesz sz.)
A processz a mkdse sorn folyamatosan hasznlja a memrit. Ott ta-
llhat a kdja, amelyeket a processzor kiolvas s vgrehajt, de ott trolja az
adatait is. Ezek az adatok mind a memria egy-egy trolegysgben helyez-
kednek el, amelyekre cmekkel hivatkozhatunk. A virtulis memria haszn-
latakor ezek a cmek mind virtulis cmek a virtulis memriban. (Vagyis
minden processznek van egy sajt virtulis birodalma".)
Ezeket a virtulis cmeket a memriakezel egysg (Memory Manage-
ment Unit, MMU) alaktja fizikai cmekk. Az MMU a korszer rendszereknl
a processzor rsze. Az talaktst az opercis rendszer ltal karbantartott
informcis tblk alapjn vgzi el, amelyeknek neve laptbla.
Ennek a folyamatnak a megknnytsre a virtulis s a fizikai memria
egyenl mret (Intel x86-os architektra esetn 4 kB-os) lapokra tagoldik.
Minden lap rendelkezik egy sajt egyedi lapazonost szmmal (Page
Frame Number).
Pldnkban a virtulis cm kt rszbl tevdik ssze. Egy eltolsbl (off-
set) s egy lapazonost szmbl (Page Frame Number, PFN). Ha a lapok
mrete 4 kB, akkor az als 12 bit adja az eltolst, a felette lv bitek a lap
szmt.
Minden alkalommal, amikor a processzor egy virtulis cmet kap, sztv-
lasztja ezeket a rszeket, majd a virtulis lapazonostt megkeresi a laptblban,
s tkonvertlja a lap fizikai kezdcmre. Ezek utn az eltols segtsgvel
a laptbla alapjn mr megtallja a memriban a krdses fizikai cmet.
28
2.4. Memriakezels
Processz X Processz Y
VPFN 7 VPFN 7
Processz X Processz Y
Lap tbla Lap tbla
VPFN 6
VPFN laptb-
lval
-411
VPFN 5 VPFN 5
VPFN 4 PFN 4 VPFN 4
VPFN 3 PFN 3 VPFN 3
VPFN 2 PFN 2 VPFN 2
VPFN 1 PFN 1 VPFN 1
VPFN 0 PFN 0 VPFN 0
VIRTULIS FIZIKAI VIRTULIS
MEMRIA MEMRIA MEMRIA
2.3. bra. Avirtulis memria lekpezse fizikai memrira
A pldnkban (2.3. bra) kt processz van, s mindkt processz sajt laptb-
lval rendelkezik. Ezek a laptblk az adott processz virtulis lapjait a me-
mria fizikai lapjaira kpezik le.
Minden laptblabejegyzs az a
elt-
r
ttribtumokat tartalmazza:
Az adott tblabejegyzs rvnyes-e.
A fizikai lapazonost (PFN).
Hozzfrsi informci: az adott lap kezelsvel kapcsolatos inform-
cik, rhat-e, kd vagy adat.
2.4.3. A lapozs implementcija a Linuxon
A virtulis cm lekpezst fizikai cmm az MMU vgzi. Az MMU a procesz-
szor rsze, ebbl kvetkezen a cm lekpezse az egyes architektrkon elt-
r lehet.
Az x86-os architektra esetn a virtulis cmbl a fizikai cm ktszint
lekpezssel kaphat meg (lsd
me-
mrialapot.
Mint lthat, a virtulis cm ebben az esetben 3 rszre bonthat: lapknyv-
trindex, laptblaindex, eltols. A lapknyvtr (page directory) a laptblkra
mutat hivatkozsok tmbje. A lapknyvtrindex ebbl a tmbbl vlaszt
ki egy laptblt. A laptbla tartalmazza a hivatkozsokat a fizikai memria
egyes lapjaira. A laptblaindex ebbl meghatroz egy elemet, vagyis egy me-
mrialapot. A fizikai cm ennek a lapnak a cmbl s az eltols sszegbl
szmthat. A virtulis cm ilyen mdon kpezhet le fizikai cmm.
29
2. fejezet: Betekints a Linux-kernelbe
Virtulis cm Fizikai memria
Lapknyvtr index Laptblaindex
Eltols
(offset)
Lapknyvtr Laptbla
2.4. bra. Ktszint lekpezs (x86 32bit)
Egyes 64 bites architektrkon, mint pldul az Alpha, egy ilyen felosztsban a
lapknyvtr s laptblatmbk nagyon nagy mretek lennnek, ezrt a rend-
szertervezk bevezettk a hromszint lekpezst. Ezt a 2.5. brn lthatjuk.
Virtulis cm Fizikai memria
Lapknyvtr-
index
Kzp-
lapknyvtrindex
Laptblaindex offset
Lapknyvtr Kzps Laptbla
lapknyvtr
2.5. bra. Hromszint lekpezs (Alpha)
30
2.4. Memriakezels
Ahogy az brbl is lthat, a lekpezs alapelve megegyezik az elzekben
trgyalt ktszint lekpezssel, csak kiegszl egy tovbbi szinttel. A lap-
knyvtr s a laptbla kz beiktattunk egy kzps lapknyvtrat (page
middle directory), tovbb a virtulis cm is ngy rszre tagoldik. A lap-
knyvtrbejegyzsek gy a kzps lapknyvtrakra hivatkoznak, amelynek
a bejegyzsei laptblkra mutatnak. A fizikai cm, hasonlan az elzhz, a
laptbla ltal tartalmazott lapcmbl s az eltols sszegbl addik.
A Linux-kernel fejleszti termszetesen egysgesre szerettk volna elk-
szteni az MMU-k kezelst, fggetlenl az architektrk klnbsgeitl.
Ezrt a Linux-kernel a hromszint lekpezst alkalmazta. Ahhoz azonban,
hogy ez az x86-os architektrkon is mkdjn, egy kis trkkhz kellett fo-
lyamodni: az x86-os rendszerek esetn a kzps lapknyvtr csak egy elemet
tartalmaz, gy a hromszint lekpezs ktszintv egyszersdik.
Ezt kvettk az ia64 -es rendszerek, ahol mr a ngyszint lekpezst
tmogatja a hardver. Eleinte a kernelfejlesztk trkkkkel a hromszint le-
kpezst alkalmaztk ezeken a rendszereken is, m ezzel mestersgesen kor-
ltoztk a folyamatok maximlis virtulis cmtert 512 GB-ra. A kernel miatt
korltozni a hardver kpessgt nem tnt clszernek, ezrt ksbb talak-
tottk a lekpezalgoritmust ngyszintre. gy a virtulis cm felptse az
ia64 -es rendszerek esetben a 2.6. bra szerint alakul.
PGD PUD PMD PTE
Eltols
PGD Lapknyvtr (Page Global Directory)
PUD Fels lapknyvtr (Page Upper Directory)
PMD Kzps lapknyvt
al gorit-
musban
Directory)
PTE Laptbla (Page Table)
2.6. bra. A virtulis cm felptse ia64-es rendszerek esetn
gy a jelenlegi kernel a platformfggetlen virtulismemria-kezel algorit-
musban a ngyszint lekpezst hasznlja, amelyet az egyszerbb architek-
trk esetben illeszt az adott rendszerhez.
2.4.4. Igny szerinti lapozs
A vals lettel ellenttben a lustasg a szmtgpek vilgban sokszor igen
elnys tulajdonsg. Ugyanis ha csak akkor vgez el egyes mveleteket a gp,
amikor tnyleg szksges, akkor ezzel rendszeridt takartunk meg a tbbi
feladat szmra, gy a rendszernk teljestmnye nvekszik.
31
2 . fejezet: Betekints a Linux-kernelbe
Ez az elmlet, tltetve a memriakezels vilgba, jelentheti azt, hogy
csak akkor tlti be a rendszer a lapot a httrtrolrl, amikor egy processz
hivatkozik r, ignyli az informcit. Pldul egy adatbzis-kezel program-
nl elg, ha csak azokat az adatokat tartja a memriban, amelyekre ppen
szksg van. Ezt a technikt igny szerinti lapozsnak (demand paging)
nevezzk.
Amikor egy processz olyan laphoz prbl hozzfrni, amelyik ppen nem
tallhat meg a memriban, az MMU egy laphibt (page fault) generl,
amellyel rtesti az opercis rendszert a problmrl
17
Ha a hivatkozott virtulis cm nem rvnyes, az azt jelenti, hogy a pro-
cessz olyan cmre hivatkozott, amelyre nem lett volna szabad. Ilyenkor az
opercis rendszer a tbbi vdelmben megsznteti a processzt.
Ha a hivatkozott virtulis cm rvnyes, de a lap nem tallhat ppen a
memriban, az opercis rendszernek be kell hoznia a hivatkozott lapot
a httrtrolrl. Termszetesen ez a folyamat eltart egy ideig, ezrt a pro-
cesszor addig egy msik processzt futtat tovbb. A beolvasott lap kzben be-
rdik a merevlemezrl a fizikai memriba, s bekerl a megfelel bejegyzs
a laptblba. Ezek utn a processz a meglls helytl fut tovbb. Ilyenkor
termszetesen a processzor mr el tudja vgezni a lekpezst, gy folytatdhat
a feldolgozs.
A Linux az igny szerinti lapozs mdszert hasznlja a processzek kd-
jnak a betltsnl is. Amikor a programot lefuttatjuk, akkor a rendszer
nem tlti be a teljes kdot a fizikai memriba, csak az elejt, mg a marad-
kot csak lekpezi a folyamat virtulismemria-terletre. Ahogy a kd fut, s
laphibkat okoz, a Linux gy hozza be a kd tbbi rszt is. Ez ltalban sz-
szessgben is gyorsabb, mint betlteni a teljes programot, mert a nagyobb
programok esetben gyakran csak egy rsze fut le a kdnak.
2.4.5. Lapcsere
Amikor a processznek jabb virtulis lapok behozsra van szksge, s nincs
szabad hely a fizikai memriban, az opercis rendszernek helyet kell terem-
tenie. Ezt gy teszi meg, hogy egyes lapokat eltvolt a fizikai memribl.
Ha az eltvoltand lap kdot vagy olyan adatrszeket tartalmaz, ame-
lyek nem mdosultak, akkor nem szksges a lapot lementeni. Ilyenkor ez
egyszeren eldobhat, s legkzelebb, amikor szksg lesz r, megtallhat a
httrtroln.
Ha azonban a lap mdosult, akkor az opercis rendszernek el kell trol-
nia a tartalmt, hogy ksbb elhozhassa. Ezeket a lapokat nevezzk pisz-
kos lapnak (dirty page), s az llomnyt, ahova az MMU az eltvoltskor
17
Az illeglis memria-hozzfrsek (pl. csak olvashat lapra rs) szintn laphibt ered-
mnyeznek (ezt lsd ksbb).
32
2 .4 . Memriakezels
elmenti ket, lapcserellomnynak (swap file).
18
A hozzfrs a lapcse-
reeszkzhz nagyon hossz ideig tart a rendszer sebessghez kpest, ezrt
az opercis rendszernek az optimalizci rdekben mrlegelnie kell.
Ha a lapcsere-algoritmus nem elg hatkony, elfordulhat, hogy egyes la-
pok folyamatosan cserldnek, s ezzel pazaroljk a rendszer idejt. Hogy ezt
elkerljk, az algoritmusnak lehetleg a fizikai memriban kell tartania
azokat a lapokat, amelyeken a processzek ppen dolgoznak, vagy ksbb dol-
gozni fognak. Ezeket a lapokat hvjuk munkahalmaznak (working set).
Ugyanakkor az algoritmusnak elg egyszernek kell lennie, hogy ne ignyel-
jen tl sok rendszeridt a vlaszts.
A kernel dntshoz munkjt tmogat algoritmusok sokszor bele van-
nak ptve a processzorokba. A kernel ezek kzl ugyanakkor csak azokat az
algoritmusokat hasznlhatja fel, amelyeket minden processzor ismer, a tbbit
szoftverben kell implementlnia.
A Linux az gynevezett Least Recently Used (LRU, legrgebben hasz-
nlt") lapozsi technikt alkalmazza a lapok kivlasztsra. Ebben a sm-
ban a rendszer nyilvntart egy lapok kztti sorrendet az alapjn, hogy mikor
frtek hozz utoljra az adott laphoz. Minl rgebben frtek hozz egy laphoz,
annl inkbb sor kerl r a kvetkez lapcseremveletnl.
A laphozzfrsi sorrendet egy lncolt listban lehetne kezelni. Ha hozzf-
rnk egy laphoz, akkor a hivatkozst a lncolt lista elejre tesszk. Ezltal
a hivatkozsnak a listban elfoglalt helye megmutatja, hogy milyen sorrend-
ben frtnk hozz a lapokhoz. Ha azonban minden laphozzfrs esetn fris-
stennk a lncolt listt, akkor ez hasznlhatatlan mrtkben lasstan a
memria-hozzfrs sebessgt.
19
Ezrt az elbb emltett egyszer metdussal szemben a Linux egy mdos-
tott durva lptk LRU-technikt hasznl. Ez a megolds alapveten kt m-
veleten alapul. Amikor egy folyamat hozzfr egy laphoz, akkor ezt egy jelzbit
belltsval jelzi a rendszer. Ezt a mveletet minden jelenlegi architektra
hardveresen tmogatja, gy gyorsan mkdik. Msrszt elg egyszer ahhoz,
hogy szksg esetn szoftveresen is megvalsthat legyen.
A msik mvelet kt lncolt lista nyilvntartsa. Az egyik lista az aktv
lapokat, a msik az inaktv lapokat tartja nyilvn. A lapok mindkt irnyban
vndorolnak a kt lista kztt. A vlts alapja a hozzfrsi bit llapota.
A kernel bizonyos idkznknt megvizsglja az elbb emltett hozzfrst
jelz bit llapott. Ha a lap idig az inaktv listban szerepelt, akkor tkerl
az aktv lista elejre. Ha idig aktv volt, s a legutbbi vizsglat ta nem fr-
tek hozz, akkor az inaktv lista elejre kerl. Ha ezek utn a legrgebben
18
A lapcserellomny nem felttlen fjl, lehet partci vagy akr kln merevlemez is.
Ezrt clszerbb egysgesen eszkznek nevezni. A Linux tbb lapcsereeszkzt is tud
hasznlni egyszerre. Ezeket priorits szerint rendezi. Amg meg nem telik, a legnagyobb
priorits eszkzt hasznlja, majd a kvetkezvel folytatja.
19
A megolds a gyakorlatban azrt sem implementlhat, mert a kernelnek rtestst kel-
lene kapnia minden memrialap-hozzfrsrl. Ez a hardver tmogatsa nlkl nem old-
hat meg.
33
2. fejezet: Betekints a Linux-kernelbe
hasznlt lapra vagyunk kvncsiak, akkor az inaktv lista vgn talljuk meg.
Nem biztos, hogy az inaktv lista vgn a sorrend teljesen korrekt az utols
hozzfrs idpontja szerint, de nincs is szksgnk abszolt pontos eredmny-
re. Mindegyik ott tallhat laphoz rgen frtek hozz. Ez a kis pontatlansg
nem zavar, hiszen ennek kvetkeztben az algoritmusunk nagysgrendekkel
gyorsabb, mint a korbban trgyalt pontos algoritmus.
2.4.6. Megosztott virtulis memria
A virtulismemria-kezels lehetv teszi tbb processznek, hogy egy kzs
memriaterleten osztozzanak. Ehhez csak arra van szksg, hogy bejegyez-
znk a processzek laptbliba egy kzs fizikai lapra val hivatkozst, gy
kpezve le ezt a lapot a virtulis cmterletre. Termszetesen ugyanazt a la-
pot a kt virtulis cmtartomnyban kt klnbz helyre is lekpezhetjk.
Ez a megosztott memriakezels lehetsget ad a folyamatoknak, hogy a
kzs memriaterleten adatokat cserljenek. Ugyanakkor a megfelel m-
kds rdekben szinkronizlsi mdszereket is hasznlni kell.
A Linux a szlkezelst is a megosztott virtulis memria segtsgvel imp-
lementlja. (Errl mr volt sz a 2.3.4. alfejezetben.) Ilyenkor a processzek k-
zs memrin osztoznak, s mint szlakat hasznlhatjuk ket.
2.4.7. Msols rskor (COW technika)
A Linux a megosztott memrit nemcsak adattvitelre, illetve a szlak imp-
lementcijnl hasznlja, hanem a folyamatok msolsnak gyorstsra is
(fork). Elmletileg egy j folyamat ltrehozsakor a szlfolyamat cmtere
lemsoldik, s ez alkotja a gyerek cmtert. A valsgban nem ez trtnik,
mert ez nagyon lass s nagy memriaigny folyamat lenne. Helyette a Li-
nux a msols rskor (copy on write, COW) technikjt hasznlja.
Amikor a gyerekfolyamathoz le kellene msolni a szlfolyamat memria-
tartalmt, valjban a rendszer csak a virtulismemria-lekpezshez hasznlt
laptblkat msolja le. gy a gyerekfolyamat cmterbe ugyanazok a fizikai la-
pok kpzdnek le, mint amelyeket a szl hasznl. m a folyamatok elkln-
tse rdekben a lapok csak olvashatk lesznek mindkt folyamat szmra.
Ha valamelyik folyamat rni prblja a lapot, ez egy hozzfrsi hibt okoz.
A hiba lekezelrutinja tudja a hiba okt, ezrt a lapot lemsolja, s lecserli a
virtulis memriban. Ettl kezdve mindkt folyamat ismt tudja rni a lapot,
illetve a msolatt.
34
2.4. Memriakezels
2.4.8. A hozzfrs vezrlse
A laptblabejegyzsek az eddig trgyaltak mellett hozzfrsi informcikat
is tartalmaznak Amikor az MMU egy bejegyzs alapjn a virtulis cmeket
fizikai cmekk alaktja t, prhuzamosan ellenrzi azokat a hozzfrsi in-
formcikat is, hogy az adott processz szmra a mvelet engedlyezett-e,
vagy sem.
Tbb oka is lehet, amirt korltozzuk a hozzfrst egyes memriaterletek-
hez. Egyes terletek (pldul a programkd trolsra szolgl memriarsz)
csak olvashat lehet, ezrt az opercis rendszernek meg kell akadlyoznia, hogy
a processz adatokat rhasson a kdjba. Ezzel szemben azoknak a lapoknak,
amelyek adatokat tartalmaznak, rhatnak kell lennik, de futtatni nem sza-
bad a memria tartalmt. Meg kell akadlyoznunk tovbb, hogy a processzek
hozzfrhessenek a kernel adataihoz, a biztonsg rdekben ezeket csak rend-
szerhvsokon keresztl rhetik el.
A Linux az albbi jogokat tartja nyilvn egy lappal kapcsolatban (ezeket
kpezi le az adott architektrn rvnyes jogokra):
a lap bent van-e a fizikai memriban;
olvashat-e;
rhat-e;
futtathat-e;
a lap a kernel cmterhez vagy a felhasznl cmterhez tartozik-e;
a lapot mdostottk-e (dirty), gy ki kell-e majd rni a lapcserello-
mnyba;
a laphoz hozzfrtek-e;
tovbbi, a gyorsttrakkal kapcsolatos belltsok.
2.4.9. A lapkezels gyorstsa
Ha egy virtulis cmet megprblunk lekpezni fizikai cmm, akkor lthat,
hogy ez tbb memria-hozzfrst is ignyel, mire vgigjutunk az sszes szin-
ten. Jllehet idig azt mondtuk, hogy a memria olvassa arnylag gyors m-
velet, valjban elmarad a CPU sebessge mgtt. gy a laplekpezs mveletei
visszafoghatjk a rendszer teljestmnyt. Hogy ezt megakadlyozzk, a
rendszermrnkk gyorsttrakat integrltak az MMU-ba. Ezek neve:
Translation Look-aside Buffer (TLB, flretekint fordtsbuffer": a flre-
tekints" az alternatv keressi mdra utal).
35
2. fejezet: Betekints a Linux-kernelbe
A TLB trolja a legutbbi laplekpezsek eredmnyt. Amikor egy virtu-
lis cmet kell lefordtania az MMU-nak, akkor elszr egyez TLB-bejegyzst
keres. Ha tall, akkor a segtsgvel azonnal lefordthatja a fizikai cmre, s
ezzel jelents gyorsulst rhet el.
A Linuxnak a TLB kezelsvel kapcsolatosan nincs sok teendje. Egyet-
len feladata, hogy rtestse az MMU-t, ha valamelyik trolt lekpezs mr
nem rvnyes.
2.5. A virtulis llomnyrendszer
Ebben a fejezetben bemutatjuk az Unix-vilg egyik legfontosabb absztrakci-
jt, az llomnyabsztrakcis felletet. Ennek a felletnek a programozst
a 4. llomny-s I/O kezels fejezetben, az llomnykezelsnl mutatjuk be,
a fellet megvalstst pedig a 7. Fejleszts a Linux-kernelben fejezetben
rszletezzk.
2.5.1. Az llomnyabsztrakci
Az els Unix rendszer egyik jtst, amely mg ma is thatja az sszes oper-
cis rendszert, a hagyomny a kvetkezkppen foglalja ssze minden llo-
mny (everything is a file"). Ez a taln kiss leegyszerstett megfogalmazs
azt takarja, hogy a klnbz 1/O perifrik sok tekintetben gy hasznlhatk,
mint az llomnyok. Ha egy folyamat hasznlni szeretn ket, jeleznie kell ezt
a szndkt a kernelnek, amely egy llomnylert ad vissza. Ezek utn mind
az llomnyokat, mind a perifrikat rjuk, olvassuk, majd bezrjuk.
Az implementci szintjn ez gy jelenik meg, hogy az llomnyok meg-
nyitsakor egy llomnylert kapunk vissza, s ugyanazokkal a fggvnyek-
kel rhatjuk, illetve olvashatjuk az llomnyokat.
Ez az tlet nagyon knyelmess tette a perifrik s az llomnyok kztti
tjrhatsgot. A billentyzet is egy llomny, amelyrl csak olvashatunk, a
terminl kimenete egy olyan llomny, amelyet csak rhatunk. Ezrt egy prog-
ram kimenete lehet egy llomny vagy egy terminl, ez mindssze a megnyitott
llomnylertl fgg. St kt program kztti kommunikcit megvalst cs-
vezetk hasznlata is egy llomnylerval vgzett rs s olvass.
Termszetesen rgtn felmerl az a problma, hogy az rson s az olvas-
son kvl szmos mvelet van (pldul pozicionls), amelyre szmos eszkz
(pldul a billentyzet) nem alkalmas. St mr az elz bekezdsben felfigyel-
hettnk arra, hogy a billentyzetet reprezentl lert csak olvashatjuk, mg
a terminl lerjt csak rhatjuk.
36
2.5. A virtulis llomnyrendszer
Ez egyltaln nem zavar, hiszen br vannak klnbsgek, mi a hasonl-
sgokat szeretnnk kiaknzni. Egy bemeneti llomny, amelybl csak olva-
sunk, lecserlhet a billentyzetre anlkl, hogy egyetlen olvasst vgz
fggvnyt lecserlnnk a programunkban.
A tovbbiakban az llomny s a fjl szavakat a Linux filozfijval ssz-
hangban absztrakt rtelemben hasznljuk mind llomnyrendszerbeli llo-
mnyok, mind 1/0 eszkzk lehetnek a ler mgtt.
Az llomnyabsztrakcis fellet az sszes llomny- s I/O mvelet uni-
ja, sszessge. Ez az albbi mveleteket jelenti:
Olvass (read): byte-ok olvassa egy adott mret bufferba.
rs (write): egy adott mret buffer kirsa.
Pozicionls (llseek): az aktulis pozci mdostsa.
Aszinkron olvass s rs (aio_read, aio_write): POSIX aszinkron I/O
mveletek.
Knyvtr tartalmnak olvassa (readdir): ha az llomny knyvtr,
akkor a tartalmt adja vissza.
Vrakozs llomnymveletre (poll): ha az olvassi vagy rsi mve-
let ppen nem hajthat vgre, akkor tudunk vrakozni a felttel telje-
slsre.
I/O vezrls (ioctl): specilis mveletek, belltsok az llomnyra.
Lekpezs a memriba (mmap): az llomnyt vagy annak egy rszt
lekpezhetjk a virtulis memriba, gy memriamveletekkel rhat-
juk s olvashatjuk. Ha az llomny eszkz, akkor a segtsgvel lehe-
tsg van megosztott memria kialaktsra az alkalmazs s az
eszkzmeghajt kztt.
Megnyits (open): az llomny megnyitsa. A kernel a megnyits
alapjn tudja, hogy az llomny hasznlatban van.
Lezrs (close): az llomny lezrsa.
Szinkronizls (sync, fsync, fflush, aio_fsync ): ha bufferelt rst al-
kalmazunk, akkor a buffer tartalmt azonnal kirja.
llomnyzrols (flock): ha tbb folyamat hasznln az llomnyt,
akkor a zrolsokkal szinkronizlhatjuk a hozzfrst.
Ismt hangslyozzuk, hogy ritka az az eszkz vagy llomny-rendszerbeli l-
lomny, amely az sszes mveletet kpes lenne megvalstani. Ha egy ker-
nelobjektum megvalstja az llomnyabsztrakcis interfszt, akkor legalbb
egy mveletet tmogat a fentiek kzl. Egy lerra meghvhatjuk a fenti
fggvnyek brmelyikt. Ha a mvelet nem lenne tmogatva, akkor hibaze-
nettel trne vissza, amelyet a programunkban lekezelhetnk.
37
2. fejezet: Betekints a Linux-kernelbe
sszefoglalva az eddigieket: az llomnylerk akkor cserlhetk fel, ha
csak a mindegyikk ltal tmogatott mveleteket hasznljuk. Vagyis az
llomnyabsztrakcis fellet az mveletek unija, a mveletek metszete
mentn pedig ugyanazokkal a fggvnyekkel hasznlhatunk tbb klnbz
llomnytpust.
Ezek utn vegyk sorra az llomnytpusokat. Ezek az albbiak:
egyszer llomnyok (regular files),
specilis llomnyok (special files).
Az egyszer llomnyok a hagyomnyos, llomny-rendszerbeli llomnyokat
jelentik. Egy llomny-rendszerbeli llomny mveletei fggenek az llo-
mny tpustl. Az Ext3-as llomnyrendszer egyszer llomnyai az albbi
mveleteket tmogatjk:
megnyits, lezrs;
olvass, rs;
aszinkron olvass, rs;
pozicionls;
I/O kontroll;
memriba val lekpezs;
szinkronizls.
A specilis llomnyok olyan nem hagyomnyos llomnyok, amelyek megva-
lstjk az llomnyabsztrakcis fellet legalbb egy mvelett.
2.5.2. Specilis llomnyok
A Linux szmos olyan llomnytpust is hasznl, amely a hagyomnyos rtelem-
ben vve nem llomny, m implementlja az llomnyabsztrakcis interfszt.
2.5.2.1. Eszkzllomnyok
Az eszkzkhz val hozzfrs eszkzllomnyokon (device file) keresztl
trtnik. Az eszkzllomnyoknak kt tpusa van: blokkos eszkzllomny
(block device file) s karakteres eszkzllomny (character device file).
A karakteres eszkzllomnyok az ltalnosabban hasznlt eszkzinter-
fszek. Az llomnyabsztrakcis interfsznek akr minden fggvnyt tmo-
gathatjk attl fggen, hogy az eszkzre rtelmezhetk-e.
A blokkos eszkzllomnyok specilisabbak, s csak az albbi mvelete-
ket tmogatjk:
38
2.5. Avirtulis llomnyrendszer
megnyits, bezrs;
olvass, rs;
aszinkron olvass, rs;
pozicionls;
I/O vezrls;
memriba val lekpezs;
szinkronizls.
Jllehet a karakteres s a blokkos eszkzket megadhatjuk a fenti mdon a
rajtuk rtelmezett mveletekkel, a mkdsk alapjn rthetjk meg ket
igazn. Az llomnyabsztrakcis fellet tulajdonkppen fggvnypointerek
halmaza: sszerendeli a mveleteket azok megvalstsval. A mveleteket
gynevezett eszkzvezrlk (device drivers) valstjk meg. Ha pldul meg-
hvjuk az open rendszerhvst, akkor ez a kernelben gy van implementlva,
hogy megkeresi az adott llomnylerhoz tartoz eszkzvezrl fggvnymuta-
t listjt, s kivlasztja az openhez tartoz bejegyzst. Ha az open mveletet
nem valstja meg az adott eszkzvezrl, akkor ez a mutat nulla. Ebben az
esetben a kernel az open rendszerhvs visszatrsi rtkben jelzi a hibt. Ha
az eszkzvezrl megvalstja a megnyitsi mveletet, akkor a vizsglt mutat
egy kezelfggvnyre mutat, amelyet a rendszerhvs implementcija meghv.
Az eszkzvezrlk a kernel rszt alkotjk. Gyakran gynevezett kernelmodul-
ban implementljuk ket (lsd a 7.3. Kernelmodulok cm alfejezetet).
A karakteres eszkzvezrlk, amint nevk is mutatja, byte-onknti rst-
olvasst tesznek lehetv. A karakteres eszkzk egyszeren megadjk a t-
mogatott mveletekre mutat fggvnymutatkat, a kernel pedig kzvetlenl
meghvja ket.
A blokkos eszkzvezrlk felptse specilisabb, mivel olyan eszkzkhz
kszltek, amelyeknl nem frhetnk hozz egy-egy byte-hoz kzvetlenl,
hanem csak byte-ok csoportjt, blokkokat tudunk kezelni. Erre j plda a me-
revlemez, amelyhez ha byte-onknt frnnk hozz, akkor ez drasztikusan le-
lasstan a rendszert. Az eszkzvezrl felptse sokkal bonyolultabb, mert
kztes gyorsttrakat kell alkalmaznia a blokkok trolsra, illetve aszink-
ron mechanizmusokat a blokkok mozgatsra. Az llomnyabsztrakcis inter-
fszt sem kzvetlenl valstjk meg: ezt a kernel valstja meg helyettk, s
egy mveletsort hoz ltre szmukra, amelyben felsorakoztatja a krseket.
Ekzben a kernel szmos optimalizcit is elvgez. A blokkos eszkzvezrlk
tetszleges sorrendben szolglhatjk ki a mveletsorban tallhat mveleteket.
Jllehet vannak eszkzk, amelyek se nem blokkosak, se nem karaktere-
sek (pldul a hlzati krtya), az eszkzvezrlk nagy tbbsge jl megval-
sthat valamelyik eszkzvezrl-tpussal.
39
2. fejezet: Betekints a Linux-kernelbe
2.5.2.2. Knyvtr
A knyvtr olyan specilis llomny, amely a benne lv llomnyok listjt
tartalmazza. A rgi Unix rendszerekben az implementcik megengedtk,
hogy a programok az egyszer llomnyok kezelsre szolgl fggvnyekkel
hozz is frjenek a knyvtrllomnyokhoz. A knnyebb kezelhetsgrt
azonban egy specilis rendszerhvskszlet kerlt az jabb rendszerekbe.
(Ezeket lsd a 4.4. Knyvtrmveletek alfejezetben.)
2.5.2.3. Szimbolikus hivatkozs
A szimbolikus hivatkozs (symbolic link, symlink, soft link) olyan specilis
llomny, amely egy msik llomny elrsi informciit tartalmazza. Ami-
kor megnyitjuk, a rendszer rzkeli, hogy szimbolikus hivatkozs, kiolvassa
az rtkt, s megnyitja a hivatkozott llomnyt. Ezt a mveletet a szimboli-
kus hivatkozs kvetsnek hvjuk. A rendszerhvsok alaprtelmezett eset-
ben kvetik a szimbolikus hivatkozsokat.
2.5.2.4. Csvezetk
A csvezetk (pipe) a Unix-vilg legegyszerbb IPC-mechanizmusa. Mint a
neve is elrulja, egy virtulis csvezetket kpez memriban, amelynek v-
geire egy-egy llomnylerval hivatkozhatunk. ltalban az egyik processz
informcikat r bele az egyik oldaln, mg egy msik processz a msik vgn
a bersi sorrendben kiolvassa az adatokat. Mivel a kt processz prhuzamo-
san kezeli, ezrt kis memriaterletre van szksg kztes trolknt.
A parancsrtelmez a csvezetkeket a processzek kztti I/O tirnyts-
ra, mg sok ms program az alprocesszeikkel val kommunikcira hasznlja.
Kt tpust klnbztetjk meg: nvtelen (unnamed) s megnevezett
(named) csvezetkeket. A nvtelen csvezetkek akkor jnnek ltre, amikor
szksg van rjuk, s amikor mindkt oldal lezrja, akkor eltnnek. Azrt
nvtelenek, mert nem ltszdnak a fjlrendszerben, nincsen nevk. A megne-
vezett csvezetkek ezzel szemben fjlnvvel jelennek meg a fjlrendszerben,
s a processzek ezzel a nvvel frhetnek hozzjuk. A csvezetkeket FIFO-
nak is nevezik, mivel az adatok FIFO- (first in, first out, elsknt berakott
elem vehet ki elszr) rendszerben kzlekednek rajta.
Hangslyozand, hogy az llomnyabsztrakcis fellet hasznlata nem
felttlenl jelenti azt, hogy az llomny megjelenik az llomnyrendszerben.
Erre j pldt nyjtanak a nvtelen csvezetkek s a socketek.
40
2 .5. A virtulis llomnyrendszer
2.5.2.5. Socket
A socketek hasonltanak a csvezetkekre. IPC-csatornaknt hasznlhatk a
folyamatok kztt, m flexibilisebbek, mint a csvezetkek. Ktirnyak, s
lehetv teszik a kommunikcit kt, klnbz gpen fut processz kztt is.
Vagyis ezekkel valsthatjuk meg a hlzati kommunikcit (lsd a ksbbi
fejezetekben).
A socketek llomnyknt kezelhetk, mint a tbbi specilis llomny is,
m a rendszer tartalmaz olyan fggvnyeket is, amelyek specilisan a socke-
tekhez kszltek.
Az llomnyrendszerben tallkozhatunk gynevezett socketllomnyokkal.
Ez a Unix Domain Socket protokoll (lsd a 6.4. Unix domain socket alfejezet-
ben) cmzsi mechanizmusnak a rsze, s kt folyamat kztti socketkapcsolat
felptsben lt el feladatot. Kzvetlenl az llomnyt nem hasznljuk, csak
meghatrozott rendszerhvsok paramtereknt.
A socketllomny csak a Unix Domain Socket protokoll esetn tlt be sze-
repet. Ms protokolloknl a socketmechanizmus nem hasznlja az llomny-
rendszert.
2.5.3. Az inode
Az llomny egyetlen egyedi azonostja az inode (information node, infor-
mcis csompont). Kulcsszerepet tlt be a kernel llomnykezelsben.
Az llomny inode-ja tartalmaz szinte minden informcit az llomnyrl, be-
lertve a jogokat, a mrett, a hivatkozsok szmt. Ez all kt informci
kpez kivtelt:
az llomny neve,
az llomny adattartalma, mivel az inode csak a mutatt tartalmazza
az llomnyhoz tartoz adatblokkokra, magt az adatot nem.
2 0
Az llomnyok neve a knyvtrakban van eltrolva. A knyvtrllomny nv
s inode-szm sszerendelseket tartalmaz. Vagyis amikor egy llomny tar-
talmt meg akarjuk nzni, akkor megadjuk a nevt. A kernel a knyvtrl-
lomnyban megkeresi a nvhez rendelt inode-ot. Az inode-ban tallt mutat
alapjn pedig elrkeznk a tnyleges adathoz. Ezt a lekpezst a 2.7. bra je-
lenti meg.
2 0
A Linux-kernel 3.2 -es verzijtl az ext4 -es llomnyrendszer tartalmazza az gyneve-
zett inline data funkcit, amely lehetv teszi, hogy nagyon kis adatmennyisg esetn az
inode szabad terletn troldjon az llomny tartalma. Ez sok kis llomny esetben
szmottev trhely-megtakartst eredmnyez.
41
2. fejezet: Betekints a Linux-kernelbe
Knyvtr
Knyvtri
fjli inode1
fj l2 inode2
inode inode1
Jogosultsg
Tulajdonos
Csoport
Adatindex
inode
inode2
Jogosultsg
Tulajdonos
Csoport
Adatindex
2.7. bra. llomnynvtl az adatig
Lehetsgnk van arra is, hogy ugyanarra az inode-ra ms nvvel is hivat-
kozzunk, akr msik knyvtrbl. Ezt nevezzk merev hivatkozsnak
(kard link) (lsd a 2.8. brt).
Knyvtr
Knyvtri
fjlt inode1
fjl2 inode2
Knyvtr
Knyvtrt
113 inode1
inode
inode1
Jogosultsg
Tulajdonos
Csoport
Adatindex
2.8. bra. Merev hivatkozs
Az inode-szmnak azonban csak egy llomnyrendszeren bell van rtelme.
Ezrt merev hivatkozst csak egy partcin bell hozhatunk ltre. Partcik
kztt csak a korban emltett szimbolikus hivatkozs hasznlhat (lsd a
2.9. brt).
42
22.52. A virtulis llomnyrendszer
Knyvtr
Knyvtrt
fj 11
fjl2 inode2
Knyvt inode1
yvtrt
fil3 inode3
inode
inodei
Jogosultsg
Tulajdonos
Csoport
Adatindex
inode
inode2
Jogosultsg
Tulajdonos
Csoport
Link nv
2.9. bra. Szimbolikus hivatkozs
Az inode tartalmazza a r hivatkoz llomnynevek, vagyis a merev hivatko-
zsok szmt. Ezt hvjuk link countnak (a kapcsolatok szma) Amikor egy
llomnyt trlnk, akkor valjban egy merev hivatkozst trlnk, s ez a
szm cskken eggyel. Ha elri a 0 rtket, s egyetlen folyamat sem tartja
ppen nyitva az llomnyt, akkor tnylegesen trldik, s a hely felszabadul.
Viszont ha legalbb egy folyamat nyitva tartja, csak akkor trtnik meg a
trolhely felszabadtsa, miutn mindenki bezrta.
2 1
Az inode trolsnak mdja s tartalma a hasznlt llomnyrendszer
fggvnye. Jelentsen eltrhet a klnbz llomnyrendszer-tpusoknl. m
ennek lekezelst nem hrthatjuk az alkalmazsokra. Ezrt a kernel a me-
mriban csak egyfle reprezentcit hasznl, amelyet in-core inode-nak
e tall-
koznak.
a almazsok minden e tall-
koznak.
a reprezentcival tall-
koznak. A merevlemezen trolt inode-okat on-disk inode-nak nevezzk.
Amikor egy processz megnyitja az llomnyt, az on-disk inode betltdik, s a
kernelben tallhat llomnyrendszer-kezel rutinok automatikusan in-core
inode-d alaktjk. A lekpezst visszafel is elvgzik, amikor az in-core inode
mdosul. A megfeleltethet rtkeket visszakonvertljk, s lementik az on-
disk inode-ba.
Az on-disk s az in-core inode nem teljesen ugyanazt az informcit tartal-
mazza. Pldul csak az in-core inode knyveli az adott llomnyhoz kapcsold
folyamatok szmt. Nhny llomnytpus, pldul a nvtelen csvezetk, nem
rendelkezik on-disk inode-dal, csak a memriban ltezik.
2 1
Ilyenkor nem trldik tnylegesen az llomny tartalma, csak specilis esetekben. Val-
jban csak jra felhasznlhatnak lesznek nyilvntva afjl3 kok.
4 3
22. fejezet: Betekints a Linux-kernelbe
2.5.4. Az llomnylerk
Az alkalmazsok szmra az llomnyt tbbnyire az llomnyler reprezen-
tlja Amikor egy llomnyt megnyitunk, akkor a kernel visszaad egy kis
egsz szmot (int), amely a tovbbiakban az llomnnyal kapcsolatos mvele-
tek sorn hivatkozsknt szolgl az llomnyra.
Az llomnyler csak a folyamaton bell van rtelmezve. Ha ugyanazt az
llomnyt egy msik folyamatban is megnyitjuk, akkor lehet, hogy msik l-
lomnylert kapunk. Az llomnylerk konkrt szmrtke valjban az l-
lomnyok megnyitsnak sorrendjtl fgg. A kernel 0-tl kezdden kezdi
kiosztani a folyamat szmra. m az els hrom ler foglalt.
0: bemenet
1 kimenet
2 : hibakimenet
Ezt kveten az jabb llomnymegnyitsok sorn egyre nagyobb szmokat
kapunk vissza. Lehetsgnk van arra is, hogy llomnylerkat kicserljnk
egymssal. gy az is megoldhat, hogy a 0, 1, 2 lerk mgtt az llomnyt ki-
cserljk, s gy a folyamat bemenett vagy kimenett pldul egy csveze-
tkre cserljk le. Ezt a kimenet/bemenet tirnytsnak nevezzk (lsd
rszletesen a 4.1.8. llomnyok tirnytsa cm alfejezetben).
A bemenetet, a kimenetet s a hibakimenetet nemcsak a programban,
hanem akr mr indtsnl a shell parancsban is tirnytatjuk:
ere
A fenti pldban az els program kimenett egy csvezetkre ktjk, amelynek a
msik vgt a sort program bemenetre csatlakoztatjuk. A sort program bc-
sorrendbe rendezi a sorokat, majd a kimenett egy llomnyba irnytjuk t.
2.6. A Linux programozsi fellete
A Linux programozsi felletnek kt jl elklnthet szintje van: az egyik a
kernel fellete, a msik az erre pl, felhasznli zemmdban fut knyv-
trak. A kernel felhasznli zemmdban hvhat funkciit rendszerhv-
soknak (system call, rviden syscall) nevezzk, ezek sszessge adja a kernel
programozsi fellett. A rendszerhvsok teszik lehetv az tjrst a felhasz-
nli s a kernelzemmd kztt: ezeket ugyanis felhasznli zemmdban
hvjuk, de kernelzemmdban futnak. Mivel az zemmdok kztti vlts
architektrafgg, ezrt az implementci rszletei is klnbznek az egyes
architektrkon.
44
- -- write() libc hvs
22.62. A Linux programozsi fellete
A rendszerhvst egyedi szm, a rendszerhvsszm (syscall number)
azonostja. Erre azrt van szksg, mert az zemmdok kztti tkapcsols-
kor nem hagyomnyos fggvnyhvst vgznk: a kernelnek egy belpsi
pontja van, amely a memrin s a regisztereken keresztl veszi t az adato-
kat, kztk a rendszerhvsszmot. Ez utbbi segtsgvel egy tblzatbl ki-
vlasztja, majd meghvja a megfelel rendszerhvs-kezelt. A Linux rklte
a rendszerhvsait a Unix rendszerektl, amely meglehetsen stabil s kifor-
rott felletet ad. Ezrt nagyon ritkn vezetnek be j rendszerhvsokat. Ha
mgis szksgnk lenne erre, a Linux makrkkal teszi egyszerv j rend-
szerhvs ksztst. Ezt a 2.10. bra szemllteti.
A rendszerhvsok meghvshoz tisztznunk kell az
alkalmazsprog-
ramozi fellet (Application Programming Interface, API) s a binris al-
kalmazsfellet (Application Binary Interface, ABI) fogalmt. Ezekre a
fogalmakra magyarul is az angol rvidtst hasznljuk.
Az API forrskdszint felletet definil, a Linux estben C-fggvnyek
prototpusait, illetve azok viselkedst, a Linux esetn kziknyvoldalakat.
Jllehet a rendszerhvsokat kzvetlenl is hvhatnnk, hiszen azok is C-
fggvnyek, a Linuxot a C-programknyvtr (C library, libc) API-jn ke-
resztl programozzuk. Ennek az API-nak tlnyom rsze POSIX-szabvny,
de a Unix/Linux opercis rendszerek estben elg kzel van a rendszerhv-
sok biztostotta API-hoz. Sok esetben a libc fggvny maga a rendszerhvs.
Ugyanakkor nem minden libc fggvny felel meg kzvetlenl egy rendszerh-
vsnak. A libc fl szmtalan API ll rendelkezsre, sokuk interpreter s vir-
tulis gp formjban, ezltal teszi lehetv a C-nl magasabb szint nyelvek
hasznlatt. A szabvnyos C++-knyvtr is a libc-re pt.
Felhasznli zemmd
teml_handler() rendszersysteml_handler
sys_write() rendszerhvs
Kernel zemmd
2.10. bra. A rendszerhvs folyamata
Mint a neve is sugallja, az ABI a binris kompatibilits feltteleit rja le, ide
tartoznak a hvsi konvencik, a regiszterek hasznlata, byte-sorrend. Az
ABI
lnyegben a fordtt s a linkert rinti. Mg a Linux
API nagy rszt a
POSIX-szabvny definilja, az ABI- k specifikcija architektrafgg. Ez a
specifikci fellelhet az interneten, gyakorlatban arra ptnk, hogy egy
adott platformon a gcc csomag ismeri s tmogatja a Linux ABI-jt.
45
HARMADIK FEJEZET
Programknyvtrak
ksztse
A programknyvtrak alapjainak ismerete elengedhetetlen egy Linux rend-
szer testreszabshoz, elksztsk s felhasznlsuk nlkl pedig nem kp-
zelhet el nagyobb program. Ha bepl modulokat (plugin) szeretnnk
megvalstani, vagy a programunk architektrjt lecserlhet binris kom-
ponensekre ptjk fel, ugyancsak a programknyvtrak nyjtjk az implemen-
tci httert. Ebben a fejezetben ttekintjk a programknyvtrak alapjait,
majd programozsi krdseiket trgyaljuk meg C nyelven, vgl kitrnk a
C++-osztlyokat tartalmaz programknyvtrakkal kapcsolatos megoldsokra.
A fejezetet egy halad tmakr zrja: megvizsgljuk a programbetlts folya-
matt, valamint ennek keretben a sebessgoptimalizl eszkzk mkdst is.
3.1 . Statikus programknyvtrak
Bevezetsknt nzznk meg egy egyszer pldt:
/*
ceiling.c*/
include<stdio.h>
doubleceil(double);
intmain()
{
doublex;
printf("Keremazx-et:");
scanf("%lf",&x);
printf("ceil(x)=%6.4f\n",ceil(x));
return0;
}
32. fejezet: Programknyvtrak ksztse
double cei 1 (doubl e x)
{
double i x=(int)x;
return ix<x ? ix+1 : ix;
}
Ennek fordtsa a kvetkez:
gcc-oceilingceiling.c
A fggvnyt a C nyelv konvencii szerint deklarcira s defincira bontottuk.
A deklarci megadja a fggvny nevt, argumentumainak s visszatrsi r-
tknek a tpust2 . Ez tulajdonkppen az sszes adat, amelyre a fordtnak
egy fggvny meghvshoz szksge van. A definci a fggvnnyel kapcso-
latos minden informcit tartalmazza.
Ha a hvshoz elg a deklarci, akkor a defincit akr kln llomnyba
is tehetjk. A ceiling.c llomny tovbbra is felhasznlja a ceil fggvnyt:
7* ceiling.c */
#i ncl ude <stdi o.
double ceil (doubl e) ;
int mai n()
{
double x;
pri ntf("Kerem az x- et: ");
scanf ("%1 f" , &x);
pri ntf("ceil (x) = %6. 4f \ n" , cei 1 (x)) ;
return 0;
A ceilfunc.c llomny pedig tartalmazza a meghvand ceil fggvnyt: /*
ceil func.c */
double cei 1 (doubl e x)
{
double i x=(i nt)x ;
return ix<x?ix+1: x;
48
32.12. Statikus programknyvtrak
Ezt az albbiak szerint fordtjuk (az els kt sor a fordtt hvja, termszete-
sen felcserlhet):
2 2
gcc-cceilfunc.c
gcc-cceiling.c
gcc-oceilingceiling.oceilfunc.o
A 3.1. bra mutatja a fordts egsznek a folyamatt.
ceilfunc.c
Fordt (Compiler)
ceilfunc2.o
ceiling2.c
Fordt (Compiler)
ceiling.o
gcc -c
gcc -o
Linker
ceiling
3.1. bra. A fordts egsznek folyamata
Amikor a fordt a ceiling.c llomnyt fordtja, assembly kdot generl az
egyes utastsokbl Amikor a fggvnyhvshoz rkezik, akkor a deklarci-
bl tudja, hogy milyen paramtereket kell tadnia a fggvnynek. Egy dolgot
azonban nem tud: mi lesz a ceil fggvny cme? Ezt ilyenkor mg nem csak a
fordt nem tudja kiszmolni: a vgleges program struktrja nlkl a cmet
nem lehet megmondani. Ugyanis s ennek szemlltetsre fordtottunk a
gcc tbbszri futtatsval az egyes llomnyok fordtsa teljesen fggetle-
nl fut: a ceiling.c fordtsa teljesen fggetlen a ceilingfunc.c llomny ford-
tstl, a compilert akr prhuzamosan is lefuttathatjuk.
22
A gcc tulajdonkppen egy olyan ltalnos program (compiler driver"), amely a parancs-
sori argumentumai alapjn kivlasztja, hogy melyik eszkzt kell meghvni, s hogyan.
Az eszkzk sokflk: lehetnek szmos nyelv fordtprogramjai (esetnkben a C/ C++
fordt), az assembler s a linker. Mi magunk is kiegszthetjk a gcc-t klnbz eszk-
zkkel2 . A fordt-assembler-linker szekvencia a leggyakoribb forgatknyv.
49
3. fejezet: Programknyvtrak ksztse
Mivel teht a cm nem ismert, a fordt jobb hjn elhelyez egy ceil szimb-
lumot
2 3
a cm helyre, s ezzel elvgezte az sszes feladatt. A fordt kimenett
trgykd llomnynak (object file) nevezzk, s alaprtelmezetten .o-ra
vgzdik.
Ebbl szinte egyenesen kvetkeznek a linker fbb feladatai. Elszr egyms
utn kell raknia az egyes fggvnyek kdjait a trgykd llomnyokbl, majd
vgrehajtani az thelyezsbl add cmmdostsokat. Msodszor fel kell ol-
dania a fordt ltal htrahagyott szimblumhivatkozsokat, jelen esetben a
ceil szimblumot, a memriahelyeket kijell szimblumdefincikkal. Ez azt je-
lenti, hogy meg kell keresnie az sszes szimblumot s szimblumhivatkozst,
majd ssze kell prostania ket. Harmadszor el kell ksztenie a futtathat l-
lomnyt az adott platform ltal tmogatott formtumnak megfelelen.
Az els fordtk idejn az egsz forrskdot egyszerre kellett lefordtani,
m ez sok idt vett ignybe. A folyamatot gy lehetett gyorstani, hogy a
program egyes rszeinek fordtsa kln is megvalsult. A C/C++ programo-
zsi nyelveknl ez az jelenti, hogy a fordt kln dolgozza fel az egyes forrs-
llomnyokat, gy csak azokat az llomnyokat kell jrafordtani, ahol a for-
rsllomny frissebb, mint a fordt kimenete, vagyis a trgykd llomny.
gy a nem vltoztatott forrskdokat nem kell fordtani, elg csak linkelni.
Ha fggvnyknyvtrunkat szeretnnk msok szmra is hozzfrhetv
tenni, elg csak a lefordtott verzit odaadnunk, ezzel gyorsthatjuk a ford-
tst, hiszen a fggvnyknyvtrunk implementcijt nagy valsznsg sze-
rint nem szeretn mdostani az ezt felhasznl programoz.
2 4
Ha strukturlni szeretnnk a forrskdunkat, tipikusan tbb llomnyban
rjuk meg a fggvnyeket. A fentiek alapjn annyi trgykd llomny jn lt-
re, ahny forrsllomnyunk van. Ez kiss knyelmetlen, hiszen sokszor az
sszes fggvny egyetlen fggvnyknyvtrat alkot. Erre ad megoldst a sta-
tikus programknyvtr (static library), amely lnyegben sszefztt
trgykd fjlokbl ll. A statikus programknyvtrakat a linker fzi a fut-
tathat programhoz, gy az egsz fggvnyknyvtr kdja a futtathat prog-
ram rszv vlik.
2 3
Jllehet az eredeti C-fordtk egy alhzst is tettek a fggvny neve el ma mr rg el-
avult okokbl (a FORTRAN s az assembly nyelv rutinokkal val nvtkzs elkerlsre
vezettk be), az ELF formtumot tmogat fordtk mr nem kvetik ezt a gyakorlatot: a
szimblum a fggvny neve. A C++ esetn a fggvnynevek tlterhelse teszi szksges-
s, hogy az argumentumlista tpusaival egsztsk ki a fggvnyneveket, gy a linker
szintjn is megklnbztethetv vlnak a tlterhelt fggvnynevek. A C++-szabvny ezt
az gynevezett nvelferdtst (name mangling) a fordtkra bzza, amelyek ezzel a lehe-
tsggel teljesen klnbz mdon oldjk meg a krdst2 . Arra azonban a legtbb fordt
figyel, hogy a C-, illetve C++-nvelferdtssel fordtott fggvnyek ne tkzhessenek a
linker szintjn2 .
2 4
Termszetesen a gyakorlatban mellkelik a hibakeresshez szksges informcikat is,
valamint nagyon sokszor a forrst is, amely megknnyti a hibakeresst, vagy lehetsget
biztost a testreszabsra.
50
32.1 . Statikus programknyvtrak
A pldhoz visszatrve statikus programknyvtrat ksztnk a ceilfunc
llomnyunkbl:
ar rcs libceilfunc.a ceilfunc.o
Mindenkppen meg kell jegyeznnk, hogy egyetlen llomnybl teljesen feles-
leges statikus knyvtrat kszteni, hiszen az egsz koncepcit arra talltk
ki, hogy a trgykd llomnyokat ssze lehessen fzni s egy llomnyknt
rendelkezsre bocstani. ltalnos esetben a tovbbi trgykd llomnyokat
szkzzel elvlasztva sorolhatjuk fel az ar program argumentumlistjban.
Az ar segdprogram tulajdonkppen tetszleges llomnyok archivls-
ra alkalmas, ugyanakkor ritkn hasznljuk msra. Ezt az archvumot nevez-
zk statikus programknyvtrnak. A statikus programknyvtr szerkeze-
tileg egy rvid llomnyfejlcbl ll, amely az llomny formtumt jelzi
(!<arch>" karaktersorozat), majd az llomnyok kvetkeznek. Minden llo-
mnyt egy fejlc elz meg, amely az llomnyra vonatkoz informcit (llo-
mnynv, legutols mdosts dtuma, felhasznl s a felhasznli csoport
azonostja, jogosultsgok, llomnymret) tartalmazza. Szmunkra a tovb-
biakban elg, ha a statikus programknyvtrra mint trgykd llomnyok
halmazra gondolunk. A statikus knyvtrak neve ltalban a libxxx.a kon-
vencit kveti, ahol az xxx a knyvtr ltalunk adott neve, esetnkben ceil.
Statikus knyvtrat az albbiak szerint linkelhetnk a programunkhoz:
gcc -o ceili ng ceil ing .o -L2. -1 cei 1 func
Ehhez kt kapcsolt hasznltunk: az L kapcsol megadja azokat az llomny-
rendszerbeli knyvtrakat, ahol a programknyvtrak tallhatk, jelen eset-
ben ez az aktulis knyvtr. Az 1 kapcsol a programknyvtr nevt adja
meg: a lib eltagot s az .a vgzdst elhagyva. A paramterezsben fontos,
hogy ezek a kapcsolk a trgykd llomnyok felsorolsa utn kvetkezze-
nek. A statikus knyvtrak kezelshez a linkernek tulajdonkppen annyival
kell tbbet tudnia az eddigieknl, hogy kpes legyen rtelmezni (kicsomagol-
ni") a statikus knyvtrt reprezentl archvumot. A linker tartalmaz egy
olyan logikt, amely kivlasztja azokat a trgykd llomnyokat, amelyekre
szksg van, s csak azokat fordtja bele a futtathat programba.
A knyvtrban tallhat fggvnyek s globlis vltozk hasznlathoz
termszetesen meg kell adni a fggvnyek s a globlis vltozk deklarcijt a
fordt szmra. Az elbbit a pldban bemutatott mdon tehetjk meg, vlto-
zk esetben az extern kulcsszt hasznljuk. Ezeket a deklarcikat clszer
sszefogni egy .h llomnyban. Vagyis ha az fvkonyvtar fggvnyknyvtrun-
kat statikus knyvtrknt tesszk kzz, akkor tipikusan kt llomnyt bocs-
tunk a programknyvtr felhasznlinak a rendelkezsre: az fvkonyvtar.h-t a
deklarcik szmra, a libfvkonyvtar.a pedig a statikus knyvtr maga.
51
3 2 .fej ezet:P rogramk ny v t rak k sz t se
Ezek utn mr csak egy dolgot kell megvizsglnunk: ha adott egy stati-
kus knyvtr binris formtumban, hogyan tudjuk megnzni azt, hogy ez a
knyvtr milyen szimblumokat definil. Ez hasznos lehet akkor, ha nem
tudjuk, hogy egy adott .h llomnyhoz melyik knyvtr tartozik, vagy megke-
ressk azt a knyvtrat, amely tartalmaz egy adott szimblumot (tipikusan
fggvnyt), vagy csak szmzni akarjuk a felesleges knyvtrakat a progra-
munkbl. Ehhez nzzk meg az albbi pldt:
#include<math.h>
introundingMethod=0;
externinterrorCode;
doubleround(doublex)
{
doubleix;
intsign=x<0?-1:1;;
if(roundingMethod<0
11roundingMethod>2 )
errorCode=-1;
return0;
}
else
{
errorCode=0;
ix=(int)x;
switch(roundingMethod)
{
case0://felk erek it
returnx-ix<=0 ix:ix+1;
case1://lek erek it
returnx ix>=0?ix:ix-1;
case2 ://k erek ites
if(fabs(x-ix)>0.5)
{
returnix+sign;
else
{
returnix;
return0;
52
32.1 2. Statikus programknyvtrak
A fenti knyvtr egy kerektsi algoritmust foglal magban. A knyvtrban
egy globlis vltoz adja meg, hogy felfel, lefel vagy hagyomnyos mdon
kerektsen. Azoknak az llomnyoknak, amelyek szeretnk hasznlni ezt a
vltozt, externknt kell deklarlniuk. gy a knyvtrunkhoz tartoz .h llo-
mny a kvetkez:
/*round.h*/
externintroundingMethod;
doubleround(double);
A hibakd ppen ellenkez logikt kvet: az errorCode vltozt a fprogram
definilja, nem a knyvtr, gy ezt a programknyvtrban externnek deklarl-
juk. Ezek a megoldsok rgiek, nem is kvetendk, ugyanakkor nem plda
nlkliek.
2 5
A teljessg kedvrt bemutatunk egy pldt a fprogramra:
/*roundmain.c*/
#include"round.h"
interrorCode=0;//Errehiv atk ozik maj dak ny v t rbeliextern
intmain()
{
doublex=4.2 ;
roundingMethod=0;
printf("%lf\n", round(x));
roundingMethod=1;
printf("%lf\n", round(x));
roundingMethod=2 ;
printf("%lf\n", round(x));
roundingMethod=3 ;
round(x);
printf("%d\n",errorcode);
//
//
//
//
5.000000
4.000000
4.000000
-1
}
2 5
Tbbszl programokban ezek a globlis vltozk problmt okozhatnak. A rounding-
Method clszeren a round f
5.4 2 .4 .
y egy tovbbi paramtere lenne. Ha kt szlbl hvjuk
a round fggvnyt, a hibakdok sszekeveredhetnek. Ezrt, ha nem visszatrsi rtkkel
vagy kivtelkezelssel, hanem tovbbra is megosztott globlis adattal oldjuk meg a hiba-
kezelst, akkor az 5.4 .4 . Szlbiztos fggvnyek alfejezetben trgyalt szlspecifikus adat-
knt rdemes trolni a hibt s a hozzfrst fggvnyhvson keresztl megoldani.
53
32. fejezet: Programknyvtrak ksztse
Nzzk meg a fordts folyamatt. Elsknt a programknyvtrat fordtjuk le:
gcc - c round.c
ar rcs libround.a round.o
Majd a fprogramot:
gcc -c roundmai n .c
Vgl pedig a linkels kvetkezik:
2 6
gcc -o roundmain roundmai n .o -L. -1 round
Ezutn vizsgljuk meg a knyvtrban tallhat szimblumokat az nm segd-
programmal:
nmlibround.a
round.o:
uerrorCode
00000000T round
00000000B roundingMethod
Ha megnzzk az nm parancs dokumentcijt, a szimblumok tulajdonsga-
ira az angol bc betinek mintegy a felt felhasznlja. Szmunkra azonban
hrom eset fontos. A T azt jelenti, hogy egy fggvnyt definiltunk az adott
knyvtrban,
2 7
ezt a fggvnyt a programknyvtr felhasznlja hvhatja.
Az U valjban egy szimblumhivatkozst jelent: ez a szimblum nincsen de-
finilva (undefined) ebben a programknyvtrban. Ide tartoznak az extern
vltozk s azok a meghvott fggvnyek, amelyek ms programknyvtrban
vagy trgykd llomnyokban tallhatk.
2 6
Jogosan merl fel az a krds, hogy hol van a fabs fggvny definilva, mirt nem ka-
punk linkerhibt2 . Ugyanis a math.h-t tartalmazza az llomnyunk, m az ezzel jr ma-
tematikai programknyvtrat nem linkeltk hozz az /m kapcsolval2 . A megolds az,
hogy a fabs makrknt definiland, vagyis nem jelenik meg kln fggvnyknt, a ford-
t mr csak a behelyettestett makrtrzset ltja2 . Ugyanakkor pldul a sin fggvny
nem makr: ha azt hasznlnnk, akkor linkelskor hozz kellene adnunk a fent emltett
kapcsolt a gcc paramterlistjhoz2 .
2 7
A T a text rvidtse: ez az llomny azon szekcijnak a neve, amely a futtathat kdot
tartalmazza2 . Az elnevezs eredete homlyos, ugyanakkor ismers a gcc linker hibazene-
teibl: ott a 2.text a futtathat kd szekcijnak kezdett jelli, s megadja, hogy attl
szmtva melyik utasts hivatkozik a nem tallt szimblumra2 .
54
32.22. Megosztott programknyvtrak
Az bc tbbi betje fknt a vltozkra vonatkozik, s azt rja le, milyen
jelleg adatterletre tlti be ket az opercis rendszer betltrutinja.
2 8
Ha
egy szimblum nagybet, akkor ez azt jelenti, hogy globlis, vagyis kvlrl
hozzfrhet, a kisbet pedig azt jelenti, hogy loklis, vagyis kvlrl nem
hasznlhat.
2 9
Ez utbbit a C nyelv static kulcsszavval rhetjk el mind a
fggvnyek, mind a vltozk esetben. sszefoglalva: ha a knyvtr nagybe-
tvel definilja ezeket a vltozkat, hivatkozhatunk rjuk.
Az nm segdprogram a trgykd llomnyokra is mkdik:
$nm roundmain.o
00000000 B errorCode
00000000 T main
u printf
u round
u roundingMethod
A fprogram termszetesen definilja a main fggvnyt s az errorCode glo-
blis vltozt, tovbb hivatkozik a printf, a round s a roundingMethod
szimblumokra. Ugyanakkor felmerl a krds: hol tallhat a printf kdja?
Az stdio.h-ban definilt fggvnyek a libc elnevezs knyvtrban vannak, de
az -lc kapcsolt ekkor, a futtathat llomnyok ksztsnl nem kell kln
szerepeltetnnk a gcc argumentumai kztt: a szabvnyos C-programknyv-
trat a linker alaprtelmezetten hozzadja a programunkhoz
3.2. Megosztott programknyvtrak
Ha a fggvnyknyvtrunkat frissteni szeretnnk, kijavtunk benne pldul
nhny hibt, akkor a statikus programknyvtrat hasznl programot jra
kell linkelni: a linkernek az j verzit kell hozzfznie a programhoz A stati-
kus knyvtrbl a szksges trgykd llomnyok ltal tartalmazott kd be-
lekerl a futtathat programba. gy pldul, ha tbb program hasznl egy
2 8
Leszmtva V s W betket, amelyek a gyenge (weak) szimblumokat jelzik. A gyenge
szimblumok felldefinilhat globlis szimblumok: ha valahol mshol definilva van
egy ugyanolyan nev nem gyenge globlis szimblum, akkor azt hasznlja a linker, ha
nem, akkor a gyenge szimblumot, vltoz esetn nullra inicializlva. Ha kt ugyano-
lyan nev nem gyenge globlis szimblumot definilunk, az linkerhibt eredmnyez.
Gyenge fggvnyeket a gcc-vel az albbi mdon adhatunk meg: void _attribute_((weak))
func(void)Q. Ebben az esetben, ha valahol mshol definilunk egy nem gyenge func nev
fggvnyt, akkor a linker ezt hasznlja, s nem a fenti, res trzst, egybirnt azonban
a fenti fggvnyt2 . Ezzel hatkonyan rhatunk fell alaprtelmezett viselkedst2 . Vltozk
esetn ugyangy az _attribute_((weak)) nem szabvnyos gcc-kiterjesztssel rhatjuk el
a gyenge viselkedst.
2 9
Itt csak globlis szimblumokrl beszlnk, a loklist nem a fggvnyen belli", hanem
a modulra nzve csak bellrl lthat rtelemben hasznljuk.
55
32 . fejezet: Programknyvtrak ksztse
statikus programknyvtrban lv fggvnyt, pldul a mr emltett printf-et,
s minden fontosabb kategribl egy fggvnyt, akkor az egsz libc knyvtr
annyi pldnyban szerepel a memriban s a merevlemezen, ahny program
hasznlja.
Ennek elkerlshez az szksges, hogy a programknyvtrunkat kln l-
lomnyban helyezzk el: egy pldnyban troljuk a merevlemezen, amennyire
lehetsges, egy pldnyban tltjk be a memriba a knyvtr megoszthat r-
szeit, gy az sszes program ezt a pldnyt hasznlja. Ezt az llomnyt meg-
osztott programknyvtrnak (shared library) nevezzk. A megosztott
programknyvtrat az els, ezt hasznl program indtsakor vagy az els
programknyvtrbeli fggvny hasznlata eltt tltjk be dinamikusan, s
a betlts kzben vgezzk el a szimblumfeloldst, amely klasszikus esetben
a linker feladata. Ezrt a megosztott knyvtrakat dinamikus linkels prog-
ramknyvtraknak (Dynamically Linked Libraries, DLL) is nevezik.
Ezek alapjn nyilvnval, hogy a program futtatshoz nem elg a fut-
tathat llomny, szksgnk van a programknyvtrat tartalmaz llo-
mnyra is. Ezt a megoldst az opercis rendszerek ltal felajnlott fgg-
vnyknyvtrakra is alkalmazhatjuk: gy egyszeren megoldhat a Linux
frisstse a mr teleptett programok vltoztatsa nlkl.
A kvetkezkben ismertetjk a megosztott knyvtrakat. A lersban
megfigyelhetjk, hogy a megosztott knyvtrak kszti megtettek minden t-
lk telhett, hogy a forrskdot ne kelljen vltoztatni, ha statikus program-
knyvtrak helyett megosztott knyvtrakat szeretnnk hozzlinkelni a
programunkhoz.
3.2.1. Megosztott programknyvtr ksztse
Feladat Ksztsnk megosztott knyvtrat a kerektst vgz fggvnynkkel.
A megolds figyelemre mlt eleme az, hogy a forrsllomnyokat nem kell
mdostani. Kt fontos vltozs van:
mskpp kell fordtani a programknyvtrat, s
konfigurlni kell a krnyezetet, hogy a program futsi idben megta-
llja a knyvtrat.
A konkrt fordts lpseinek rszletezse eltt meg kell rtennk a megosz-
tott knyvtrak nvkonvencijt. Egy megosztott knyvtr elnevezse azrt
fontos, mert szmos program hasznlhatja ugyanannak a programknyvtr-
nak a klnbz verziit, s kellemetlen lenne, ha sszekeverednnek.
30
A megosztott programknyvtrakat tartalmaz llomnyok neve az albbi
3
A Windows opercis rendszereknl ez a jelensg a DLL-pokol" (DLL hell) nevet kapta.
Linux alatt ezt az elnevezsi konvencik betartsval kerljk el.
56
3.2. Megosztott programknyvtrak
sma szerint pl fel: libxxx.so.y.w.z, ahol y a fverziszm, w a mellkverzi-
szm, z pedig a kibocstottverzi-szm (release), az xxx pedig a knyvtr lta-
lunk adott neve. Az so a megosztott trgykd llomny" kifejezst (shared
object lile) rvidti. A kibocstott verzi szma ltalban minden egyes nyil-
vnos fordtssal nvekszik, a mellkverziszm a fontosabb javtsokat jelzi.
A fverziszm a legfontosabb, a msik kett opcionlis. Ha a futtathat
programtl kln llomnyban troljuk a programknyvtr kdjt, akkor az
esetleges javtsok utn elg csak a programknyvtr llomnyt kicserlni
az j verzira. Nyilvnval, hogy a mdostsok csak bizonyos keretek kztt
mozoghatnak, hiszen pldul a fprogram szmt bizonyos szimblumokra,
amelyeket nem tvolthatunk el, illetve a fggvnyeket tovbbra is meg kell
tudnia hvni. Vizsgljuk meg, melyek ezek a keretek pontosan. Mivel csak a
linkels dinamikus, a fordts nem, ezrt a fordt ltal hasznlt informci
nem vltozhat. Ez gyakorlatilag a hasznlt vltozk tpust s a fggvnyek
prototpust jelenti. Vagyis ha a fggvnyek trzsben hibt javtunk, vagy j
loklis fggvnyeket/vltozkat adunk a knyvtrhoz, akkor a mr lefordtott
program tovbbra is mkdik a knyvtrral, nem kell jrafordtanunk. Rvi-
den sszegezve: a knyvtrnak a program fel mutatott fellete, vagyis az in-
terfsze nem vltozik. A fverziszm lnyegben az interfsz vltozst jelzi.
Azonos fverziszm knyvtraknak azonos interfszknek kell lennie. Va-
gyis ha megvltozik a fverziszm, akkor az elz verziszm knyvtrral
fordtott programok futsa nagy valsznsggel hibt jelezve megszakad.
Nzzk meg a kvetkez szitucit. A merevlemezen ugyanannak a prog-
ramknyvtrnak klnbz verzii tallhatk egy knyvtrban, hiszen a k-
lnbz programok klnbz verzikat hasznlnak:
libround.so.1.0.1
libround.so.1.0.2
libround.so.1.1.0
libround.so.2 .0.0
Tegyk fel, hogy a roundmain programunk az egyes fverziszm inter-
fsszel lett fordtva. Azt szeretnnk, hogy a legfrissebb egyes fverziszm
programknyvtrat hasznlja (libround.so.1.1.0). Ezt legknnyebben egy ndi-
rekcival oldhatjuk meg: ltrehozunk egy libround.so.1 nev szimbolikus lin-
ket, amely mindig a legfrissebb programknyvtrra (libround.so.1.1.0) mutat.
A roundmain programnak a szimbolikus linket adjuk meg. Ha kijavtunk egy
hibt az egyes fverzij programknyvtrban (libround.so.1.2.0), akkor a
frissts az j programknyvtr bemsolst jelenti az adott knyvtrba, va-
lamint a libround.so.1 szimbolikus link tlltst erre a legfrissebb verzira.
A szimbolikus linket so-nvnek
3 1
(soname) nevezzk, mg a programknyv-
tr fjlrendszerbeli nevt fizikai nvnek.
31
Kiejtse esonv".
57
3. fejezet: Programknyvtrak ksztse
Programknyvtrat tartalmaz llomny
(libxxx.so.1.3.5)
Szimbolikus link Szimbolikus link
So-nv
(libxxx.so.1)
Linkernv
(libxxx.so)
Ezt hasznlja a programunk, Ezt hasznlja gcc, alatta cserlhetjk
alatta cserlhetjk a fizikai a fizikai llomnyt:
llomnyt. Ltszik, hogy a f gcc -Ixxx
verziszmot megtartjuk, Ha mindig a legfrissebbet szeretnnk
mert ha az vltozik,
fordtani, a szimbolikus linket az
akkor mr a programnak is so-nvre lltjuk.
vltoznia kell (jrafordts).
3 .2 . bra.A programknyvtrak elnevezsi konvencija
A 3.2. bra bal oldala a programknyvtr eddig ismertetett hasznlatt il-
lusztrlja. A jobb oldal azokat rinti, akik fordtani szeretnnek. Hasonlan
a statikus knyvtrakhoz, a gcc paramterei kztt gy hivatkozunk a prog-
ramknyvtrra, hogy elhagyjuk a kiterjesztst (jelen esetben ez nem .a,
hanem .so) s a lib eltagot. Ha azonos nev statikus s dinamikus program-
knyvtrat tall a linker, automatikusan az so kiterjeszts dinamikus prog-
ramknyvtrat veszi figyelembe, hacsak nem alkalmazzuk a static kapcsolt.
Mindez azt jelenti, hogy ksztennk kell egy jabb szimbolikus linket,
amelynek az alakja libround.so , hogy ha a linkernek az -lround paramtert
adjuk meg, akkor megtallja. Ezt a szimbolikus linket linkernvnek (linker
name)
nevezzk. Arra a verzira lltjuk, amelyiket hozz szeretnnk linkelni a
programunkhoz. Ha egy adott interfsz legfrissebb verzijt szeretnnk hasz-
nlni (ez fordul el leggyakrabban), akkor egyszeren az so-nvre lltjuk.
Nzzk meg, hogy mkdik ez a gyakorlatban. Elsknt fordtsuk le a
programknyvtrat. A fordtt az albbi mdon paramterezzk:
gcc - fPIC -c -Wall round.c
Az egyetlen klnbsg -fPIC kapcsol, amely a pozcifggetlen kd generlst
rja el. (Ennek pontos jelentsre ksbb mg visszatrnk.) Ez a kapcsol
programknyvtrak esetben csak nhny architektrn nem alaprtelme-
zett, az Intel-architektra azonban nincsen ezek kztt.
58
3.2. Megosztott programknyvtrak
Ezek utn a linkels kvetkezik:
gcc-shared-w1,-soname,libround.so.1
-olibround.so.1.0.1round.o-1c
Itt megadjuk a gcc-nek, hogy megosztott programknyvtrat szeretnnk k-
szteni. A -W/ kapcsolval a vessz utni karaktersorozatot a gcc a linkernek
tovbbtja. Ez esetben gy adjuk meg a linkernek az so-nevet. A tbbi param-
ter ismers, ezttal a libc alapknyvtrat rdemes kln megadnunk. Eddig
teht elksztettnk egy olyan programknyvtrat, amely a libround.so.1.0.1
llomnyban tallhat, s nyilvnval, hogy erre a libround.so.1 so-nvvel hi-
vatkozunk. Ezek utn fel kell lltani a szimbolikus linket Ezt legegyszerb-
ben az ldconfig segdprogrammal tehetjk meg:
/sbin/ldconfig -n .
A segdprogram alapfunkcija szerint a rendszer szoksos knyvtraiban (pl-
dul /lib, /usr/lib) tallhat, tovbb az letc/ld.so.conf llomnyban felsorolt
llomny-rendszerbeli knyvtrakban lv programknyvtrakra elkszti a
szimbolikus linkeket, majd az opercis rendszer programknyvtrakat tar-
talmaz gyorsttrban (cache) helyezi el 'ket. Ez a gyorsttr egy olyan bi-
nris llomny (letc/ld.so.cache), amely lnyegben a programknyvtrak
so-nevt, llomnyformtumt s teljes elrsi tvonalt tartalmazza. gy a
programbetlt gyorsan megtallja a hivatkozott programknyvtrakat
Termszetesen a parancssorban is megadhatunk llomny-rendszerbeli
knyvtrakat, amelyekhez ugyangy szimbolikus link kszl, s amelyek
hozzaddnak a gyorsttrhoz. A gyorsttr ltal hivatkozott program-
knyvtrakat a
isbin/ldconfig - p
parancs segtsgvel rathatjuk ki. Pldaknt a libm bejegyzst mutatjuk
meg:
libm.so.6(libc6, OSABI : Linux2 .2 .5)=>/lib/libm.so.6
A libm matematikai knyvtr a libm.so.6 so-nevet kapja, libc6-os formtum, a
Linux 2 .2 .5 binris interfszt ignyli, s a szimbolikus link a /lib/libm.so.6 el-
rsi tvonalon tallhat.
Ha az -n, kapcsolt hasznljuk, akkor a segdprogram csak a megadott l-
lomny-rendszerbeli knyvtrakban tallhat programknyvtrakhoz kszt
szimbolikus linket, s nem frissti a gyorsttrat. Pldnkban az aktulis
knyvtrat adtuk meg, s ennek hatsra ltrejtt a fizikai llomnyra muta-
t szimbolikus link:
libround.so.1->libround.so.1.0.1
59
3 .fej ezet:P rogramk ny v t rak k sz t se
Mivel a linker belefordtotta az so-nevet a programknyvtrba, az ldconfig
automatikusan el tudta kszteni a szimbolikus linket.
32
Jelen esetben a
programunk mellett troljuk a knyvtrat, s ksbb rszletezend okok mi-
att nem adtuk hozz a gyorsttrhoz.
rdemes megjegyezni, hogy a statikus knyvtrhoz kpest a program-
knyvtr C-kdjt nem kellett megvltoztatnunk, mindssze a fordt argu-
mentumai vltoztak meg. Ugyangy a .h s a binris llomnyokat kell tadni
a programknyvtr hasznljnak. Tovbbi klnbsg az, hogy le kell futtat-
nunk az ldconfig segdprogramot legalbb a szimbolikus link elksztshez.
3.2.2. Megosztott programknyvtrak hasznlata
A kvetkezkben nzzk meg a programknyvtrak hasznlatt Itt mg any-
nyi vltoztatssal sem kell szmolnunk, mint fentebb: a programknyvtr
nevt kell megadnunk a linkernek ezttal is a lib s a kiterjeszts nlkl.
Ha pldul a linker egy -lround argumentumot kap, az -L kapcsolval
megadott knyvtrakban elszr egy libround.so llomnyt keres, majd ha
nem tall, akkor egy libround.a-t. Ahhoz, hogy a fenti parancs mkdjn, lt-
re kell hozni a libround.so llomnyt, amely termszetesen egy szimbolikus
link, s kzvetlenl vagy kzvetve a programknyvtrat tartalmaz llo-
mnyra mutat. Ezt a szimbolikus linket, ahogy korbban mr volt rla sz,
nevezzk linkernvnek, ugyanis azt lltja be, hogy a linker melyik fizikai
programknyvtrat tartalmaz llomnyt hasznlja fel. Ha mindig az aktu-
lis verzit szeretnnk hasznlni, akkor az so-nv szimbolikus linkjre lltjuk
a linkernevet is:
ln -slibround.so.1libround.so
Ezzel ltrejtt az albbi szimbolikus link:
libround.so->libround.so.1
Ha msik verzit szeretnnk hozzlinkelni a programunkhoz, a linkernevet
megad szimbolikus linket a megfelel verzit tartalmaz llomnyra lltjuk
be. Ezek utn futtassuk a linkert:
gcc-oroundmainroundmain.o-L.-lround
32
A Linux opercis rendszer szmos programknyvtr-formtumot tmogat (ez a libm
esetn a libc6 volt), amely mgtt kln formtumok llnak. A libc6 a legjabb ELF for-
mtumot jelenti. Az ldconfig ezt a hivatkozott libc verzi alapjn prblja kitallni Ez az
oka annak, hogy a programknyvtr linkelsekor expliciten megadtuk az -/c kapcsolt.
Az ldconfig egyszerre tbb formtumot is kpes kezelni ugyanazon a rendszeren.
60
3.2. Megosztott programknyvtrak
Vgl mr csak a program futtatsa marad Ekkor azonban a kvetkez tr-
tnik:
. /roundmain
./roundmain:errorwhileloadingsharedlibraries:libround.so.1:
cannotopensharedobj ectfile: No suchfileor
directory
Jl lthat, hogyha az opercis rendszer nem tallja a hivatkozott program-
knyvtrakat, hibazenetet kapunk. A kvetkezkben megvizsgljuk, hogyan
lehet ezt a problmt orvosolni.
Els'knt nzzk meg az LD_LIBRARY PATH krnyezeti vltozt, amely
a programknyvtrak keressi tvonalait tartalmazza. Az aktulis knyvt-
rat hozzadjuk, s a programunk azonnal fut:
LD_LIBRARY_P ATH=.:$LD_LIBRARY_P ATH
Ez a krnyezeti vltoz a legels lloms, amikor az opercis rendszer a
programbetlts sorn elkezdi keresni a megosztott programknyvtrat. Ha
ezen elrsi tvonalak valamelyikben megtallja az adott programknyvt-
rat, betlti. Termszetesen minl tbb tvonalat tartalmaz ez a krnyezeti
vltoz, annl tbb knyvtrat kell megvizsglni a betlts sorn, s ez jelen-
tsen lassthatja a rendszert. Ennek a krnyezeti vltoznak a hasznlatval
lecserlhetnk" mr ltez programknyvtrakat: mivel a rendszer itt keresi
elszr a betltend programknyvtrakat, elbb tallja meg az LD_LIB-
RARY PATH elrsi tvonalaiban tallhat programknyvtrakat, mint a
mshol tallhatakat. Ugyanakkor ez ritkn clunk, legtbbszr, ha meg-
adunk egy tvonalat, amellyel vletlenl lecserlnk egy azonos so-nvvel
rendelkez knyvtrat, akkor rejtlyesen szllnak el" betlts kzben a ko-
rbban jl mkd programok. Radsul egyes 64 bites rendszereken me gje-
lennek az LD_LIBRARY PATH 64 s az LD_LIBRARY_PATH_32 krnyezeti
vltozk tovbb fokozva a nehzsgeket.
33
Ha valamely, a rendszer ltal alaprtelmezett knyvtrba msoljuk a
programknyvtrat, majd az elz fejezetben megismerteknek megfelelen
futtatjuk az ldconfig segdprogramot, vagy szintn az ldconfig segtsgvel
csak egyszeren hozzadjuk a programknyvtrat a gyorsttrhoz, ez meg-
oldst jelenthet a problmra. Ugyanakkor tl sok programknyvtr lasstja
a rendszer mkdst, mert a gyorsttr mrete megn. Mivel nagyon sok
program, kztk az opercis rendszer egyes rszei is, a gyorsttrat hasz-
nlja sajt programknyvtrai betltshez, ezrt a rendszer mkdst is le-
lassthatjuk. A megoldst tovbb rontja, ha hlzaton szeretnnk elhelyezni a
programknyvtrat: ekkor mind a lasssg, mind a hlzati llomnyrend-
szer elrhetsge problmt jelent.
33
Egy konkrt rendszeren az strace segdprogrammal indtva a programot az open rend-
szerhvs-prblkozsokbl egyszeren kiderthet, hogy milyen nev programknyvt-
rak betltsvel prblkozott a dinamikus linker.
61
3. fejezet: Programknyvtrak ksztse
Ugyanakkor, ha egyedl a mi programunk futtatott pldnyai hasznljk
a knyvtrat, kihagyhatjuk a rendszerszint megoldsokat a programknyv-
traink betltshez. A Linux ltal hasznlt llomnyformtumok lehetv
teszik, hogy a programunk binris llomnyban megadjuk az ltala felhasz-
nlt megosztott programknyvtrak keressi tvonalt, amelyet a program-
knyvtr futsi idej keressi tvonalnak (runtime library search path,
RPATH) neveznk. Ez az tvonal lehet relatv is. Pldnkban azt a megol-
dst vlasztjuk, hogy a libround.so.1 programknyvtr a roundmain prog-
rammal egy knyvtrban lesz. Ezrt az -rpath (vagy rviden -R) linkerkapcso-
lval hozzadjuk az aktulis knyvtrat a keressi tvonalhoz:
gcc -o roundmain roundmain.o -L. -lround -w1, -rpath .
A - W1 gcc kapcsol itt is arra szolgl, hogy az utna kvetkez karaktersoro-
zatot tadja a linkernek parancssori argumentumknt.
tmutat Lehetleg ne hasznljuk az LD_LIBRARY_PATH varinsait. Ha a programknyvtrat
tbb klnbz program hasznlja, adjuk hozz a gyorsttrhoz. Alaprtelmezetten hasznl-
juk az RPATH adta lehetsgeket.
A teljessg kedvrt megjegyezzk, hogy elvileg a linker is tmogatja a betl-
tshez hasznlt opcikat a linkernv alapjn elnevezett szimbolikus link
megtallshoz, de tapasztalataink szerint ez nem minden rendszeren mk-
dik, ellenttben az ltalunk bemutatott megoldssal. ltalban elmondhat,
hogy legalbb a gyorsttrat vagy az alaprtelmezett llomny-rendszerbeli
knyvtrakat a legtbb linker felhasznlja, hiszen pldul a libc s a libm is
gy rhet el a legknnyebben, s ezek elrhetsgt egyik rendszeren sem
kell megadni."
A gcc korbban bemutatott paramterezsnl egyrtelmen tetten rhet-
jk, ahogy a linker sszeprostja a programknyvtrban tallhat, a fprog-
ram ltal hivatkozott szimblumokat. St a korbban tapasztalt hibazenet
arrl rulkodik, hogy a linker kdot generl annak a programnak az elejre,
amely betlti a knyvtrat, illetve hibazenetet ad, ha nem tallja. Az gy
hasznlt programknyvtrat statikusan linkelt megosztott program-
knyvtrnak (statically linked shared library) nevezzk.
Ha a megosztott programknyvtr hasznl valamilyen erforrst, amelyet
betltskor le kell foglalnia, tovbb amikor a programknyvtrat az operci-
s rendszer eltvoltja a memribl, akkor fel kell szabadtania, megadha-
tunk kt fggvnyt, amely pontosan a fenti esetekben hvdik meg:
34
A linker ltal alaprtelmezetten (nem az L kapcsolval) figyelembe vett knyvtrakat
a linker konfigurcis llomnynak, az gynevezett linkerszkriptnek (linker script) a
SEARCH DIR bejegyzse tartalmazza. A linker PC-ken alaprtelmezetten a beptett
linkerszkriptet hasznlja, amelyet az ld verbose paranccsal rathatunk ki.
62
3.2. Megosztott programknyvtrak
extern void ni
-
L H b(void) attribute_ ((constructor));
extern void cl eanupLi b(voi d) attribute_ ((destructor));
void initLib(void)
{
printf("Betoltes\n");
}
void cl eanupLi b(void)
{
pri ntf("Ki tol tes\n") ;
}
A fggvnyek neve nem szmt, csak az, hogy externknt definiljuk, s megje-
lljk a constructor s a destructor nev gcc attribtummal. Mivel a program-
knyvtrak itt megismert betltse a main fggvny meghvsa eltt trtnik,
illetve felszabadtsa a programbl val kilpskor zajlik, ezek a fggvnyek
is ekkor hvdnak meg.
A fentiek alapjn lnyeges gyakorlati jelentsge van annak, hogy felde-
rtsk, hogy egy adott program vagy programknyvtr milyen ms program-
knyvtrakat hasznl. Erre szolgl az ldd segdprogram:
35
ldd ./roundmain
libround.so.1 => ./libround.so.1 (0x006c7000)
libc.so.6 => /lib/t1s/libc.so.6 (0x009dd000)
/lib/ld-linux.so.2 => /libild-linux.so.2 (0x009c4000)
ldd ./libround.so
libc.so.6 => /lib/t1s/libc.so.6 (0x00815000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x009c4000)
A programknyvtrban tallhat szimblumokat a statikus programknyvt-
raknl megismert nm segdprogrammal rathatjuk ki.
3.2.3. Megosztott programknyvtrak dinamikus
betltse
Feladat Mdostsuk gy a kerekt fprogramunkat, hogy ne csak a sajt kerektalgoritmu-
sunkat tudja hasznlni, hanem ms programozk is rhassanak kerektalgoritmusokat: ezeket
bepl modulnak (plug-in) nevezzk.
35
List Dynamic Dependecies: kb. listzd ki a dinamikus fggsgeket.
63
3 .fej ezet:P rogramk ny v t rak k sz t se
A feladathoz meg kell oldanunk azt, hogy a lefordtott fprogram kpes
legyen olyan programknyvtrakat betlteni, amelyek mg nem llnak ren-
delkezsre linkelsi idben. A statikus knyvtrakkal ez termszetesen kivi-
telezhetetlen. Az elz fejezetben a megosztott programknyvtrat a linker
nv szerint hozzfzte a programunkhoz, az adott nev programknyvtrhoz
pedig automatikusan betltkdot generlt, amely a program indulsakor
megkereste s betlttte a knyvtrat. Termszetesen gyeskedhetnnk az
LD_LIBRARY PATH vltozval, hogy klnbz helyrl tltse be az ugyano-
lyan nev, de klnbz programknyvtrunkat, vagy fellrhatnnk az adott
knyvtrat, jtszhatnnk az so-nvvel, m ezeket a megoldsokat egyrtel-
men nevezhetjk ignytelennek. Ez akkor vlik nyilvnvalv, ha egy na-
gyobb program klnbz rszeiben klnbz bepl modulokat szeretnnk
hasznlni.
Szerencsre lehetsgnk van arra, hogy futs kzben igny szerint be-
tltsnk egy megadott nev programknyvtrat, s annak fggvnyeire s
kvlrl elrhet vltozira nv szerint hivatkozhassunk. A programknyvt-
rat hasznlat utn el is tvolthatjuk a memribl. Nzzk meg, milyen
fggvnyekkel lehetsges ez:
constchar*pluginP ath="./libround.so.1";
handle=dlopen(pluginP ath, RTLD_LAZY);
if(!handle)
{
fputs(dlerror(),stderr);
exit(1);
Pldnkban sztringkonstansknt definiljuk a programknyvtr elrsi tvo-
nalt, a gyakorlatban legtbbszr ezt konfigurcis llomnybl vagy felhasz-
nli adatbevitel alapjn kapjuk meg. Ezutn megnyitjuk a programknyvtrat
a dlopen segtsgvel. Ez a fggvny vgzi el a dinamikus linkelst, amelyet
az elz fejezet pldjban a linker vgzett el, valamint a betltst. Ha a
programknyvtr tovbbi programknyvtrakat hasznl, azokat is automati-
kusan betlti a hivatkozsaikkal egytt tetszleges mlysgig. A bemutatott
dinamikus betlts sorn a program indulsakor nem tltdik be a program-
knyvtr, csak akkor, amikor a vezrls elri a dlopen fggvnyt. Vagyis ha a
megosztott programknyvtr nem tallhat, a program elindul, mindssze
a dlopen fggvny visszatrsi rtke lesz NULL. Ellenkez esetben egy lert
(handle) kapunk, amelyet a programknyvtron vgzett mveletek sorn t
kell adnunk paramterknt. Ha valami hiba trtnik, bvebb informcival a
dlerror fggvny szolgl, amely a hiba lerst adja vissza C-tpus sztring-
knt. Ez a hibakezelsi mdszer rvnyes a programknyvtr tovbbiakban
ismertetett fggvnyeire is.
Nzzk meg, hogy a program betltse utn hogyan frhetnk hozz a
program fggvnyeihez:
64
3.2. Megosztott programknyvtrak
double(*round)(double);
round=dlsy m(handle,"round");
if((error=dlerror()) ! = NULL)
{
fputs(error,stderr);
exit(1);
printf("%lf\n",round(3 .14));
A fenti programrszletben a round fggvnyhez frnk hozz. Elsknt defi-
nilunk egy fggvnypointert, amely egy double argumentumlistj double
visszatrsi rtk fggvnyre mutat. A fordtnak szksge van a fggvny
prototpusra (lsd korbban is). Ennek megadsa elkerlhetetlen, hiszen csak
a linkelst/betltst vgezzk dinamikusan, a fordtst nem. Egy program-
knyvtrbeli fggvnyre mutat mutatt a dlsym fggvnnyel szerezhetnk.
A fggvny meghvsa ezek utn gy trtnik, mint brmelyik mutatjval az
adott fggvny meghvsa. A dlsym tulajdonkppen egy adott szimblum kez-
dcmt adja vissza, legyen az fggvny vagy vltoz. gy a programknyvtr
roundingMethod nev globlis vltozjhoz nagyon hasonlan frhetnk hozz:
int*roundingMethod;
roundingMethod=dlsy m(handle,"roundingMethod");
if((error=dlerror())!=NULL)
{
fputs(error,stderr);
exit(1);
*roundingMethod=1;
A fordtnak ezttal is szksge van a vltoz tpusra, amelyet ezttal is po-
interknt definilunk; ugyanazzal az indirekcival frhetnk hozz a pointer
tartalmhoz, mint ltalban. Ha itt rossz tpust adunk meg, akkor a fgg-
vnyhvst elkszt kdrszlet ltal a veremben elhelyezett adatstruktra
klnbz lesz a fggvny ltal vrttl, s ez szinte brmilyen furcsa mk-
dst eredmnyezhet. Mindig gondosan figyeljnk a fprogramban megadott
pointer s a programknyvtrbeli fggvny egyezsre.
A dlsym nemcsak az ltalunk betlttt programknyvtrban tallhat
szimblumokat adja vissza, hanem a programknyvtr ltal hasznlt prog-
ramknyvtrak szimblumait is tetszleges mlysgig.
Ha nem hasznljuk a programknyvtrat, akkor fel kell szabadtanunk,
ennek hatsra ha a program kzvetlenl vagy ms betlttt program-
knyvtrakon keresztl nem hivatkozik a programknyvtrra az opercis
rendszer eltvoltja a programknyvtrat a memribl. A felszabadtst a
dlclose fggvny vgzi el:
dlclose(handle);
65
3. fejezet: Programknyvtrak ksztse
Trjnk vissza a dlopen fggvnyhez. A fggvny msodik paramtereknt
szablyozhatjuk azt, hogy a programknyvtrban tallhat szimblumokat
(lsd a 3.4.3.4. Dinamikusan linkelt megosztott knyvtr linkelse s betltse
alfejezetet) mikor oldja fel a dinamikus linker Ha azt szeretnnk, hogy a
dlopen meghvsakor trtnjen a szimblumfelolds, akkor az RTLD_NOW r-
tket hasznljuk. Ilyenkor, ha a valamelyik szimblumfelolds nem sikerl,
a dlopen hibval tr vissza. Ha a nem definilt szimblumhoz val hozzf-
rskor szeretnnk a szimblum feloldst, akkor az RTLD_LAZY jelzbitet
adjuk t a fggvnynek.
tmutat Ha nem szeretnnk a betltst a szimblum-hozzfrs sebessgre optimalizlni, va-
lamint rrnk az egyes szimblum-hozzfrsnl lekezelni a hibkat, hasznljunk az RTLD_LAZY-t.
A teljes program forrskdja a kvetkez:
// dynamic_roundmai n c
#include <stdio h>
#include <d
-
I fcn h>
#include "round. h"
int errorcode;
const char* pluginPath = "./libround.so.1";
-
int mai n(i nt argc, char **argv)
{
void *handle;
double ("round)(double);
int* roundingMethod;
char *error;
/" Megnyitjuk a konyvtarat.
handle = dlopen(pluginPath,
i f(! handle)
{
* /
RTLD_LAZY);
fputs(dlerror(), stderr) ;
exit(1);
}
/* Hozzaferunk a round szimbol umhoz "/
round = dl sym(handl e , "round");
if((error = dlerror()) ! = NULL)
{
fputs(error, stderr);
exit(1);
66
3. 2. Megosztottprogramk ny v t rak
/*Hozzaferunk aroundingmethodszimbolumhoz.*/
roundingmethod=dlsy m(handle,"roundingmethod");
if((error=dlerror())!= NULL)
{
fputs(error,stderr);
exit(1);
doublex=4.2 ;
*roundingmethod=0;
printf("%1f\n",round(x));
*roundingmethod=1;
printf("%1f\n"round(x));
*roundingmethod=2 ;
printf("%lf\n",round(x));
*roundingmethod=3 ;
round(x);
printf("%d\n",errorCode);
/*felszabaditj uk ak ony v tarat
dlclose(handle);
}
Fordtskor hozz kell linkelnnk a programunkhoz a dinamikus linker
knyvtrt, ez a fentiekben ismertetett fggvnyeket tartalmaz program-
knyvtr (libdl.so):
gccdy namic_roundmain.c-ody namic_roundmain-1d1
Amikor azonban futtatjuk a programot, hibazenetet kapunk:
./libround.so.1:undefinedsy mbol:errorCode
A fggsg ugyanis esetnkben ktirny: nemcsak a programknyvtrban
lv szimblumokat kell feloldani, hanem a programknyvtrban externknt
definilt errorCode szimblumot is. gy tudjuk rvenni a linkert, hogy a f-
program publikus szimblumait tegye elretv a dinamikusan betlttt prog-
ramknyvtrak szmra, hogy a gcc-nek megadjuk az -rdynamic kapcsolt:
gccdy namic_roundmain.c-ody namic_roundmain-1dl-rdy namic
67
3. fejezet: Programknyvtrak ksztse
Ha azt szeretnnk, hogy a programknyvtrunk hasonlkppen megosztan a
klsleg hozzfrhet szimblumait az ltala hasznlt programknyvtrak-
kal, hasznljuk az RTLD_GLOBAL jelzbitet a dlopen paramtereknt VAGY
kapcsolatban a tbbi jelzbittel.
tmutat Valjban ez egy elgg ritkn hasznlt megolds, mindezzel inkbb a dinamikusan
betlttt programknyvtrak lehetsgeit szeretnnk illusztrlni. Ha a programknyvtrnak
szksge van fprogrambeli vltozkra vagy fggvnyekre, azt lehetleg pointerekkel adjuk t
a programknyvtr fggvnyeinek.
Ismt hangslyozzuk, hogy a betlts teljesen dinamikus, a programnak nin-
csen fggsge a megosztott knyvtrra. Programunk csak a libc-tt (printf s
trsai), valamint a dinamikus programbetlttl (dynamic loader) fgg
(dlopen s hasonlkat tartalmaz programknyvtr).
ldd /dynamic_roundmain
libdl.so.2 => /lib/libdl.so.2 (0x00afb000)
1ibc.so.6 => /lib/t1s/libc.so.6 (0x009dd000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x009c4000)
Mindebbl kvetkezik, hogy ha megadtunk konstruktort, illetve destruktort a
programknyvtrnak, akkor az a programknyvtrat elsknt betlt dlopen,
illetve az utolsknt felszabadt dlclose hatsra hvdik meg. Az gy hasz-
nlt programknyvtrat dinamikusan linkelt megosztott program-
knyvtrnak (dynamically linked shared library) nevezzk, de hasznlatos
a dinamikusan betlttt programknyvtr (dynamically loaded shared
library) elnevezs is. Mind a statikusan, mind a dinamikusan linkelt jelz a
megosztott programknyvtr felhasznlsnak a mdjt jelenti, a megosztott
knyvtr szmra ez nem jelent klnbsget, csupn a fprogram szmra.
Dinamikus esetben a fprogram fggvnyhvsokkal tlti be s tvoltja el a
programknyvtrat, a szimblumfeloldst fggvnypointereken keresztl
vgzi: a szimblumhivatkozs a fggvnypointer, a dlsym ltal visszaadott
rtk a szimblumdefinci helye. Statikus esetben a linker gondoskodik rla,
hogy a programknyvtrakat betltse az indul program, s a szimblumfel-
oldst is elvgzi.
Ebben a fejezetben ismertettk a C nyelv programozs egyik legrugalma-
sabb architektrjt: hogyan lehet olyan bepl modulokat rni, amelyekrl
elg csak a benne lv fggvnyek nevt s argumentumlistjt, illetve a vlto-
zk nevt s tpust ismernnk, a knyvtr kivlasztst s gy a konkrt
implementcit megadhatjuk futsi idben. Felmerl a krds, hogy ltezik-e
olyan megolds, ahol mg ennl is kevesebb informci is elg lenne, pldul
megkrdezhetnnk a knyvtrat, milyen fggvnyei vannak, ezeknek melyek
az argumentumai, s milyen tpusak.
68
3.3. Megosztott knyvtrak C++ nyelven
A vlasz sajnos nemleges, ezzel ugyanis elrtk a C nyelv hatrait: a struk-
trk adattagjainak felptse s a fggvnyek argumentumai elvesznek a for-
dts sorn: pointermveletekk vagy veremkezel utastsokk alakulnak,
amelyekbl lehetetlen visszanyerni a fenti krdsekre kaphat vlaszokat.
36
3.3. Megosztott knyvtrak C++ nyelven
Az elz fejezetekben lttuk, hogy a programknyvtrak hasznlatt lehetv
tv mechanizmusok a fordts utn, a linkels s a betlts folyamatnak
rszeknt aktivldnak. A C++-szimblumok linkerszint reprezentcija
nmileg eltr a C nyelvektl. Ebben a fejezetben bemutatjuk, hogy miknt
kezelhetjk ezeket a klnbsgeket.
Mivel a C++ objektumorientlt nyelv, gy a programok alapvet adat-
struktri az osztlyok, nem pedig a fggvnyek, mint a C-programokban.
Ezrt az elvrsaink is msok: mg az elz fejezetben az adott prototpus
C-fggvnyek implementcijt kicserlhettk egy jabb verzij program-
knyvtrban, a C++ esetben ugyanolyan interfsz (ugyanolyan publikus tag-
vltozkkal s tagfggvnyekkel rendelkez) osztlyokkal szeretnnk ugyanezt
megtenni. Jllehet erre a problmra nem lehet igazn elegns C/C++ megol-
dst javasolni, az albbiakban bemutatjuk a lehetsgeket.
3.3.1. Programknyvtrbeli C++-osztlyok hasznlata
A C++ nyelv lehetv teszi a fggvnynevek tlterhelst (function over-
loading), ez azt jelenti, hogy ugyanazt a fggvnynevet klnbz paramter-
listval tbbszr is felhasznlhatjuk. Mivel a sok ugyanolyan nev szimblum
linkerhibhoz vezetne, a C++ ezt a nvelferdts (name mangling) hasznla-
tval oldja meg. Ez azt jelenti, hogy a fordt az argumentumlista tpusait be-
lepti a fggvnynvbe. Erre szabvnyos eljrs nincs, minden fordt sajt
megoldst vlaszthat, s vlaszt is a tapasztalatok szerint. Ennek kvetkez-
tben a C++-fggvnyek szimblumneveit nemcsak hogy nem egyszer kita-
llni a fggvnynv alapjn, de mg a sokat tapasztalt programozi szem
szmra sem tl eszttikus a ltvny.
A nvelferdts a statikus knyvtrak esetn akkor okozhat problmt, ha
az egyik llomnyt C-fordtval, a msikat C++-fordtval fordtjuk. St ugya-
nez a problma a klnbz C++-fordtk esetben is. Ekkor a linker szintjn
ugyanazok a prototpusok msknt ltszdhatnak, ezrt a linker nem tudja sz-
szeprostani a fggvny hvst a fggvny implementcijval, s nem defi-
36
Ez a problma vezetett el a Java- s .NET-krnyezetek nler adatstruktrihoz.
69
3. fejezet: Programknyvtrak ksztse
nilt szimblumot jelez. Ez a problma programknyvtrak hasznlata nlkl
is ugyangy elkerlhet klnbz fordtval fordtott trgykd llomnyok
linkelsekor. A nem dinamikusan betlttt, megosztott programknyvtr ese-
tn is hasonl a helyzet: azonos fordtnl a linker elvgzi az sszeprostst.
Nzznk egy pldt.
Feladat rjunk C++-osztlyt, amelynek egyetlen fggvnye felfel kerekti a megadott beme-
netet. Az osztlyt megosztott programknyvtrban helyezzk el.
Elsknt ksztsk el az osztlyt. Az osztlydeklarcit kln .h llomnyban
helyezzk el:
// rounder.h
class Rounder
{
publ i c :
int Round(doubl e) ;
};
Az osztly egyetlen fggvnynek a defincijt tartalmazza a rounder.cpp l-
lomny:
#include <math.h>
#include <stdio.h>
#include "rounder.h"
int Rounder::Round(double x)
{
doubl e ix;
ix =(int)x;
return ix < x ? ix+1 : ix;
}
Ezekbl az llomnyokbl megosztott knyvtrat ksztnk a mr jl ismert
mdon, de ezttal C++-fordtval:
g++ -c rounder.cpp
g++ -shared -w1,-soname,librounder.so.1
-o librounder.so.1.0.1 \ rounder.o -lc
/sbin/ldconfig -n .
70
3.3. Megosztott knyvtrak C++ nyelven
Ezutn elksztjk a fprogramot a roundermain.cpp llomnyban:
#i ncl ude "rounder . h"
#i ncl ude <iostream>
using namespace std;
int mai n()
{
double x=4.2;
Rounder r;
cout r.Round(x)endl;
}
A fprogramot a szoksos mdon fordtjuk:
-orounder de rmai n cp - lrounder
Ha visszatekintnk a forrskdra, lthat, hogy a fprogram csak az osztly-
deklarcit ismeri, a fggvnyek implementcijt nem. A fordt tudja, hogyan
kell a C++-fggvnyeket kezelni, a linker pedig sszeprostja a megfelelen
fordtott szimblumhivatkozsokat az implementcival.
A dinamikus linkels programknyvtraknl ppen az okoz problmt,
hogy C-fggvnypointereket hasznlunk (ez a dlsym visszatrsi rtke), gy
a fordt nem ismeri fel, hogy C++-fggvnyekrl van sz, s nem kpes he-
lyettnk kezelni. A linkerszint nevek elferdtsi konvencijn tl rgtn egy
msik problmba is tkznk. A C++-osztlyok nem statikus tagfggvnyei-
nek az adott objektumpldnyra mutat pointert (this pointer") is t kell ad-
nunk. Mind a nvelferdtst, mind a this pointer tadst rdemes a fordtra
bznunk, nincs rtelme kzzel" hamistanunk, mert a fordtkat nem ktik
szabvnyok, az implementci egyik verzirl a msikra vltozhat, st elviek-
ben akr egy fggvny hozzadsa is mdosthatja a nvelferdtst. A nvelfer-
dtsre, illetve a C++-tagfggvnyek hvsra a dlsym nem nyjt tmogatst.
Kvetkezskppen C++-tagfggvnyeket kzvetlenl nem rhetnk el a dlsym
fggvny hasznlatval.
Nvelferdts esetn a megoldst az jelenti, ha megadjuk a fordtnak,
hogy egyes fggvnyeknl ne hasznljon nvelferdtst. Ezt az extern C"
kulcsszval rhetjk el.
extern "C" double round (doubl e x)
{
}
71
3. fejezet: Programknyvtrak ksztse
Termszetesen, ha egy fggvnyt extern C"-vel deklarltunk, akkor nem
terhelhetjk tl. Ezt a megoldst azonban tagfggvnyekre nem alkalmaz-
hatjuk.
tmutat Ha programknyvtrban tallhat C++-osztlyokat szeretnnk felhasznlni, rjunk
extern C" fggvnyeket, amelyek pldnyostjk az osztlyokat, s felszabadtjk a ltreho-
zott objektumokat.
Az eddigiekre ptve a kvetkez fejezetben bemutatjuk, hogyan tudunk di-
namikusan betlttt programknyvtrak C++-objektumaihoz hozzfrni.
3.3.2. C++-objektumok dinamikus betltse
programknyvtrbl
Feladat Az elz feladat kerektst vgz megosztott programknyvtrt mdostsuk gy, hogy
dinamikusan is betlthet legyen. Ksztsk el a dinamikus betltst vgz fprogramot is.
Mint ahogy a fggvnyek esetben, itt is egy indirekci segt: mg a fggv-
nyeknl fggvnypointert hasznltunk, itt az osztlyra mutat pointerrel
dolgozunk. Termszetesen az osztly deklarcijra tovbbra is szksg van
a fprogramban is, ez alapjn az informci alapjn veszi szre a fordt, hogy
egy C++-osztly tagfggvnyt kell hvnia, s gy kezelni tudja helyettnk a
C++-sajtossgokat. A fggvny implementcijt viszont elrejtjk a fprog-
ram ell, ez adja a megosztott knyvtr erejt: brmikor lecserlhetjk egy
msik implementcival. Ennek azonban az az ra, hogy nem hasznlhatjuk
a new opertort, ugyanis ennek a fordtsa azt felttelezi, hogy a konstruktor
cme rendelkezsre ll linkelsi idben, ez pedig a dinamikus linkels
knyvtrak esetben mr nem teljesl. A pldnyostst teht a program-
knyvtr egy fggvnyben kell elvgeznnk. Mivel ezt a fggvnyt meg sze-
retnnk hvni a fprogrambl, extern C"-nek deklarljuk. Ennek jegyben
gy egszthetjk ki a rounder.h llomnyt:
extern"c"Rounder*create();
extern"c"v oiddestroy (Rounder*);
ty pedefRounder*(*create_t)();
ty pedefv oid(*destroy _t)(Rounder*);
Elreltan a pointertpusokat is deklarljuk, hiszen azokkal a dlsym fgg-
vnymutatkkal tr vissza, amelyeket konvertlnunk kell a fggvny tpus-
ra. Az eddigiek alapjn a fprogram egyszer:
72
3.3. Megosztott knyvtrak C++ nyelven
#include"rounder.h"
#include<stdio.h>
#include<iostream>
#include<dlfcn.h>
usingnamespacestd;
constchar*pluginP ath="./librounder.so.1";
intmain(intargc,char**argv )
{
v oid*handle;
create_tcreateFuncP tr;
destroy _tdestroy FuncP tr;
char*error;
//Megny itj uk ak ony v tarat.
handle=dlopen(pluginP ath,RTLD_LAZY);
if(!handle)
{
fputs(dlerror(),stderr);
exit(1);
}
//Hozzaferunk acreateszimbolumhoz.
createFuncP tr=(create_t)dlsy m(handle,"create");
if((error=dlerror())!=NULL)
{
fputs(error,stderr);
exit(1);
}
//Hozzaferunk adestroy szimbolumhoz.
destroy FuncP tr=(destroy _t)dlsy m(handle,"destroy ");
if((error=dlerror())!=NULL)
{
fputs(error,stderr);
exit(1);
}
doublex=4.2 ;
//Letrehozunk egy Roundertipusuobj ek tumot
Rounder*r=(*createFuncP tr)();
coutr->Round(x)endl;
//Felszabaditj uk aRounderobj ek tumot
(*destroy FuncP tr)(r);
73
3. fejezet: Programknyvtrak ksztse
//Felszabaditj uk ak ony v tarat
dlclose(handle);
}
A dlsym visszatrsi rtkt explicit tpuskonverzival kell az adott tpusra
alaktani, mert a C++ a C nyelvvel ellenttben szigoran tpusos nyelv.
Fordtskor azonban linkertl jv hibazenetet kapunk:
(.text+0x107): functionmain':
undefinedreferenceto'Rounder::Round(double)
1
collect2 :ldreturned1exitstatus
A linker nem kpes elrni a tagfggvnyt, mert az a programknyvtrban
van definilva. Nem dinamikusan betlttt knyvtr esetn a linker megta-
llta a teljes osztlydefincit a programknyvtrban, itt azonban linkelsi
idben nem tudunk semmit a fggvny implementcijrl, gy annak cmrl
sem. A linker teht joggal jelzi, hogy nem tallja a fggvnyt. Eddigi ismere-
teink alapjn mshogyan is eljuthattunk volna erre a kvetkeztetsre: mr
egyszer fggvnyek esetben is a fggvnypointer alapjn tudtunk hozz-
frni a fggvnyekhez, itt azonban csak az osztlyhoz frnk hozz mutat-
val, a fggvnyhez nem.
Ltszlag ekkor el is akadunk, hiszen visszartnk a kiindulsi probl-
mhoz: C++-tagfggvnyekhez nem tudunk pointeren keresztl hozzfrni,
mskpp pedig a linker problmt jelez. Ha az implementcit belerjuk a
fggvnyekbe, akkor mr az egsz osztlyt temeltk a fprogramba. Egy
olyan megoldsra van szksgnk, amely esetn
nem kell megadnunk a fggvny trzst, csak a deklarcijt,
mgis tudunk pointert definilni az osztlyra, s meg tudjuk hvni a
fggvnyeit.
A C++-ban a tisztn virtulis fggvny pontosan ilyen nyelvi konstrukci.
Vagyis ltrehozunk egy kizrlag virtulis fggvnyeket tartalmaz absztrakt
osztlyt, amelyet mind a fprogramban, mind a programknyvtrban defini-
lunk. A ltrehozst vgz fggvny ugyanakkor egy leszrmazott osztlyt pl-
dnyost (az absztrakt osztlyt nem is tudn), s ezt adja vissza az absztrakts-
osztly-tpus mutatn keresztl. Mindezek fnyben a programknyvtrat az
albbiak szerint valsthatjuk meg. A kzs rounder.h tartalmazza az abszt-
rakt osztlyt s a nvelferdts nlkli fggvnyeket:
cl ass Rounder
{
public:
v irtualintRound(double)=0;
v irtual~Rounder(){ }
;
74
3.3. Megosztott knyvtrak C++ nyelven
extern "c" Rounder*create();
extern"C"v oiddestroy (Rounder*);
ty pedefRounder*(*create_t)();
ty pedefv oid(*destroy _t)(Rounder*);
Mivel az osztly leszrmazottjait Rounder tpus pointeren keresztl szaba-
dtjuk fel, virtulis destruktort is definilunk. Elviekben ez is lehetne tisztn
virtulis, de a C++-ban a tisztn virtulis destruktor szintaxisa meglehetsen
tlthatatlan. A programknyvtrat gy implementltuk:
#include<math.h>
#include<stdioh>
#include"rounderh"
classupRounder:publicRounder
{
intRound(double);
};
intupRounder::Round(doublex)
doubleix;
ix=(int)x;
returnix<x?ix+1:ix;
extern"C"Rounder*create()
{
returnnewUpRounder();
extern "c" v oiddestroy (Rounder*obj ect)
deleteobj ect;
Leszrmaztattunk egy UpRounder osztlyt, s abban adtuk meg az imple-
mentcit. A create fggvny egy ilyen osztlyt hoz ltre, s Rounder tpus
mutatknt adja vissza. A fprogram a leszrmazottbl annyit lt", ameny-
nyit a Rounder sosztly megmutat.
Ez a megolds elg rugalmas. Ha tbb kerektsi algoritmusunk van,
mindegyiknek szrmaztatunk egy osztlyt a Rounder osztlybl (pldul a
DownRoundert, amely lefel kerekt), s hozzadjuk az implementcit.
A create fggvnyt paramterezni lehet (pldul az eddigi roundingMethod
paramtert adjuk neki t, s az ennek megfelel algoritmust tartalmaz osz-
tlyt pldnyostja). A fprogramot ehhez egyltaln nem kell mdostani. Ha
binris (lefordtott) formban szeretnnk kzreadni az algoritmusainkat, akkor
75
3. fejezet: Programknyvtrak ksztse
egy algoritmus egy megosztott knyvtrba kerlne, s a fprogram
pluginPatha
nem konstans lenne, hanem az algoritmusnak megfelel programknyvtrne-
vet tartalmazn.
Nagyon fontos a felszabadts krdse. Lthattuk, hogy az objektumokat
csak pointeren keresztl rhetjk el. Ez egyben sokszor dinamikus memria-
kezelst is jelent, amely knnyen memriaszivrgshoz vezethet. Itt azonban
nem azrt hasznlunk pointereket, hogy a felhasznland memria mrett
futs kzben hatrozzuk meg. Ha a fprogramban definiltuk volna az osz-
tlyt, egy loklis vltoz is elegend lett volna. A mutatk jelenlte magbl a
mechanizmusbl ered: a polimorfizmus C++-ban pointeren keresztl rhet
e1,
37
amelyhez a tisztn virtulis fggvnyek adta lehetsgeit hasznltuk ki
a megoldshoz. Vagyis pointert kell visszaadnunk, hogy mkdjn az imple-
mentcivlasztst lehetv tv polimorfizmus a dinamikus betltsnl. Mivel
loklis vltozra nem adhatunk vissza pointert, erre a problmra egy lehets-
ges megolds a dinamikus foglals s felszabadts. Egy msik megoldsknt
termszetesen ltrehozhatunk globlis vltozkat, tmbket, ekkor arra kell
figyelnnk, hogy a fprogram ne hvjon delete-et a pointerekre. A dinamiku-
san ltrehozott pointereket esetleg tmbben trolhatjuk, s a programknyv-
tr destruktorfggvnyben felszabadthatjuk a htrahagyott objektumokat.
tmutat
Mindig klns vatossggal kell kezelnnk a programknyvtrban dinamikusan le-
foglalt objektumok felszabadtst.
Ha tbb program hasznlja ugyanazt a programknyvtrat, ez nem jelent k-
lnsebb bonyodalmat: a programknyvtrak adatterlete minden program
szmra kln, egymstl fggetlenl ltrejn (mg a fggvnyeken belli
statikus vltoz is). A szlak ugyanakkor osztoznak az adatterleten, ilyen-
kor ugyanahhoz az objektumhoz val konkurens hozzfrst szablyozni kell.
Ha egy objektumot tbben hasznlnak, rdemes referenciaszmllst beve-
zetni, pldul a szabvnyos shared_ptr C++-sablon hasznlatval.
Felmerlhet a krds, hogy mirt kell ezt ilyen bonyolultan csinlni. Mi-
rt kell absztrakt osztlyt ltrehoznunk, s mirt kell az osztlyhoz pointeren
keresztl hozzfrnnk? Nem lehet a dinamikus betltst kiegszteni egy
olyan funkcival, amely le tudja krdezni, hogy milyen osztlyok vannak egy
programknyvtrban, annak milyen metdusai vannak, illetve ltrehozha-
tunk-e egy pldnyt az adott nev osztlybl, s meghvhatnnk egy adott
nev fggvnyt? A vlasz rviden: nem. Sajnos mindez a C++ nyelv megk-
tseibl ered.
38
A C++ nyelv fordtsnl az osztlyok adatstruktri elvesz-
37
Elrhet referencin keresztl is, de az mg tbb problmt okoz a felszabadtsnl.
38
Persze a C++ nyelvet ki lehetne egszteni ezekkel a funkcikkal. Ugyanakkor a nagyobb
szoftvercgek gy gondoltk, hogy rdemesebb ltrehozni egy teljesen j krnyezetet,
amely ezeknek a kihvsoknak jra tgondoltan, j gondolkodsmdot tmogatva felel
meg. A Sun kifejlesztette a Java nyelvet, mg a Microsoft (az elbbitl nem teljesen fg-
getlenl) a .NET platformot valstotta meg.
76
3.4. A megosztott knyvtrak mkdsi mechanizmusai
nek, az adathozzfrs, illetve a fggvnyhvs csak a kezdcmek (pl. this) s
a memriacm-klnbsgek (eltolsok") szintjn trtnik meg, s ezekbl az
eredeti adatstruktra nem llapthat meg. A linkels fzisban a fggvny-
nevek s a globlis szimblumok mg megjelennek (azrt lehet nv szerint le-
krdezni ket), viszont az osztlyokra vonatkoz informci mr nincsen meg.
Ez nem is annyira meglep, hiszen a linkert alapveten a C nyelvhez ksz-
tettk, s ksbb egsztettk ki a C++-hoz szksges funkcionalitssal.
Mindezekbl kvetkezik, hogy az osztly elrshez s a hvshoz szks-
ges informcit mind a fprogram, mind a kliens oldaln meg kell adnunk
(ezt tartalmazza a .h llomny osztlydefincija, valamint a globlis fggv-
nyek prototpusa), mert ezt a fordts sorn a fordtnak le kell kpeznie c-
mekre s eltolsokra, lehetleg mindkt oldalon ugyangy. Ha az osztlyhoz
hozzvesznk egy j tagvltozt vagy egy virtulis tagfggvnyt, megvltoz-
hatnak az eredeti eltolsok. Ezrt klnsen figyeljnk arra, hogy amit pl-
dnk sorn is kvettnk kln .h llomnyban adjuk meg a mindkt oldalon
hasznlt absztraktosztly-defincit, s mindkt oldalon ugyanazt az llo-
mny hasznljuk, klnben a lefordtott program s a programknyvtr flre-
cmzi a memrit. Vagyis ha egy j verzit szeretnnk ltrehozni a kerektsi
algoritmusbl, a fprogrambl pedig nem, akkor az absztrakt osztlyt ne vl-
toztassuk meg, klnben a fprogramot is jra kell fordtanunk. Ha viszont
meg tudjuk oldani azt, hogy ugyanabbl az absztrakt osztlybl szrmazta-
tunk le a programknyvtr jabb verziiban is, a programknyvtrat rugal-
masan, a fprogramtl fggetlenl cserlhetjk. Ezrt ebben az esetben nem
vltoztatjuk meg a programknyvtr f verziszmt.
tmutat Ha a knyvtrbl j verzit adunk ki, ellenrizzk, hogy az eredeti programmal
megegyez absztrakt osztlyt hasznl-e. Ha nem, a fprogramot is jra kell fordtanunk, s
abbl is j verzit kell kiadnunk, valamint a programknyvtr f verziszmt is meg kell vl-
toztatnunk.
3.4. A megosztott knyvtrak mkdsi
mechanizmusai
Az eddigiek alapjn lthat, hogy a dinamikus programknyvtrak miatt a
linkels s a programbetlts kztt nehz les hatrt hzni. Ezrt a rszlete-
sebb trgyalst a linkertl kezdjk. Elszr bemutatjuk egy olyan nll
program betltst, amely nem tartalmaz megosztott knyvtrat. Ez a linke-
ls s betlts legegyszerbb esete. Utna megvizsgljuk, hogyan mkdik
ugyanez a folyamat megosztott, illetve dinamikus knyvtrak esetben. Azt
felttelezzk, hogy itt a fordt s a linker kimenete az Executable and Link-
able Format (ELF) llomnyformtumot kveti, s ez legtbbszr teljesl is.
77
3. fejezet: Programknyvtrak ksztse
3.4.1. A betlttt program
A linkels s a betlts folyamatnak megrtshez vizsgljuk meg elszr
azt, hogy milyen krnyezetbe kell betltennk a programot. Eltekintve az
egyszerbb, fknt begyazott rendszerekben hasznlatos architektrktl, a
hardver biztostja a virtulismemria-kezelst (lsd a 2.4. Memriakezels al-
fejezet). Rviden ez a kvetkez'ket jelenti. A szoftver (belertve a gpi kd
szintet) virtulis cmekkel dolgozik, amelyet a hardver laptblkon keresztl
a fizikai memrira kpez le. Minden processznek kln virtulis cmtarto-
mnya van, amelyhez csak a processz frhet hozz. Amikor az opercis rend-
szer vlt a processzek kztt, a taszkvlts rszeknt betlti az aktuliss vl
processz virtulis cmtartomnyt. Amikor egy processz elindul, a Linux res
virtulis cmtartomnyt rendel hozz. Ebbe az res cmtartomnyba csak
a kernel kpzdik le, m csak a cmtartomny vgre. Ez lehetv teszi, hogy
a linker egy lland kezdcmre betltd programot ksztsen.
A program betltshez ugyancsak kihasznljuk a virtulis memria adta
lehetsgeket. A lapkezels virtulis trkezels esetben nemcsak az ltal-
nos swapterletre kpezhetnk le egy lapot, hanem egy llomny-rendszerbeli
llomny adott rszre is, vagyis magra a betltend programot tartalmaz
llomny egyes rszeire. Ez azt jelenti, hogy az llomny a memrialap swap-
terletv vlik. A virtulismemria-kezelssel sszhangban, amikor elszr
hozzfrnk a laphoz, akkor laphiba generldik, s az llomny betltdik a
memriba. Ha vltoztatjuk a memria tartalmt, az llomny csak akkor
vltozik, amikor a virtulismemria-kezel rendszer lecserli a lapot, s a
vltozsokat kirja az llomnyba. gy az llomny nincs mindig szinkronban
a memrival. A memriakezel egy egyszer vdelmi mechanizmust is lehe-
tv tesz, amely egyben hatkonysgnvelst is eredmnyezhet. Egy lap lehet
csak olvashat, csak rhat, rhat s olvashat, illetve ezek kombinlhatk a
futtathat tulajdonsggal. Ha ezeket a szablyokat megsrtjk, jelzst ka-
punk (segmentation fault). A csak olvassra hasznlt memrialapot nem kell
visszarni az llomnyba: vagyis egy csak olvashat s futtathat lap idelis
vlaszts a program futtathat kdjnak a betltsre. Ehhez termszetesen
arra van szksg, hogy a betltend llomny strukturlva legyen: a futtat-
hat kdot kln, folytonos szekcikban (section) kell trolnunk, amelyhez
memrialapokat rendelhetnk. A kdot tartalmaz szekcikhoz egy csak ol-
vashat s futtathat lapot rendelnk. Ha a program megprblja fellrni a
sajt kdjt, azonnal hibt kapunk: ez biztonsgosabb teszi a futtatst eset-
leges pointerhibk, illetve tmadsok esetn. A program adatterlett azon-
ban mr nem tudjuk ilyen egyszeren kezelni.
Ha az adatokat tartalmaz lapot olvashatknt s rhatknt jelljk
meg, akkor a vltoztatsok megjelennek a programot tartalmaz llomny-
ban is, ez pedig egyrtelmen nem kvnt mellkhats. Erre megolds lehet a
msols rskor (copy-on-write) mdszer, amely a vltozst az eredeti llo-
mny helyett a swapterletre rja ki. Ez a technika az els memriarsi m-
78
3.4. A megosztott knyvtrak mkdsi mechanizmusai
veletig ugyangy mkdik, mint a csak olvashat lap. gy ez a mdszer k-
lnsen takarkos, ha az rsra mgsem kerl sor. Ha az llomnyt a msols
rskor technikjval kpezzk le a memriba mivel a memrialap vlto-
zsai az els rs utn a swapterletre rdnak ki , a vltozs csak a processz
sajt cmtern keresztl ltszik, a tbbi, ugyanazt az llomnyt lekpez fo-
lyamat nem ltja a vltozsokat. Ezrt a msols rskor lekpezst privt
lekpezsnek is nevezzk.
39
Ha a program adatokat tartalmaz szekciit r-
hat s olvashat, msols rskor lekpezssel rendeljk hozz a memrihoz,
akkor a vltozsok nem rdnak vissza az llomnyba, s csak akkor msol-
dik le a lap, ha vltoztatunk az adatokon, tovbb a memriakezel gy dnt,
hogy a lap helyre msikat hoz be a httrtrrl.
A globlis jelleg adatokat kt rszre kell vlasztanunk: az explicit m-
don, kezdeti rtket megadva inicializlt, illetve az inicializlatlan adatokra.
Az inicializlt adatot tartalmaz szekcit ugyanis memrialaphoz kell ren-
delni, mg az inicializlatlan adatnak elg egy adott mret cmtartomnyt
foglalni. Ez utbbit a C specifikcival (az inicializlatlan globlis s statikus
vltozk kezdeti rtke nulla) sszhangban a programbetlt lenullzza.
A dinamikus vltozknak fenntartott heapnek, illetve a veremnek tovbbi
adatterleteket foglalunk, ezeket nem nullzzuk le.
Termszetesen a valsgban az llomny szmos tovbbi informcit tar-
talmaz, pldul a nyomkvetst tmogat bejegyzseket, amelyekre nincs
szksg a betltshez, st nem is tltdnek be a memriba. Ezeket nem le-
foglalhat (non-allocable) szekciknak nevezzk, szemben az eddig trgyalt,
lefoglalhat (allocable) szekcikka1.
4 9
A betlttt programrl egy pillanatfelvtelt" az albbiak szerint foglalha-
tunk ssze:
4 1
Mivel a virtulis memriakezels segtsgvel gyorsthatjuk a betltst,
a programokat szekcikra osztottuk, gy klnvlasztottuk a kdot az
adattl, illetve sztvlasztottuk az adatokon bell az inicializlt s
nem inicializlt adatot.
A kdot futtathat s csak olvashat lapokhoz rendeltk, mg az inici-
alizlt adatterletet msols rskor lekpezssel rendeltk a mem-
rialapokhoz. A nem inicializlt adat szmra lapokat hoztunk ltre,
amelyeket lenullztunk.
A heapnek s a veremnek tovbbi virtuliscm-tartomnyokat foglal-
tunk le
39
Ezek a lehetsgek szmunkra is rendelkezsre llnak, rszletes hasznlatukat lsd a
4.8. llomnyok lekpezse a memriba alfejezetben.
4
A nem lefoglalhat szekcikat eltvolthatjuk a strip segdprogrammal a --strip-unneeded
kapcsol segtsgvel.
4
' Az egyes virtulismemriacm-tartomnyt s a rjuk lekpezett szekcik sszerendelst
a gdb programnv utn az info files paranccsal rathatjuk ki.
79
3. fejezet: Programknyvtrak ksztse
Minden processznek kln virtuliscm-tartomnya van, gy nem je-
lent problmt, ha kt processz ugyanazt a virtulis cmet hasznlja.
A program kezdcme teht lehet mindig ugyanaz a cm. Indtskor
a kernel res virtuliscm-tartomnyt rendel a processzhez, vagyis a
cmtartomny vgn elhelyezked kernelt leszmtva egyik virtulis
cm sem foglalt. A lnyeg az, hogy a linker s a programbetlt egy
cmben megegyezzen, ott, ahol a program kezddik, s erre a cmre
tltsk be a programot.
3.4.2. Statikus knyvtrat tartalmaz program
linkelse s betltse
Nzzk meg, hogyan jutunk el a linkertl elindulva a fenti pillanatfelvte-
lig". Mivel a kdot, az inicializlt s a nem inicializlt adatterletet meg kell
klnbztetnnk, clszer, ha mr maga a fordt klnvlasztja ket.
Az inicializlt adatot C nyelven az albbi vltozdeklarcik adjk:
charbuf[2 048];
inti,res;
structpollfdpollset[2 ];
intnumpoll=2 ;
/*Olv asasramegny tj uk apipelespipe2 allomany ok at,ha
leteznek .*/
if((fds[0]-open("pipel",O_RDONLY1O_NONBLOCK))<0)
{
perror("openpipel");
return1;
}
224
/*Felszabaditj aamutex-et. Az el obbi parj a. */
templ ate<cl ass Type>
voi d fo<Ty pe>::unlock ()
pthread_mutex_unlock (&cri ti cal _secti on_mu tex) ;
- - -
5.5. POSIX-szinkronizci
/*rorolj uk ataroltadatok at.*/
if(data!=NuLL)delete[]data;
data-NULL;
elements=0;
/*Felszabad tj uk amutex-et.*/
unlock 0;
Kzben figyelnnk kell arra, hogy hiba esetn visszatrs eltt elengedjk a
mutexet:
template<classTy pe>
int Fi fo<Ty pe>::pop(Ty pe&ret)
/*Lev edj uk ak r tik usmuv eletek et.*/
lock ();
/*Megv izsgalj uk v an-ev arak ozoelemaFIFO-ban.*/
i f(!elements)
t
/*Hibaesetenfelszabad tj uk amutex-etesv isszaterunk .*/
unlock ();
return-1;
Hasonlan vgig kell nznnk minden egyes utastst, nehogy vletlenl
visszatrjnk a mutex elengedse nlkl: ez a megolds rengeteg hibale-
hetsget rejt magban. A lefoglalst s az elengedst most kt fggvny vgzi:
it
template<classTy pe>
v oidFifo<Ty pe>::lock ()
{
pthread_mutex_lock (&critical_section_mutex);
}
Erre biztonsgosabb felhasznlni a C++ konstruktor/destruktor mechaniz-
must: runk egy olyan osztlyt, amelynek a konstruktora lefoglalja a para-
mterknt kapott mutexet, a destruktora pedig felszabadtja:
225
5. fejezet: Prhuzamos programozs
class Lock
{
pthread_mutex_t* mutex;
public:
Lock(pthread_mutex_t* mutex):
mutex(mutex){pthread_mutex_lock(mutex);}
Lock(){pthread_mutex_unlock(mutex);}
};
Fontos, hogy a mutexet pointerknt vesszk t, mert a ler nem msolhat.
Ezek utn az sszes /ock0 hvst kicserljk az albbi sorra:
Lock 1 ock(&cri ti cal_section_mutex) ;
A felszabadtst automatikusan elvgzi a destrukort, amikor a vezrls el-
hagyja azt a blokkot, amelyben a lock vltozt definiltuk. Nem kell figyel-
nnk sem a visszatrsre, sem a kivtelekre.
rdemes tgondolnunk a destruktort is. Ennek implementcija a kvetkez:
template<class Type>
Fi fo<Type>: : Fi fo ()
if(data!=NULL) delete[] data;
pthread_mutex_destroy(&critical_section_mutex);
Amikor a destruktor meghvdik, akkor komoly problma lenne, ha a felsza-
badtskor msik szlbl mg szeretnnk hasznlni a trolt. Ennek biz-
tostsra szmos megolds ltezik, pldnkban a trol felszabadtst az
sszes hasznl szl kilpse utn vgezzk. Ezzel sszhangban a tesztelst
vgz szlakat az albbiak szerint implementltuk:
class FifoThread: public Thread
int start; // Ettol szamolunk
int end; // Eddig
static Fifo<int> sharedFifo;
public:
FifoThread(int start, int end):start(start), end(end){}
void Threadmain()
for(int i=start; i<=end; i++)
sharedFifo.push(i);
cout i " pushed" endl;
226
5.5. POSIX-szinkronizci
sleep(1);
sleep(1);
for(int i=start; i<=end; i++)
{
int a;
if(sharedFifo.pop(a) 0)
{
coutaendl;
sleep(1);
}
}
1;
A FIFO-t statikusan hozzuk ltre, gy a szlak elindtsa eltt ltrejn, s
utna szabadul fel, majd egyszeren elrhet mindkt j szlbl. Ha az inici-
alizlst az egyik szlbl vgeznnk, akkor az 5.4.4. Szlbiztos fggvnyek al-
fejezetben bemutatott egyszeri inicializls stratgijt kellene hasznlnunk,
vagy statikusan kellene inicializlni a mutexet.
Ezek utn a main() fggvnynk egyszeren implementlhat:
Fi fo<int> Fi f0Thread::sharedFifo;
int main()
II
FifoThread t1(0,5), t2(10, 15);
t1. start();
t2 Start();
tl.Join();
t2.loin();
return 0;
5.5.2. Feltteles vltozk
A feltteles vltozk (conditional variable) arra szolglnak, hogy rtestst
kldjnk egy mutexszel vdett megosztott erforrs llapotnak megvltoz-
srl, illetve erre az rtestsre vrakozni tudjunk. Ennek illusztrcjaknt
nzzk meg a kvetkez szitucit.
Feladat Egy egsz tpus szmll llapota arnyos egy vztartly vzszintjvel, amelyet egy
adatgyjt szl folyamatosan frisst a szenzorok alapjn. Ha a szmll elri a 10-es rtket, egy
msik, monitoroz szlbl rjunk ki egy figyelmeztetst a terminlra, ha pedig elri a 15-s szin-
tet, a monitoroz szl szltsa fel az szni nem tudkat, hogy hagyjk el a gyr terlett.
227
5. fejezet: Prhuzamos programozs
A fenti plda implementcijban az adatgyjt szl foglalkozik a tartly l-
lapotval, s frissti a megosztott erforrst: az unsigned int tpus szmllt.
Tegyk fel, hogy a tartllyal foglalkoz szlakat csak adatgyjtsre hasznl-
juk, ezrt nem implementlhatunk benne sszetett logikt. Ezrt a szmll
llapott egy kln monitoroz szlbl ellenrizzk, s ugyaninnen kldjk a
figyelmeztetseket. Mivel a szmllhoz tbb szl is hozzfr, ezrt azt egy
mutex vdi. Amikor a monitoroz szl olvasni szeretn a vltozt, lefoglalja a
mutexet. m ha egyfolytban olvasgatja az rtket, s fogva tartja a mutexet,
akkor a tartly llapott frisst adatgyjt szlak nem tudjk lefoglalni a
mutexet, gy nem tudjk megvltoztatni a szmll rtkt. Vagyis minden szl
a msikra vr, mikzben a gyrat lassan, de annl hatrozottabban elbortja
a vz. J lenne, ha az ellenrz szl nem ellenrizn s foglaln folyamatosan a
mutexet, hanem az adatgyjt szlak rtestenk arrl, hogy megvltozott
a szmll rtke, s ahogy az esemny bekvetkezik, egy atomi mvelettel
felbredne, s vissza tudn szerezni a mutexet. Erre hasznlhatjuk a feltteles
vltozkat. A feltteles vltozkon kt mvelet vgezhet, az egyik a vrakozs
a jelzsre, a msik maga a jelzs.
77
A feltteles vltoznak nincs llapota, csak
ppen a jelzs pillanatban vrakoz szlak kapjk meg a jelzst. Pldnkban
az adatgyjt szlak egy feltteles vltoznak jeleznek, a monitoroz szlak
pedig a feltteles vltoz jelzsre vrakoznak. Ebben az esetben csak a 10-es
s 15-s rtknl jelznk, de ha nem akarjuk az adatgyjt szlat terhelni a
riaszts logikjval, akkor minden egyes alkalommal, amikor egy adatgyjt
szl megvltoztatja a vzszint rtkt, ezt jelezhetjk a feltteles vltoznak.
Rszletesen ez az albbiakat jelenti.
1. A monitoroz szl lefoglalja a mutexet.
2 . Ellenrzi, hogy meghaladta-e a 10-es vagy 15-s rtket, s aszerint
reagl.
3. A monitoroz szl egy atomi mvelettel elengedi a mutexet, s vra-
kozik a feltteles vltozra. Azrt van szksg az atomi mveletre,
nehogy egy vagy tbb adatgyjt szl kzben lefoglalja a mutexet,
megvltoztassa az rtkt, a monitoroz szl pedig lemaradjon a jel-
zsrl. A mutex 1. pontbeli lefoglalsa s az atomi mvelet egytt biz-
tostja azt, hogy ha egy szl elhatrozza, hogy vrakozik egy feltteles
vltozra, akkor a mutex lefoglalstl szmtva nem fgg az idz-
tstl az, hogy lemarad-e egy jelzsrl.
4 . A monitoroz szl a feltteles vltozra vrakozik, a mutexet nem
tartja fogva, ezrt egy adatgyjt szl lefoglalhatja, ez meg is trt-
nik, ha a vzszint indokoltt teszi. A vzszintszmll vltoz 10-es
vagy 15-s rtke esetn az adatgyjt szl jelez a feltteles vltoz-
nak, s elengedi a mutexet. Ezt tehetn fordtott sorrendben is, a
POSIX mindkt megoldst megengedi.
77
A feltteles vltozval kapcsolatban hasznlt jelzseknek nincs kzk a processszek k-
ztti kommunikcira hasznlt jelzsekhez (ezeket lsd az 5.6. Jelzsek alfejezetben).
2 2 8
5.5. POSIX-szinkronizci
5. A feltteles vltoz jelzsre vrakoz monitoroz szl felbred, auto-
matikusan mr birtokban van a mutex, s az 2 . ponttl folytatdik a
forgatknyv.
Nagyon fontos odafigyelnnk arra, hogy bredskor a monitoroz szl ellen-
rizze a feltteleket. Jllehet beleptettk az adatgyjt szlba, hogy csak ak-
kor szljon, ha a szmll rtke meghaladta a 10-es vagy a 15-s rtket,
nem felttelezhetjk, hogy ez gy is van. Ennek tbb oka lehet.
A feltteles vltozra vrakoz szlat az opercis rendszernek joga
van mindenfle jelzs nlkl felbreszteni. Ezt flsleges bresz-
tsnek (spurious wakeup) nevezzk, s ennek oka a feltteles vlto-
zk hatkony implementlsa tbbprocesszoros rendszeren.
Amikor az adatgyjt szl elengedi a mutexet a 3. pontban, egy msik
adatgyjt szl felbredhet, s akr cskkentheti is a vzszintet.
Ha pldnkban ms szl is vrakozna a feltteles vltozra, s az
elbb szerzi meg a mutexet, megvltoztatn a vltoz rtkt, mire a
mutexet msodkknt megszerz monitoroz szl hozzfr.
tmutat A feltteles vltozra val vrakozsbl felbredve a szlak mindig jra teszteljk
le a felttelt a megosztott erforrson, ne bzzanak a jelzsklds felttelben.
Ezek utn vegyk sorra a feltteles vltozhoz tartoz fggvnyeket. A mu-
texekhez hasonlan feltteles vltozkat ltrehozhatunk statikus inicializ-
lssal s inicializlfggvnnyel. A statikus megoldst az albbi kdrszlet
szemllteti:
sincl ude <pthread . h>
pthread_cond_t cond =P THREAD_COND_INITIALIZER;
Egybknt pedig a
#include <pthread.h>
i nt pthread_cond_init(pthread_cond_t *cond,
pthread_condattr_t "cond_attr);
fggvnnyel nicializljuk a feltteles vltozt, ahol ha a cond_attr NULL, ak-
kor a feltteles vltoz az alaprtelmezett attribtumokkal jn ltre. Az attri-
btumot a thread_condattrint fggvnnyel inicializlhatjuk, s a pthread_
condattr_destroy fggvnnyel kell felszabadtanunk. Az attribtumrtkek
kzl azt llthatjuk be, hogy processzek vagy szlak kztt akarjuk-e hasz-
nlni a feltteles vltozt (pthread_condattr_getpshared, pthread_condattr_
setpshared fggvnyek).
229
5. fejezet: Prhuzamos programozs
Inicializlfggvnnyel ltrehozott feltteles vltozt a
#include<pthread.h>
intpthread_cond_destroy (pthread_cond_t*cond);
fggvnnyel szntethetnk meg. Ekkor egy szl sem vrakozhat a feltteles
vltozra.
Jelzst a
#include<pthread.h>
i ntpthread_cond_signal(pthread_cond_t*cond);
fggvnnyel kldhetnk. Ezt akkor rdemes hasznlnunk, ha elg, hogy a
vrakoz szlak kzl egyetlen, tetszleges szl kapjon rtestst.
Ha azt szeretnnk, hogy az olyan sszes szl, amely egy feltteles vltoz-
ra vrakozik, megkezdje futst, akkor a
#include<pthread.h>
intpthread_cond_broadcast(pthread_cond_t*cond);
fggvnyt hasznljuk Ennek a fggvnynek az esetben az sszes, a jelzs pil-
lanatban vrakoz szl felbred, s vrakozni kezd a mutexre. A sorrend nincs
meghatrozva, Ilyenkor is elfordulhat, hogy valamelyik szl megvltoztatja a
megosztott erforrst, s a felttel a msodikknt hozzfr szl esetben mr
nem lesz igaz. Ezrt hangslyozzuk ismt, hogy a feltteleket a felbred sz-
laknak mindig ellenriznik kell.
Ha vrakozni szeretnnk egy feltteles vltozra, akkor a
#include<pthread.h>
intpthread_cond_wait(pthread_cond_t*cond,
pthread_mutex_t*mutex);
fggvnyt hasznljuk. A fggvny meghvsa eltt le kell foglalnunk a mu-
texet, majd a meghvs utn el kell engednnk, ugyanis visszatrs eltt ez a
fggvny visszaszerzi", azaz jra lefoglalja a mutexet.
Ha csak meghatrozott ideig szeretnnk vrakozni, akkor a
#include<pthread.h>
intpthread_cond_timedwait(pthread_cond_t*cond,
pthread_mutex_t*mutex,
conststructtimespec*abstime);
2 3 0
5.5. P051X-szinkronizci
fggvnyt hasznljuk a cond s a mutexargumentum szempontjbl ugyan-
gy, mint a pthread_cond_wait hvst. Az egyetlen klnbsg az, hogy a fgg-
vny az abstime argumentumban megadott idnl tbbet nem vr, hanem jra
lefoglalja a mutexet, s ETIMEDOUT rtkkel tr vissza. Az id 10 msod-
percre val belltst a kvetkez plda szemllteti:
structtimev alnow;
structtimespectimeout;
gettimeofday (&now);
timeout.tv _sec=now.tv _sec+10;
t meout.tv _nsec=now.tv _usec*1000;
A fentiek fnyben a plda egy leegyszerstett megoldsa az albbi lehet. El-
sknt a monitoroz szlat mutatjuk be:
unsignedintcounter=0;
pthread_mutex_tmutex=P THREAD_MUTEX_INITIALIZER;
pthread_cond_tcondv ar=P THREAD_COND_INITIALIZER;
v oid*monitor_thread(v oid*arg)
unsigned ntc;
pr ntf("Amonitorozoszalindul...\n");
pthread_mutex_lock (&mutex);//1.Mutexlefoglal sa
while(1)
{
if(counter==10)//2 .Felt telek ellenrz se
printf("!F gy elem:v zszint!\n");
}
elseif(counter==15)
{
break ;
}
pthread_cond_wait(&condv ar,&mutex);//2 .v rak oz s
}
pthread_mutex_unlock (&mutex);//Kilepesk orelengedni
printf("!!!Katasztrofatortent!!!\n");
returnNULL;
231
5. fejezet: Prhuzamos programozs
Figyeljnk oda, hogy a flsleges bresztsek miatt a vrakozs mindig cik-
lusban trtnik, s mindig ellenrizzk a felttelt. A fprogram az adatgyjt
szlat szimullja:
ntmain()
{
pthread_tmy thread;
inti;
i f(pthread_create(&my thread, NULL, mon tor_thread, NULL))
fprintf(stderr,"Hibaaszalletrehozasanal.\n");
exit(1);
}
/*Szimulalj uk av izszintv altozasat.*/
for(i=0;i<2 0;i++)
sleep(1);
pthread_mutex_lock (&mutex);
//Aszamlalonov elese
counter++;
printf("Aszamlaloallasa:%u\n",counter);
if(counter==10IIcounter-15)
printf("]elzesk uldese...\n");
pthread_cond_broadcast(&condv ar);
printf("v isszak apj uk amutexet...\n");
pthread_mutex_unlock (&mutex);
}
if(pthread_j o n(my thread, NULL))
{
fprintf(stderr,"Hibaaszalmegv arasanal.\n");
exit(1);
return0;
Jelen pldnkban elhelyeztnk egy sleep hvst, amely leth'bb tette a szimu-
lcit, de mg fontosabb, hogy a fszl nem fejezte be a szimulcit a monitroz
szl indulsa eltt. Ha meg szeretnnk vrni a szl indulst, ahhoz ltreho-
zunk egy boolean vltozt, ezt mutexszel vdjk, s feltteles vltozval vra-
kozunk a megvltozsra. Amikor a szl tlltotta a boolean vltozt, jelez a
fszlnak, erre az felbred, ellenrzi, hogy a a vltoz tnyleg t lett-e lltva,
s ha igen, fut tovbb. Tbb szl esetn boolean helyett unsigned int vltozt
hasznlunk, amelyet mindegyik indul szl megnvel.
2 3 2
5.5. POSIX-szinkronizci
A feltteles vltozk esetn a mutex s a feltteles vltoz kztt szoros
kapcsolat van.
tmutat Ugyanarra a feltteles vltozra vrakozva soha ne adjunk meg klnbz mutere-
ket, mert az eredmny nem definilt.
Ugyanakkor egy mutexhez tbb feltteles vltoz is tartozhat, ha tbbfle r-
testst szeretnnk kldeni.
5.5.3. Szemaforok
Szemben a System V IPC szemafortmbjvel a POSIX-szemaforok egyetlen
szinkronizcis objektumot jelentenek, amelyeket mind processzek, mind sz-
lak kpesek hatkonyan hasznlni. Ahogy sz volt mr rla, a System V IPC-
hvsok egy kzs nv alapjn osztottk meg a szinkronizcis objektumokat.
Az eddigi POSIX szinkronizcis objektumok esetben ltrehozskor a pro-
cesszek kzti megosztst engedlyez atttribtumot kell belltanunk, s
megosztott memriaterleten kell ltrehozni ket. POSIX-szemaforok eset-
ben mindkt lehetsg adott. Az els esetben a szemafornak egy / karakterrel
kezdd nevet adunk, ilyenkor megnevezett szemafornak (named sema-
phore) nevezzk. A msodik esetben csak egy memriacmen lv ler azono-
stja a szemafort, ezek a nvtelen szemaforok (unnamed semaphore).
Nvtelen szemafort a kvetkez fggvnnyel hozhatunk ltre:
#include semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Ha a pshared nem 0, akkor a szemaforhoz ms processzek is hozzfrhetnek,
egybknt csak az adott processz szlai. A szemafor rtke a value param-
terben megadott szm lesz.
Megnevezett szemafort az albbi fggvnnyel hozhatunk ltre:
finclude <semaphore.h>
sem_t *sem_open(const char *name, int oflag, ...);
Az els paramter a szemafor neve, a msodik a megnyits jelzbitjei az l-
lomny megnyitsnl megismert O_CREAT s O_EXCL, amelyekhez az
fcntl.h llomnyt is be kell ptennk. Ha az O_CREAT jezl'bitet belltjuk,
akkor egy harmadik s egy negyedik paramtert is meg kell adnunk. Ekkor a
fggvny prototpusa gy nz ki:
233
5. fejezet: Prhuzamos programozs
sem_t*sem_open(constchar*name,intoflag,mode_tmode,
unsignedintv alue);
_ _
A tovbbi paramterek a jogosultsgok s a szemafor kezdeti rtke.
Vegyk sorra a mveleteket. Egy sem szemafor rtkt a
#include <semaphore.h>
intsem_wait(sem_t*sem);
intsem_try wait(sem_t*sem);
"aele ~1~ 11~el
fggvnyekkel cskkenthetjk eggyel. Ha a sem szemafor rtke pozitv,
mindkt fggvny eggyel cskkenti az rtkt, s visszatr 0-val. Ha a sze-
mafor rtke 0, a sem_trywait azonnal visszatr EAGAIN rtkkel, mg a
sem_wait vrakozik a szemafor pozitv rtkre. Ez utbbi vrakozst vagy
a szemafor llapota (az rtke nagyobb lesz, mint nulla), vagy egy jelzs sza-
kthatja meg.
A szemafort rtkt hasznlat utn a
#include<semaphore.h>
intsem_post(sem_t*sem);
fggvnnyel nvelhetjk eggyel. A szemafor aktulis rtkt a
#include<semaphore.h>
intsem_getv alue(sem_t*sem,int*sv al);
fggvnnyel krdezhetjk le. Ha a szemafort lefoglaltk, akkor a visszatrsi
rtk nulla vagy egy negatv szm, amelynek abszolt rtke megadja a sze-
maforra vrakoz processzek szmt. Ha a sval pozitv, ez a szemafor aktu-
lis rtkt jelenti.
Nvtelen szemafort a
#include<semaphore.h>
intsem_destroy (sem_t*sem);
11111111L~211=1 .
--
__
fggvnnyel szntethetnk meg. Megnevezett szemafort a
#include<semaphore.h>
intsem_close(sem_t *sem);
fggvnnyel zrhatunk le.
234
5.5. POSIX-szinkronizci
A megnevezett szemaforok a processz kilpsekor vagy az exec fggvnycsa-
ld hvsakor automatikusan lezrdnak. Mivel a megnevezett szemaforok
perzisztensek, a close fggvny hatsra nem szabadulnak fel, s rtkket is
megrzik. Ha a close utn jra meghvjuk a sem_open fggvnyt a nevvel,
ugyanazt a szemafort kapjuk vissza, ugyanolyan llapotban, ahogy a processzek
hagytk. A megnevezett szemafort a sem_unlink fggvnnyel trlhetjk.
A szemafor az llomnyokhoz hasnonlan nem trldik rgtn, a kernel megvrja
mg az sszes processz lezrja a lert, s utna szabadtja csak fel. Ugyanakkor
az a processz, amely a sem_unlinket hvta, mr nem nyithatja meg jra.
Feladat Ksztsnk olyan programot, amely egy repltri bejelentkezst szimull. Hozzunk
ltre egy POSIX-szemafort, ahol a szemafor a lgitrsasg pultjait jelenti. Ezttal egy nagy k-
zs sor van, s a szemafor kezdeti rtke jelzi a pultok maximlis szmt. Egy szl hozza ltre
a szemafortmbt, egy msik szl pedig a kvetkezt: menjen oda" az els res pulthoz, ha
minden pult foglalt, lljon be abba a sorba, ahol legkevesebben vrakoznak. Az utasok nem
felttlenl rkezsi sorrendben kerlnek sorra, mert a tl ksn rkez utasokat a ksbb in-
dulk elreengedhetik.
Elsknt az utasszlat mutatjuk be:
/* Globalis valtozok *7
sem_t szemafor;
`_
int utas_szamlalo=0;
void* utas_szal (void"arg)
{
nt sorsz am=" (i nt"
-
)arg ;
Free(arg):
printf("A %d. utas sorban all...\n",sorszam);
/* varakozunk a szemaforra: innen csak akkor jutunk */
/* tovabb, ha egy pult szabad lesz */
sem_wait(&szemafor);
printf("A %d. utas sorra kerult...\n",sorszam);
sleep(KISZOLGALASI_IDO) ;
printf("A %d. utas tavozott...\n",sorszam);
/* El engedjuk a szemafort
tr i
sem_post(&szemafor);
return NULL;
}
235
5. fejezet: Prhuzamos programozs
A szl megprblja lefoglalni a szemafort. Ha nem sikerl, vrakozik, vagyis
sorba ll. Ha sikerl, akkor a szemafort, vagyis a szabad pultok szmt csk-
kenti eggyel, vrakozik a kiszolglsi ideig, majd megnveli eggyel a szema-
fort, s kilp (tvozik").
A fprogram egy lehetsges implementcija az albbi:
intmain()
{
intch;
int*p_sorszam;
pthread_tszal_leiro;
/*Beallitj uk aszemaforertek et*/
sem_init(&szemafor,O,P ULTOK_SZAMA);
printf("Ny omj onu-tuj utask uldesehez,k -tak ilepeshez!\n");
do
do
ch=getchar();
} while(ch!='u'&&ch!='k ');
utas_szamlalo++;
p_sorszam=malloc(sizeof(int));
*p_sorszam=utas_szamlalo;
pthread_create(&szal_leiro,NULL,utas_szal,p_sorszam);
while(ch!='k ');
printf("P ultok atbezartak ,sorbanallok hazamennek ...\n");
return0;
}
A fprogram a felhasznli bemenet alapjn hozza ltre a szlakat, vagyis az
utasokat. Kilpskor az sszes szl megsznik, vagyis az sszes utas eltnik,
ez feladatunkban nem okoz problmt, ezrt nem vrakozunk a szlakra, gy
lerikat sem mentjk el.
5.5.4. Spinlock
Amikor egy szl nem tudja lefoglalni a mutexet, rgtn vrakoz llapotba
kerl. Amikor a mutex llapota megvltozik, akkor a szlat fel kell breszte-
ni, amely jra megprblja lefoglalni a mutexet. Ha a mutexet csak nagyon
rvid deig fogjk a szlak, akkor a vrakozs helyett rdemes rgtn jra
2 3 6
5.5. POSIX-szinkronizci
prblkozni. Ha ez sorozatosan nem sikerl, akkor az lland prblkozssal
pazaroljuk a processzoridt. Ha viszont ez rendre sikerl, akkor a vrakozs-
felbreszts idejt megtakartottuk. Pontosan ezt a forgatknyvet valstja
meg a spinlock.
Feladat Ksztsnk szlbiztos FIFO-trolt spinlockkal.
Elsknt deklarlnunk kell a spinlock objektumot, majd gondoskodnunk kell
az inicializlsrl s a felszabadtsrl.
templatecclass Type> cl ass Fi fo
pthread_spinlock_t spin;
};
/* Al apertel mezett konstruktor '/
template<class Type>
Fi fo<Type> : Fi fo()
/* Inicializaljuk a spi nlockot es a tarolo strukturakat.
*1
pthread_spi n_i ni t(&spi n , 0) ;
}
/* Destruktor */
templ a te<cl ass Type>
Fi fo<Type>: :-Fi fo ()
pthread_spi n_destroy(&spi n) ;
A Lock osztly vgzi a lefoglalst s felszabadtst:
cl ass Lock
{
pthread_spi nlock_t* spin;
publ ic:
Lock (pthread_spi n1 ock_t*spi n) :
spin(spin){pthread_spin_lock(spin);}
-Lock {pthread_spin_unlock(spin);} ;
1;
237
5. fejezet: Prhuzamos programozs
Pusztn az osztly alapjn nem tudjuk megmondani, hogy rdemes-e a mu-
texet spinlockra cserlni, hiszen az elemek kivtele s elhelyezse sorn a
hasznlattl fggen gyakori vagy nagyon ritka is lehet.
tmutat ltalban hasznljunk mutexet, hacsak nem vagyunk meggyzdve az tkzs rit-
kasgrl.
5.5.5. Tovbbi lehetsgek: POSIX megosztott
memria s zenetsorok
A POSIX megosztott memrit az shm_open fggvnnyel hozhatjuk ltre, s
az shm_unlink fggvnnyel szntethetjk meg. A megosztott memrit a pro-
cesszek a megnevezett szemaforhoz hasonlan / karakterrel kezdd nvvel
tudjk azonostani. A POSIX-zenetsorok szintn nv alapjn azonosthatk
fggetlen processzekbl, szl-gyermek viszony esetn a ler rklsvel old-
hat meg a kzs zenetsor ltrehozsa. Megnyitskor egy ler jn ltre
(mq_open). A kld- (mq_send) s az olvas- (mq_receive, mq_timedreceive)
fggvnyek a read/write-hoz hasonl buffereket vrnak. Az zenetekhez prio-
ritsokat is rendelhetnk. Az olvasfggvnyek alaprtelmezsben blokko-
ldnak, a nem blokkold zemmdot neknk kell belltani. A szemaforhoz
hasonlan ltezik lezrs (mq_close) s megszntets (mq_unlink).
5.6. Jelzsek
A jelzsek a Linux programozsnak szinte minden terletn elfordulnak,
gy az elz fejezetekben is szmtalanszor utaltunk rjuk. A jelzsek lnyeg-
ben egyidsek a Unix rendszerekkel.
A jelzs (signal) a processzek kztti aszinkron kommunikci egy form-
ja, amelynek segtsgvel egy egsz szmot lehet kldeni, s amelyet a
processz soron kvl kezel. Az aszinkron tulajdonsg azt jelenti, hogy ltal-
nos esetben a jelzst kld processz nem vrakozik a klds utn, hanem rg-
tn folytatja a futst, nem kap rtestst arrl, hogy a jelzs clba rt-e.
Minden jelzshez egy egyedi egsz szmot rendelnk, amely egytl szmoz-
dik. Az ezekhez a szmokhoz rendelt szimbolikus konstansokhoz a signal.h
llomnyon keresztl frhetnk hozz (a signum.h llomny tartalmazza
ket). A konstansok SIG eltaggal kezddnek, pldul a program futsnak
megszaktsra szolgl SIGINT a kettes sorszm szignlt jelli (#define
SIGINT 2). A soron kvli kezels azt jelenti, hogy a processz norml vgre-
hajtsa megszakad, lefut a jelzst kezel kd, majd utna folytatdik az ere-
238
5.6. Jelzsek
deti vgrehajts. E miatt a tulajdonsguk miatt a jelzseket gyakran a meg-
szaktsokhoz hasonltjk. Jllehet a jelzseket elssorban processzek kztti
kommunikcira hasznljuk, egy folyamat kldhet magnak is jelzseket. St
ez a kommunikcis forma szlak kztt is hasznlhat.
Br jelzseket brmelyik processz kldhet, a jelzsek legfbb forrsa ma-
ga a kernel. Az albbi esetekben a kernel nagyon gyakran jelzsekkel kld r-
testst.
Valamilyen hardveresemny trtnt, tipikusan hardveres megszak-
ts rkezett, s a kernel errl rtesteni szeretn a processzeket (pl-
dul idzts, nullval val oszts).
A felhasznl a terminlfelleten valamilyen specilis billentykom-
bincit nyomott le, pldul Ctrl + C SIGINT jelzst generl.
Valamilyen szoftveresemny trtnt: egy llomnyler olvashatv
vlt, soron kvli adat rkezett a hlzaton, gyermekprocessz befejez-
te a futst.
A jelzsek alapkoncepcija nagyon egyszer: egy folyamat vagy a kernel egy
egsz szmot kld a programunknak, ennek hatsra a program normlis futsa
megszakad, s a programon bell automatikusan meghvdik egy kezelfgg-
vny, amely reagl a jelzsre, vagy ha a processz nem regisztrlt kezelfgg-
vnyt, a kernel vagy figyelmen kvl hagyja, vagy egy alaprtelmezett kezel-
fggvnnyel kezeli a jelzst. Az eddigi fejezetekben pontosan gy tekintettnk a
jelzsekre. Ugyanakkor ebben a tmakrben klnsen igaz az, hogy az rdg a
rszletekben rejlik. A Unix rendszereknek meglehetsen sok ksrletezsre volt
szksge ahhoz, hogy a jelzsek megbzhat kommunikcis mdszerr vljanak,
azaz ne vesszenek el a processzek tudta nlkl. Ahhoz, hogy biztonsggal hasz-
nljuk a jelzseket, rszletesen meg kell rtennk a mkdsket s a helyes
hasznlat rszleteit. Ebben segtenek a kvetkez fejezetek.
5.6.1. A jelzsklds s -fogads folyamata
A kld processz szempontjbl meglehetsen egyszer a helyzet. A jelzs
kldsre felhasznli zemmdban a kill, tgkill, valamint a sigqueue rend-
szerhvsok valamelyikvel lehet utastani a kernelt. Jelzst egy adott pro-
cessznek, processzcsoportnak vagy szlnak lehet kldeni. Ha a processznek
nem volt joga a cmzettnek jelzst kldeni, a rendszerhvsok hibval trnek
vissza. Ezt a folyamatot jelzskldsnek (sending a signal) nevezzk.
A cmzett processz reakcijt egy jelzsre a jelzs elrendezsnek (dis-
position) nevezzk. A cmzett processz hromflekppen rendezheti el a kl-
dtt jelzst:
239
5. fejezet: Prhuzamos programozs
Figyelmen kvl hagyja: ilyenkor a processz llapota s futsa ugya-
naz marad, mintha a jelzs meg sem rkezett volna.
Lefuttat egy fggvnyt, az gynevezett jelzskezelt (signal handler).
Ezt a fggvnyt a processznek elre be kell regisztrlnia.
Hagyja, hogy a kernel egy alaprtelmezett funkcit hajtson vgre.
A jelzstl fggen a kernel alaprtelmezett funkcija hromfle lehet:
Figyelmen kvl hagyja a jelzst (F).
Terminlja a processzt Labnormal process termination", T).
A processz memriabeli s regisztereinek aktulis llapott elmenti
egy llomnyba (core dump), majd terminlja (CD).
A processz felfggesztett (STOPPED) llapotba kerl (STOP).
A processz felfggesztett llapotbl a futsra ksz (RUNNING) lla-
potba kerl (FUT).
Az egyes jelzseket s a kernel alaprtelmezett funkcijt az 5.9. tblzat tb-
lzat tartalmazza.
5.9. tblzat. A jelzsek azonostja, lersa s alaprtelmezett elrendezse
Jelzs Lers Funkci
SIGABRT Az abort0 fggvny generlja. CD
SIGALRM Egy alarmQ ltal felhzott idzt lejrt. T
SIGBUS Memria-hozzfrsi problmk. CD
SIGCHLD A gyermekprocesszt terminltk vagy felfggesz- F
tettk.
SIGCONT A processz a lellts utn folytatja a futst. FUT
SIGHUP A processz terminljt becsuktk. T
SIGFPE Lebegpontos szmtsi hiba. CD
SIGILL A processzor illeglis utastst hajtott vgre. CD
SIGINT A felhasznl megszaktskaraktert (^C) kldtt T
a terminlon keresztl.
SIGIO Aszinkron 1/0: olvashat adat rkezett. T
SIGKILL Mindenkppen terminlja a processzt. T
SIGQUIT A felhasznl kilpsi karaktert (^\) kldtt. CD
SIGPIPE A processz olyan csvezetkbe rt, amelynek nin- T
csen olvasja.
SIGPROF A profiler ltal hasznlt idzt lejrt. T
SIGPWR Tpfeszltsghiba. T
2 4 0
5.6. Jelzsek
IJelzs Lers Funkci
SIGSEGV Illeglis memriacmhez val hozzfrs. CD
SIGSTOP Mindenkppen felfggeszti a folyamat futst. STOP
SIGTERM Kezelhet (fellbrlhat) processzmegszntets. T
SIGTRAP Trspont nyomkvetshez. CD
SIGTSTP A felhasznl felfggesztskaraktert (^Z) kldtt. STOP
SIGTTIN A httrben fut alkalmazs megprblta olvasni STOP
a terminlt.
SIGTTOU A httrben fut alkalmazs rni prblt a termi- STOP
nlra.
SIGWINCH A terminl mrete megvltozott.
SIGURG Srgs I/0 esemny. F
SIGUSRI Programoz ltal definilt jelzs. T
SIGUSR2 Programoz ltal definilt jelzs. T
SIGXCPU CPU idszeletnek tllpse. CD
SIGXFSZ Fjlmret hatrnak tlpse. CD
SIGVTALRM A setitimer() ltal felhzott virtuls idzt lejrt. T
A fenti tblzatot ttanulmnyozva lthatjuk, hogy a Linux elg szigor: ha a
tipikus forgatknyv szernt ltalban kezelnnk kellene egy jelzst, akkor
a kerne] alaprtelmezsben terminlja a programot, nehogy rejtve maradjon
a hiba. Ha komoly hardverhiba trtnik, amely utn knnyen elfordulhat,
hogy a hiba feldertse rdekben nyomon szeretnnk kvetni a processzt, ott
a kernel core dump llomnyt is kszt. A processz felfggesztsvel s jra-
indtsval kapcsolatos jelzsek kezelst a terminl feledatvezrlse szerint
alaktottk ki.
A rendszer elvrt mkdse rdekben a kernel fenntartja a lehetsget,
hogy bizonyos jelzsek elrendezst ne lehessen megvltoztatni. Ezeknek a
jelzseknek a nevt vastagon szedtk a tblzatban. Ugyangy a 0 processza-
zonostj processznek nem lehet jelzst kldeni, mg az 1-es processznek
(nit) csak olyanokat tovbbt a kernel, amelyre jelzskezelt definil.
Ha egy processz jelzst kap, megszaktja a futst, s vgrehajtja az adott
jelzshez tartoz elrendezst. Mivel a pontos felttelek implementcifggk,
rdemes azzal a felttelezssel dolgoznunk, hogy brmelyik kt utasts kztt
rkezhet jelzs, s vgrehajtdhat az elrendezse. Ha a jelzskezelbl hasznl-
juk a program vltozit, a fenti felttelezs tkrben oda kell figyelnnk a ver-
senyhelyzetekre. Vegyk pldaknt az albbi pszeudokdot:
241
5. fejezet: Prhuzamos programozs
intidozito;
staticv oididozito_j elzesk ezelo
idozito=1;
I
intmain()
{
// idozito_j elzesk ezeloberegisztr l saa SIGALRM j elz sre
idozito=0;
alarm(150);//150nanoszek undummlv a SIGALRM j elz s
while(!idozito)
{
pause();//A pausefggv ny ak v etk ezj elz sigv rak ozik
I
A fenti programrszlet egy klasszikus hibt tartalmaz. A megolds alapgon-
dolata az, hogy a fprogram gy vrakozik egy meghatrozott ideig, hogy fel-
hz egy rt. Az ra a beltott id leteltvel egy SIGALRM jelzst kld.
A fprogram s a jelzskezel egy globlis vltozn keresztl kommunikl: az
idozito rtke az indulskor nulla, a jelzskezel lltja be egyre. A fprogram
addig vrakozik, amg a vltoz rtke egy nem lesz. A pause fggvny egy
jelzsre vr. A while ciklusra azrt van szksg, hogy ha ms jelzs breszte-
n fel a pause-t, akkor tovbb vrakozzunk A fenti program az esetek nagy
rszben jl mkdik. m ha az temezs ppen gy alakul, elkpzelhet,
hogy a jelzs az idzt vizsglata utn, de mg a pause fggvny meghvsa
eltt kvetkezik be. Addig, ameddig a program ms jelzst nem kap, vrako-
zik ez pedig tetszleges ideig eltarthat.
A megolds az lenne, ha bellthatnnk egy kritikus szekcit, amelynek a
futsa alatt a processz nem fogadhatna jelzseket. Viszont ha ekzben jelzs
rkezk, annak nem szabad elvesznie, ezrt egy vrakozsi sorban kell tarta-
ni. Termszetesen ennek az alapgondolatnak tbbfle varicija ltezhet, pl-
dul a vrakozsi sor feldolgozsnak sorrendje sokfle lehet, vagy egy adott
tpus jelzs tbbszri elfordulsakor csak egyet trolhatunk.
Els megoldsknt ttelezzk fel az albbi lehetsges megoldst. Minden
egyes jelzshez hozzrendelnk egy engedlyezbitet. Ha ez a bit igaz, a pro-
cessz kezeli a jelzst, ha nem igaz, akkor a kernel nem kzbesti a jelzst. Mi-
vel ez utbbi esetben a jelzs nem veszhet el, minden jelzshez fellltunk egy
vrakozsi sort is. Amikor egy nem engedlyezett jelzs rkezik, a kernel be-
leteszi ebbe a sorba Amikor a processz jra engedlyezi a jelzseket, akkor a
kernel az ppen rvnyes elrendezs szerint kzbesti a vrakozsi sorokban
tallhat jelzseket: a legkisebb rtkhz tartoz sort rti ki elszr. Ter-
mszetesen a vrakozsi sorok FIFO-jellege miatt rkezsi sorrendben
dolgozza fel egy adott sor elemeit. Az ezen az elven mkd jelzseket vals
}
242
5.6. Jelzsek
idej jelz seknek (real-time signal) nevezzk. A vals idej jelzseket
a sigqueue fggvny segtsgvel adhatjuk hozz a vrakozsi sorokhoz, a
SIGRTMIN s a SIGRTMAX kztti jelzsekkel a kezd s a vgrtket is be-
lertve. Mivel a jelzs rtke ilyenkor csak a prioritsrl rulkodik, a sig-
queue tovbbi paramterek elkldst is lehetv teszi.
Sokszor a vals idej jelzsek ltal nyjtott lehetsgeknl jval keve-
sebbre van szksgnk. Nzzk meg pldaknt azt az esetet, amikor egy
idztesemnyre szeretnnk valamilyen feladatot periodikusan elvgezni.
Elfordulhat, hogy a processzor leterheltsge miatt az esemnyek egymsra
futnak: egy esemnyre mg nem tudtunk reaglni, de az jabb mr megrke-
zett. Ilyenkor nem problma, ha arra az esemnyre, amelyrl amgy is lema-
radtunk, nem reaglunk. A torlds leegyszerstsvel szemben viszont nem
szeretnnk, ha egy jelzs elveszne. Ezalatt pontosan azt rtjk, hogy ha a jel-
zs feldolgozsnak megkezdse utn mg egy ugyanolyan jelzs rkezik, ar-
rl kln rtestst szeretnnk kapni, nem veszhet el.
Ezt rdemes gy tekintennk, hogy az egyes jelzsekhez tartoz vrako-
zsi sor egyelem, vagyis egyszerre egy adott tpusbl csak egy feldolgozatlan
jelzst tudunk trolni. Az gy mkd jelzseket ha gyom nyos jelz seknek
(traditional signals) nevezzk. A hagyomnyos jelzseket a kill rendszerh-
vssal kldhetnk.
t mut a t Mivel a hagyomnyos jelzsek esetben a torld jelzsekrl a processz nem kap k-
ln rtestst, a jelzseket nem rdemes szmolni, mert egy adott jelzssorozatra a processzor
terhelstl s egyb rendszerjellemzktl fgg eredmnyt kapunk. Mind a hagyomnyos mind
a vals idej jelzsek esetn egy elkldtt jelzsre a cmzett maximum egyszer reaglhat
(consumable resource"). Jelzs egyik modellben sem veszhet el, pusztn az egymsra torl-
dott jelzsekrl csak egy rtestst kap a cmzett. A vals idej jelzseknl a sorrend adott, a
hagyomnyos jelzseknl nincs elrva, de az implementcik a processz adott llapott rint
jelzseket ltalban elbb kzbestk. A kerneltl kapott jelzsek hagyomnyos jelzsek, mnt
ahogy a Linux rendszer s a programok tbbsge is ilyen jelzseket kld.
A fentiekben teht a kritikus szekcinak csak az egyik felt vizsgltuk: a kri-
tikus szekcit gy alaktottuk ki, hogy a jelzseket letiltottuk, valamint egy
szigor s egy megengedbb megoldst ismertettnk arra, hogy a jelzsek
a letilts alatt ne vesszenek el. Viszatrve a pldnkhoz, a kritikus szekcit
az ra felhzsa eltt belltjuk. A SIGALRM hagyomnyos jelzs: ha a kriti-
kus szekciban mr rkezik jelzs, az nem veszik el, ha tbb is rkezik, csak
egyre hvdik meg a jelzskezel:
int idozito;
static void idozito_jelzeskezelo
{
idozito =1;
243
5. fejezet: Prhuzamos programozs
int main()
{
// idozito_jelzeskezelo beregisztrlsa a SIGALRM jelzsre
idozito =0;
// Az SIGALRM letiltsa
sigprocmask(...);
alarm(150); // 150 nanoszekundum mlva SIGALRM jelzs
whi le( ! i dozi to)
// Kritikus szekci vge SIGALRM engedlyezse
sigprocmask(...)
pause(); // A pause fggvny a kvetkez jelzsig vrakozk
A fenti programrszlettel sajnos nem sokkal vagyunk elrbb: ha a jelzs a
kritikus szekci vge (sigprocmask) s a pause fggvny kztt kvetkezik be,
a fprogram ugyangy nem bred fel, mint azeltt. A pause helyett olyan
atomi mveletre van szksgnk, amely osztatlanul engedlyezi a SIGALRM
jelzst, s vrakozik a legkzelebbi jelzsig. Ez a sigsuspend fggvny. Argu-
mentumban megadhatjuk azokat a jelzseket, amelyre vrakoznia kell, eze-
ket engedlyezi. Ha a megadott jelzsek valamelyike rkezik, elszr megvrja
a jelzskezel lefutst, s csak utna tr vissza. Viszont ha sigsuspend a jel-
zskezel lefutsa utn tr vissza, akkor a jelzskezel futsa utn rgtn le
kell tiltania a megadott jelzseket, vagyis vissza kell lltania az egyes jelz-
sek engedlyezettsgt a hvs eltti llapotokba. Ugyanis ha neknk kellene
ezt megtennnk egy soron kvetkez sigprocmask hvssal, akkor jelzseket
veszthetnnk:
int idozito;
static void idozito_jelzeskezelo()
{
idozito =1;
int main()
{
// idozito_jelzeskezelo beregi sztrlsa a SIGALRM jel zsre
idozito =0;
/7 Az SIGALRM letiltsa
sigprocmask(...);
alarm(150); // 150 nanoszekundum mlva SIGALRM jelzs
244
while(!idozito)
//Kritik usszek civ ge- SIGALRMenged ly ez se,v rak oz s
sigsuspend(...);//Az tadottj elz saSIGALRM
//v isszat r sut nah v sel tti llapotot ll tj av issza
Ezzel megoldottuk a jelzsre vrakozs problmjt anlkl, hogy jelzseket
vesztettnk volna.
tmutat A pause fggvny helyett hasznljunk sigsuspendet.
Specilis jelzs a nulla rtk jelzs: ha ezt kldjk, a kernel semmit nem
kzbest, viszont ellenrizhetjk, hogy az adott azonostj processznek jo-
gunk van-e zenetet kldeni, vagy azt, hogy a processz megtallhat-e a
rendszerben. Ez utbbira jobb megolds a wait fggvnyek hasznlata (ha
a szl szeretn tudni, hogy a gyermeke fut-e) vagy kzs szinkronizcis ob-
jektumok, zrolsok, illyetve IPC-mechanizmusok hasznlata, amelyeket a
kilp processz tllt. Ezek a technikk ugyanis nem okoznak problmt ak-
kor sem, ha a nem hasznlt azonostkat a kernel j processzekhez rendeli.
5.6.2. Jelzsek megvalstsa
A kernel szempontjbl ez valamivel sszetettebb folyamat. Tegyk fel, hogy
processz vagy maga a kernel egy jelzskldst kezdemnyez. Ha a kld
folyamatnak volt ehhez joga, a kernel rtesti a cmzett processzt a jelzs r-
kezsrl, vagyis belltja a processz megfelel adatstruktrit. A kernel
szempontjbl ez a jelzsklds folyamatnak az els rsze, amelyet a jelzs
generlsnak (signal generation) neveznk, mg a folyamat msodik rsze
a jelzs kzbestse (signal delivery). A kzbests folyamn a kernel feldol-
goztatja a cmzett processzel a jelzst. Azokat a generlt jelzseket, amelyek
mg nem lettek kzbestve, fggben lv (pending) jelzseknek nevezzk.
Az egyes jelzsek engedlyezett/letiltott llapott a jelzsmaszk (signal
mask) trolja. Minden folyamathoz tartozik egy jelzsmaszk, amelyet a mr
emltett sigprocmask fggvnnyel llthatunk. A SIGSTOP s a SIGKILL jel-
zseket nem lehet letiltani.
A kernel megprblja kiszrni az egyszerbben kezelhet eseteket. Els-
knt megvizsglja, hogy a generland szignlt nem hagyja-e figyelmen kvl
a processz. Ha ez gy van, akkor a jelzs nem is generldik. Ezt csak akkor
lehet megtenni, ha a jelzs engedlyezett, mert letiltott jelzs nem veszhet el,
hiszen a processz engedlyezs eltt megvltoztathatja a jelzs elrendezst.
245
5. fejezet: Prhuzamos programozs
A msodik eset az, amikor a kernel jelzst generl, s megprblja azon-
nal kzbesteni. Ez akkor lehetsges, ha a cmzett processz mr fut. Ez gy
fordulhat el, hogy a kernel hardvermegszakts miatt generlta a jelzst
(pldul nullval val oszts), amelyet az ppen fut processznek kell kzbe-
stenie. A msik lehetsg az, ha a processz sajt magnak kldte a jelzst.
Ezekben az esetekben a generls utn azonnal megtrtnik a kzbests is.
A nem azonnal kzbestett jelzsek esetben a generlskor a kernel v-
rakozsi sorba helyezi el a jelzst, s bellt egy jelzbitet a processzlerban.
A kernel kt vrakozsi sort tart fenn a fggben lv jelzsek szmra: a
privt vrakozsi sort szlanknt hozza ltre, mg a megosztott vrakozsi
sor a processznek szl jelzseket tartalmazza. A vrakozsi sor maximlis
mrett az opercis rendszer konfigurcis paramterei kztt tartjuk nyil-
vn (RLIMIT SIGPENDING).
Ha a generlt jelzs nem vals idej, s van mr ilyen jelzs a vrakozsi
sorban, akkor nincs tovbbi lpsre szksg, a generls vget r. Ellenkez
esetben a kernel hozzadja a jelzst a megfelel sorhoz. Ha a jelzs engedlyez-
ve van, akkor a kernel belltja a processzben a jelzs rkezst jell jelzbitet,
s megprblja felbreszteni a processzt, vagyis vrakozsi llapotbl tviszi
a futsra ksz llapotba, s hozzadja a futsra ksz processzek listjhoz.
A kernel minden egyes alkalommal, amikor kernelzemmdbl felhasznli
zemmdba kapcsol azrt, hogy egy adott processzt futtasson, ellenrzi, hogy
ennek a processznek van-e fggben lv jelzse. Tipikusan ilyen tkapcsols
trtnik a taszkvlts, illetve rendszerhvsokbl val visszatrs esetn. Ha
vannak ilyen jelzsek, akkor a kernel kzbesti ket. gy, amikor processz fut-
tatsa legkzelebb sorra kerl, a kezdett veszi a kzbests folyamata.
Mivel a kernel nem hoz ltre minden jelzsnek kln vrakozsi sort,
csak kettt tart fenn, kzbestskor nem sorrendben dolgozza fel az zenete-
ket, hanem vlogat" a bennk lv jelzsek kztt. A kernel elsknt elkezdi
kirteni elszr a privt, majd utna a megosztott vrakozsi sort. Elszr a
legalacsonyabb szm jelzseket dolgozza fel, az azonos rtkeket pedig r-
kezsi sorrendben.
Ha a jelzs elrendezse a kernel alaprtelmezett mechanizmusa, akkor
meghvdik az alaprtelmezett mecahnizmus. Jl ismert kivtelt jelent az nit
processz, ez esetben ugyanis a kernel figyelmen kvl hagyja a jelzst.
Ha a jelzs elrendezse egy jelzskezel meghvst rja el, akkor ezt a
kernelnek kell meghvnia. Mivel a fggvny a felhasznli cmtrben van,
a kernelnek t kell kapcsolnia. Ez tbb problmt is felvet. A fggvnynek nem
a veremben tallhat cmre kell visszatrnie, hanem a kernelbe. Ezrt a kernel
a jelzskezel hvsa eltt belltja a sigreturn fggvny cmt, amely egy rend-
szerhvson keresztl visszatr a kernelbe. Radsul, mivel a jelzskezelk
rendszerhvsokat is hasznlhatnak, fontos, hogy a kernel helyett ne a meg-
szaktott fprogramba trjen vissza a fggvny. Ezrt a jelzskezel futtats-
hoz a kernel nem hasznlhatja a megszaktott program veremtartalmt.
246
5.6. Jelzsek
A Linux erre azt a megoldst hasznlja, hogy ltrehoz egy vermet a fel-
hasznli cmtartomnyban (ennek helyt mi is megadhatjuk a signaltstack
fggvnnyel), arra tmsolja a kernel kontextust, kztk a jelzs esetleges pa-
ramtereit, ezutn belltja a visszatrsi cmet a sigreturn cmre, majd elug-
rik a jelzskezel kezdcmre. A jelzskezel vgeztvel a sigreturn rendszer-
hvs tkapcsol kernelzemmdba, visszalltja az eredetileg megszaktott
program kontextust, majd tadja neki a vezrlst.
Sokszor nem akarunk visszatrni a jelzskezelbl, knyelmesebb elug-
rani egy program adott pontjra. Ehhez a setjmp -longjmp prost vlaszthat-
juk. Az elbbi elmenti a kontextust a program egy adott pontjn egy bufferba,
a longjmp pedig visszalltja. Ez azrt fog mkdni, mert a longjmp a kernel
ltal belltott vermet fellrja a program setjmp ltal elmentett kontextus-
val, belertve az utastsszmllt is. gy a program a megfelel veremtarta-
lommal s kontextussal folytatja a futst a setjmp ltal kijellt helytl.
Knnyen lehet azonban, hogy a jelzskezelben ms jelzsek vannak letiltva
s engedlyezve, mint a setjmp ltal meghatrozott ponton. Mivel a setjmp
nem menti el a jelzsmaszkot, a jelzskezelben rvnyes maszkkal fut to-
vbb a program. Ha ezt el szeretnnk kerlni, akkor a hasznljuk a sigsetjmp
s a siglongjmp fggvnyeket, amelyek mindssze annyiban klnbznek a
setjmpllongjmp prostl, hogy ezek elmentik, illetve visszalltjk a jelzs-
maszkot is.
A processz ltrehozsval kapcsolatos szablyok az albbiak. Ha a fork
hvssal hozunk ltre j processzt, az rkli a szl ltal belltott elrendez-
seket s a jelzsmaszkot, viszont a fggben lv jelzseket nem. Az exec fgg-
vnycsald a jelzskezelkre belltott elrendezst alaprtelmezettre lltja,
ugyanis az j program betltsvel a jelzskezelk cme rvnytelenn vlik.
Minden egyb jelzsekkel kapcsolatos bellts megmarad.
5.6.3. A jelzskezel s a fprogram egymsra hatsa
Elsknt vizsgljuk meg annak hatst, hogy egy jelzs milyen llapotban ri
a processzt. Azt az esetet mr korbban trgyaltuk, amikor a processz ppen
fut: ilyenkor a kernel a jelzst azonnal kzbesti.
A rendszer vrakoz llapota valjban ktfle llapotot takar: megsza-
kthat (INTERRUPTIBLE) s megszakthatatlan (UNINTERRUPTIBLE).
Ez a megklnbztets pontosan a jelzsek miatt ltezik: megszakthatatlan
llapotban a processz nem fogadhat jelzst. Ilyenkor a generls megtrtnik,
de a kzbests majd csak akkor, ha a processz elhagyja ezt az llapotot.
A processz ltalban meglehetsen kevs idt tlt ebben az llapotban, fknt
merevlemezzel kapcsolatos mveletek esetben, ezrt ez legtbbszr nem
okoz problmt. Nagyon ritkn, de elfordulhat, pldul valamilyen lemezhiba
folytn, hogy a processz beragad ebbe az llapotba. Termszetesen ilyenkor
mg SIGKILL-t sem kpes fogadni, csak a rendszer jraindtsa segt a prob-
247
5. fejezet: Prhuzamos programozs
lmn. Ezt elkerlend, a Linux egy jabb llapotot is bevezet a megszaktha-
tatlan llapoton bell, ez a KILLABLE. Ebben az llapotban csak a SIGKILL
rkezsekor breszti fel (fut llapotba viszi t) a processzt, amelynek a futsa
a jelzs fontossgnak megfelelen rgtn megszakad.
A megszakthat llapotban rkezett jelzsek klnsen fontosak a prog-
ramoz szmra, ugyanis ebben az llapotban szoktak vrakozni a blokkold
rendszerhvsok, pldul a read fggvny. Ilyenkor a jelzs megszaktja a
rendszerhvst, majd a kernel lefuttatja a jelzs elrendezst. Ezutn kt v-
lasztsi lehetsgnk van: a rendszerhvsbl visszatrnk EINTR rtkkel,
vagy jraindtjuk a rendszerhvst. A jl megrt program fel van kszlve az
EINTR visszatrsi rtkre, s szksg szerint jraindtja a rendszerhvst.
Ezt mr bemutattuk a 4.1.5. Rszleges s teljes olvass alfejezetben:
while((len=read(STDIN_FRENo,buf,sizeof(buf)))!=0)
{
if(len==-1)
{
i f(errno==EINTR)
{
continue;//uj ramegprobalj uk
perror("read");
return-1;
if(write(STDOUT_FILENO,buf,len)==-1)
perror("write");
return-1;
}
Erre a megoldsra akr makrt is definilhatunk: ha a visszatrsi rtk hi-
ba, s az errno rtke EINTR, akkor egy while ciklusban mg egyszer meghv-
juk a fggvnyt:
#defineSIGNAL_RESTART(FUNC) while((FuNC)==-1&&errno==EINTR);
SIGNAL_RESTART(len=read(STDIN_FILEN0,buf,sizeof(buf)))
i f(len=-1)
//Tov bbihib k k ezel se
248
5.6. Jelzsek
Minden pontencilisan blokkold hvs mg a fenti makrba csomagolva
sem a legknyelmesebb megolds. A sigaction fggvny SA_RESTART para-
mtervel megadhatjuk, hogy az egyes jelzseknl a rendszer automatikusan
jraindtsa (jra meghvja) a megszaktott rendszerhvst. Ennek hasznlata
elg krlmnyes, mert jelzsenknt kell belltani az jraindtst, valamint
nem minden rendszerhvs indthat jra. Ezt az informcit a kziknyv 7.
fejezetben tallhat signal oldala rja le.
A msik problmt a fggvnyek nem globlis adatai okozhatjk (globlis
vltozk, statikus loklis vltozk). Pldul a printf fggvny globlis buffere-
ket mdost. Ha a printf egy futsa ppen mdostja a globlis buffert, de mg
nem vgzett a mvelettel, ebben az inkonzisztens llapotban meghvdik egy
jelzskezel, amely szintn hv egy printf-et, amely a globlis buffert inkonzisz-
tens llapotban tallja. Ilyenkor nagyon nehz megjsolni, mi lesz a program
mkdse, azt viszont nem nehz, hogy ez nagy valsznsggel nem az elvrt
viselkeds lesz. Hasonl a problma a memriafoglalsnl s -felszabadtsnl
(malloclfree), amelynek szmos implementcija globlis lncolt listban tart-
ja az adatokat. Ezeket a fggvnyeket nem reentrns fggvnyeknek nevez-
zk. Ha a jelzskezelben is s a fprogramban is hasznlunk nem reentrns
fggvnyeket, a program mkdse definilatlan. Ezt ltalban az albbi
szably betartsval szoktk elkerlni.
tmutat Ne hasznljunk a jelzskezelben nem reentrns fggvnyeket.
A reentrns fggvnyek listjt szintn a signal (7) kziknyoldala tartal-
mazza (jelzsbiztos fggvnyeknek nevezve ket). Tipikusan azok a fggv-
nyek nincsenek ezek kztt, amelyek valamilyen I/O mveletet vgeznek,
vagy a malloc/ free fggvnyek valamelyikt hvjk.
A kvetkez egymsra hats abbl ered, hogy egy mveleti hardverese-
mny ltal kivltott jelzs (SIGBUS, SIGILL, SIGSEGV, SIGFPE) feldolgozsa
utn a megszaktott program ugyanonnan folytatja a futst, ahol abbahagy-
ta. Ha pldul nullval val oszts trtnt, a jelzs feldolgozsa s a jelzske-
zel norml visszatrse utn folytaddik a program, amely jra elidzi a
nullval val osztst s vele egytt a jelzst is.
tmutat A hardveresemny ltal kivltott jelzsek esetben trekedjnk a legegyszerbb
megoldsra: hagyjuk rvnyeslni az alaprtelmezett kezels mechanizmust. Ha ez mgsem
oldhat meg, azok jelzskezelit vagy ugrutastssal (siglongjmp, longjmp), vagy az exit
fggvnnyel hagyjuk el.
Ha egy hardveresemny ltal kivltott jelzst figyelmen kvl hagyunk, a ker-
nel ennek ellenre kzbesti. Ha letiltjuk ket, akkor terminlja a programot.
249
5. fejezet: Prhuzamos programozs
5.6.4. Jelzsek s a tbbszl processz
Tbbszl programok esetn a szabvnyok s az implementcik arra tre-
kedtek, hogy megtartsk a jelzsek eredeti viselkedst abban az esetben,
amikor a processznek kldnk jelzseket, ugyanakkor megprbltk ezt ki-
egszteni egy intuitv s hasznlhat szlak kztti jelzskldssel. Egy
tbbszl programban a szlak nem osztoznak az albbiakon:
jelzsmaszk,
a mr emltett privt vrakozsi sor,
a kernel ltalt a jelzskezel'k szmra ltrehozott ideiglenes verem.
Ez azt jelenti, hogy a jelzselrendezsek viszont kzsek a szlakra nzve: ha
egy szl megvltoztat egy elrendezst, az az egsz processzre, gy a tbbi szl-
ra is rvnyes. Az alaprtelmezett elrendezsek kzl a STOP s a terminls
processzszint: a kernel az sszes szlat meglltja, illetve terminlja.
A legfontosabb krds az, hogy ki kapja a tbbszl processznek kldtt jel-
zst. Az egyes szlaknak kln kldtt jelzst (pthread_kill, pthread_sigqueue)
az adott szl kapja. Az azonnal kzbestett jelzseket (harverjelzsek s a
processz nmagnak kldtt jelzsei), valamint a SIGPIPE jelzst szintn.
A tbbit a kernel mind a processz vrakozsi sorban helyezi el. Ha a kernel
a processz vrakozsi sorban lv jelzst dolgoz fel, amelynek elrendezse egy
jelzskezel, akkor kivlaszt egy tetszleges szlat, amely nem tiltja le az adott
jelzst, s ezt megszaktva futtatja le a jelzst. Ha mindegyik blokkolja a jel-
zst, az termszetesen a vrakozsi sorban marad. Sajnos a szlkezel fggv-
nyeket, belertve a szinkronizcit is, nem hasznlhatjuk a jelzskezelben.
tmutat Szlakban ne hasznljunk aszinkron jelzskezelst. Lehetleg egyetlen szlban en-
gedlyezzk a jelzseket, s ott szinkron mdon kezeljk ket.
5.6.5. Jelzsek programozsa
A jelzsek mkdse utn vegyk sorra a programozs rszleteit. A program-
kdban ktflekppen valsthatunk meg jelzskezelst. Az egyik a mr is-
mertetett megolds, amikor jelzskezelt adunk meg. A msik lehetsg
amely nagyon hasonlt a select/poll fggvnyekhez az, hogy letiltjuk az
sszes letilthat jelzst, s egy fggvnnyel vrakozunk arra, hogy a
processz/szl vrakozsi sorba jelzs rkezzen Amikor a fggvny visszatr,
kezeljk a jelzst. Ez utbbi sokszor nagyon praktikus lehet kifejezetten sz-
lak esetn , sem a reentrns fggvnyekkel, sem pedig a jelzsek elveszts-
vel nem kell foglalkoznunk. Az els mdszert aszinkron jelzskezelsnek
(asynchronous signal handling), mg a msodikat szinkron jelzskezels-
250
5.6. Jelzsek
nek (synchronous signal handling) nevezzk. Hangslyozni kell, hogy csak a
jelzskezels szinkron, a kommunikci formja tovbbra is aszinkron, hiszen a
jelzst kld processz/szl nem vrakozik. A jelzskezlsnl viszont nem tet-
szleges helyen szaktja meg a programot, hanem szinkronizltan, a vrakoz-
fggvny belsejben. Nem kezelhetjk szinkron mdon sem a SIGKILL, sem a
SIGSTOP jelzseket, hiszen ezek elrendezst nem vltoztathatjuk meg, nem
tilthatjuk le ket, valamint nem is vrakozhatunk rjuk. A tovbbiakban sor-
ra vesszk azokat a fggvnyeket, amelyekkel mindezt megvalsthatjuk.
5.6.5.1. Jelzsek kldse
Jelzseket a ki//0 rendszerhvssal kldhetnk:
#include<sy s/ty pes.h>
#include<signal.h>
intk ill(pid_tpici,intsig);
Apid argumentum a processz azonostja, a sig pedig a jelzs azonostja.
A pid specilis rtkeivel lehetsgnk van arra, hogy az nit processzen s
sajt magn kvl az sszes processznek (-1) kldjnk jelzst. Ha a sig argu-
mentum nulla, akkor a ki//0 fggvny nem kld jelzst, de a hibaellenrzst
elvgzi. gy megnzhetjk, hogy van-e jogunk s lehetsgnk jelzst kldeni
egy processznek. Ha a pid kisebb, mint nulla, akkor a kernel a vltoz abszo-
lt rtknek megfelel processzcsoportnak kldi a jelzst. Ezt a konverzt
elvgzi helyettnk az albbi fggvny, ahol kzvetlenl megadhatjuk a pro-
cesszcsoport azonostjt:
#include<sy sity pes.h.
# nclude<signal.h>
intk illpg(intpgrp,intsig);
"1111
,
111
~EMIL
A pgrp argumentum a processzcsoport azonostja, nulla esetn a hv pro-
cessz sajt csoportjnak kldi a jelzst. Vals idej jelzseket a sigqueue fgg-
vnnyel kldhetnk:
#include<signal.h.
intsigqueue(pid_tpid,intsig,constunionsigv alv alue); -
Ahogy sz volt rla, a kernel megrzi az ezzel a fggvnnyel kldtt jelzsek
sorrendjt, s ha tbbszr kldnk ugyanolyan jelzst, azt ugyanannyiszor
kzbesti. A fggvny els argumentuma a cmzett processz azonostja, a
msodik a kldend jelzs. A nulla jelzs itt is hasznlhat a jogosultsg ki-
dertsre. Mivel a hagyomnyos jelzsektl eltren a vals idej jelzsek
2 51
5. fejezet: Prhuzamos programozs
nem hordoznak elre definilt jelentst, egy tovbbi, programoz ltal defini-
lt kiegszt adatot is tkldnk. A fggvnyek ezen harmadik argumentu-
mt hasznlhatjuk egsz szmknt vagy pointerknt:
union sigval
{
int sival_int ;
vod *sival_ptr ;
}; - - - - - -
Arra azonban oda kell figyelnnk, hogy ha a cmzett processz nem azonos a
kld processzel, akkor a kld processz cmtartomnynak egy processze
nem lesz rvnyes a cmzett processz cmtartomnyban. Ezrt a fenti lehet-
sgek kzl ezt az argumentumot ltalban egsz rtkknt kezeljk.
Szlak esetn a pthread_kill s a Linux-specifikus pthread_sigqueue fgg-
vnyt hasznlhatjuk. Mindkt esetben csak a sajt processzbeli szlaknak
kldhetjk a jelzst. Mind szlakra, mind processzekre mkdik az albbi fgg-
vny, amellyel sajt magunknak kldhetnk jelzst:
#include <signal .h>
int raise(int sig);
Ha a fggvnyt tbbszl programbl hvjuk, akkor a kernel a hv szlnak,
ellenkez esetben a hv processznek tovbbtja a jelzst.
Jllehet jelenleg a Linux sszes jelzskld fggvnye tmogatja a vals
idej jelzseket, ez a megolds nem hordozhat, s nincs garantlva, hogy
mindig gy lesz a Linux alatt.
tmutat Ne keverjk a jelzskld fggvnyek s a jelzsek tpusait. Vals idej jelzseket
(SIGRTMIN s SIGRTMAX kztt) mindig sigqueuelpthread_sigqueue fggvnyekkel kldjnk, ha-
gyomnyos jelzseket pedig a killIkillpg/raise/ pthread kill fggvnyekkel. Vals idej jelzsek
kezelsekor mindig lltsuk be a SA_SIGINFO jelzbitet a sigaction fggvny belltsai kztt.
A kldshez val jogosultsgot a kernel az albbi szablyok alapjn dnti el.
A CAP KILL jogosultsggal rendelkez processz brmely processznek kldhet
jelzst. Ahogy emltettk, az init processznek csak olyan jelzst kldhetnk,
amelynek elrendezsre jelzskezelt adott meg. Kln jogosultsgokkal nem
rendelkez processzeknl az albbiak szerint trtnik a dnts. A kernelnek
a kld processz valdi s effektv azonostja szmt. A kernel ezt veti ssze
a cmzett processz valdi s elmentett azonostjval. Ez a kvetkezt jelenti.
Ha nem setuiddal fut a program, akkor a valdi azonost s az effektv meg-
egyezik: gy a jogosultsg vizsglatt a valdi azonost alapjn is el lehet v-
gezni. Ha setuid privilgiumokkal fut a program, akkor pedig egy processz
mindig tud a gyermekeinek zenetet kldeni, hiszen az elmentett azonostja
sajt maga lesz. Mivel az effektv azonostt a kernel nem ellenrzi, ezert egy
252
5.6. Jelzsek
A felhasznlhoz tartoz processz nem tud olyan processznek jelzst kldeni,
amelyet B felhasznl indtott, de a setuid miatt A nevben fut. Egy kivtel
akad: SIGCONT jelzst brmelyik, a kldvel egyez munkamenetben lv
processznek el lehet kldeni. Ez lehetv teszi, hogy a shell akkor is jraindt-
hasson processzeket, ha azok megvltoztattk a felhasznli azonostjukat.
5.6.5.2. Jelzsek letiltsa s engedlyezse. Fggben lv
jelzsek
Szmos fggvny egy jelzshalmazon vgez mveletet. Ezt a halmazt a sig-
set_t adattpus reprezentlja, amely a signal.h llomnyban van definilva.
A POSIX-szabvny 5 fggvnyt definil ennek a halmaznak a kezelsre:
intsigempty set(sigset_t*set);
intsigfillset(sigset_t*set);
intsigaddset(sigset_t*set,intsignum);
intsigdelset(sigset_t*set,intsignum);
intsigismember(constsigset_t*set,intsignum);
A sigemptyset fggvny trli az sszes elemet a halmazbl. Ennek ellenkezje
a sigfillset, amely minden jelzst beletesz a halmazba, belertve a vals idej
jelzseket is. Egyetlen signum jelzst a sigaddset fggvnnyel adhatunk hoz-
z a halmazhoz. Ennek ellenkezje a sigdelset, amely a signum ltal megha-
trozott jelzst trli a halmazbl. A sigismember fggvnnyel lekrdezhetjk,
hogy egy adott jelzs eleme-e a halmaznak. Ha a jelzs szerepel a halmazban,
akkor 0-tl eltr rtkkel tr vissza, egybknt 0-val. Ezek a fggvnyek
csak akkor trnek vissza hibval, ha az argumentumknt megadott jelzs
helytelen. Ezeken kvl a tovbbi Linux-specifikus fggvnyek is rendelke-
zsre llnak
.
sigandset (halmazok metszete), sigorset (halmazok unija), sigis-
emptyset (ressg vizsglata).
Ahogy sz volt rla, a processz jelzsmaszkja tartalmazza azt a belltst,
hogy melyik jelzs van letiltva, illetve engedlyezve. Ezt egy sigset_t adat-
struktra valstja meg: a halmaz a letiltott jelzseket tartalmazza. A mr
emltett sigprocmask() fggvny teszi lehetv, hogy a lekrdezzk/bellthas-
suk a processz jelzsmaszkjt:
ncl ude<signal.h>
intsigprocmask (intwhat,constsigset_t*set,sigset_t*oldset);
Az els paramter, a what, azt hatrozza meg, hogy a jelzsmaszkot hogyan
mdostjuk. rtkeit az 5.10. tblzat tartalmazza.
253
5. fejezet: Prhuzamos programozs
5.10. tblzat. A sigprocmask mveletei
Parancs Lers
SIG_BLOCK A setben lev jelzsek hozzaddnak a maszkhoz.
SIG_UNBLOCK A setben lv jelzsek trldnek a maszkbl.
SIG_SETMASK A set tartalma lltdik be mint j maszk.
Ha megadunk egy halmazt utols paramterknt (nem NULL), akkor abban
visszatrskor az elz jelzsmaszkot kapjuk vissza.
Ha a jelzsmaszk aktulis rtkt szeretnnk lekrdezni, set paramter-
knt NULL rtket adunk t Ilyenkor a fggvny az els paramtert nem veszi
figyelembe. Visszatrskor az oldset tartalmazza az aktulis rtket. Ahogy sz
volt rla, a tbbszl programban az egyes szlak nem osztoznak a jelzsmasz-
kon, gy a sigprocmask viselkedse ilyenkor nem specifiklt. Ezrt tbbszl
programban az azonos paramterezs pthread_sigmask fggvnyt hasznljuk.
A fgg'ben lv jelzsek halmazt az albbi fggvnnyel krdezhetjk le:
#include <signal .h>
int sigpending(sigset_t *
set);
A fggvny visszatrsekor a set vltozban adja vissza a fggben lv jelz-
sek halmazt. Tbbszl programban ez a megosztott vrakozsi sorban s a
hv szlhoz rendelt privt vrakozsi sorban tallhat jelzsek unija.
Ha egy fggben lv jelzst szeretnnk eltvoltani a jelzslistrl, akkor
elszr tlltjuk az elrendezst: figyelmen kvl hagyjuk, azutn pedig en-
gedlyezzk. Mivel a letiltott jelzsek az engedlyezs utn az j elrendezs
szerint kezeldnek, ezrt a jelzs minden mellkhats nlkl eltnik a felfg-
gesztett jelzsek vrakozsi sorbl. Erre a technikra azonban ritkn van
szksgnk.
5.6.5.3. A jelzsek kezelse
A POSIX-programok a jelzsek kezelfggvnyt a sigaction() fggvnyhvs-
sal regisztrlhatjk, illetve krdezhetik le:
#include <signal . h>
int sigaction(int signum, struct sigaction * act,
struct sigaction * oact);
Ez a rendszerhvs belltja a signum ltal meghatrozott jelzsre az act
struktra ltal lert lekezel fggvnyt. Ha az oact nem NULL, akkor a ko-
rbbi kezelfggvny-belltsokat tartalmaz struktra rtkt veszi fel. Ha
az act rtke NULL, akkor a fggvny nem llt be semmit, hanem visszaadja
az aktulis belltsokat.
254
e
5.6. Jelzsek
A kezelfggvnyt a sigaction struktra rja le:
#include <signal .h>
struct sigaction
sighandler_t sa_handler;
sigset_t sa_mask;
unsigned long sa_flags;
void (* sa_restorer)(void);
);
Az sa_handler fggvnypointer, amelynek prototpusa a kvetkez:
void handler(int signum);
ahol a signum rtke a jelzs szma, amellyel a kernel a fggvnyt meghvta.
A fggvnypointeren kvl felveheti a SIG_DFL s a SIG_IGN rtkeket is:
az els az alaprtelmezettre lltja, a msodik esetn a jelzst a processz fi-
gyelmen kvl hagyja.
A struktra tartalmaz tovbb egy jelzslistt (sa_mask). Ezeket a jelz-
seket a rendszer hozzadja a a jelzsmaszkhoz a kezelfggvny futsnak az
idejre, majd a jelzskezel visszatrst kveten visszalltja az eredeti r-
tkre. A jelzskezel hvst kivlt jelzst a fggvny automatikusan letiltja,
fggetlenl attl, hogy szerepel-e ebben a listban, vagy sem. (Ha mgsem
akarjuk, hogy blokkoldjon, akkor ezt az saJlags paramterrel befolysolhat-
juk.) Ezzel megelzzk, hogy ugyanannak a jelzsnek az rkezse megszakt-
sa a jelzskezelt annak egy kvetkez hvsval. Ha tbb jelzst kezelnk
ugyanazzal a fggvnnyel, futsnak az idejre a jelzsmaszkkal tiltsuk le az
sszes ltala kezelt jelzst.
Az sailags vltoz rtkei jelzbitek, amelyeket bitenknti VAGY kapcso-
lattal kombinlhatunk. Ezeket a jelzbiteket az 5.11. tblzat foglalja ssze.
5.11. tblzat. A sigacton struktra lehetsges jelzbitjei
Parancs Lers
SA NOCLDSTOP Norml esetben, ha egy processz gyerekprocessze megsznik,
vagy megll, akkor egy SIGCHLD jelzst kld. Ha ezt az opcit
belltjuk a SIGCHLD jelzsre, akkor csak a megszns esetn
kldi el.
SARESTART Automatikusan jraindtja a megszaktott rendszerhvsokat
(lsd az 5.6.3. A jelzskezel s a fprogram egymsra hatsa
alfejezetben).
SANODEFER Amikor a jelzs kezelfggvnye meghvdik, akkor a jelzs nem
tiltdik automatikusan. (Hasznlata nem javasolt, csak specilis
esetekben.)
2 55
S. fejezet: Prhuzamos programozs
Parancs Lers
SA_ONSTACK Megadhatjuk a jelzskezel veremterlett, amelyet a signal-
stack fggvnnyel hozunk ltre.
SA RESETHAND Akkor hasznljuk, ha azt akarjuk, hogy a jelzskezel csak egy-
szer hvdjon meg. Miutn a kezelfggvny meghvdott, a be-
llts alaprtelmezettre lltdik. Ha ezt nem adjuk meg, akkor
a jelzskezel addig rvnyes, amg egy tovbbi sigaction hvs-
sal meg nem vltoztatjuk.
SA_SIGINFO A jelzskezel paramtereket vr.
SA NOCLDWAIT A SIGCHLD jelzsre hasznljuk: ilyenkor a gyermekprocesszek
nem vltoznak zombiv.
Feladat rjunk olyan jelzskezelt, amely tlltja egy globlis vltoz rtkt a SIGALRM jel-
zsre. lltsuk t a SIGALRM elrendezst a jelzskezelre.
A globlis vltoz deklarcijt s a jelzskezelt az albbi kdrszlet mutatja be:
static volatile sig_atomic_t timer;
static void tmer_handler(int sgno)
{
ti mer =1;
Az egsz rtk sig_atomic_t tpussal kapcsolatban a fordtk garantljk,
hogy hozzfrs atomi mvelet. A volatile mdostt azrt rjuk el, hogy
a fordt az optimalizls miatt nehogy regiszterben trolja, mert a jelzs a
kernel ltal a jelzs szmra sszelltott kln kontextusban fut, ahol nem
ltja a fprogram regisztereit s fordtva. A static kulcsszt azrt rjuk ki,
mert nem szeretnnk, ha ms modulok is hozzfrnnek. A jelzskezel a jel-
zs azonostjt kapja meg, gy egyszerre tbbfle jelzst is tudunk ugyanaz-
zal a fggvnnyel kezelni. A fggvny trzse esetnkben nagyon egyszer:
tlltja a globlis vltoz rtkt.
A regisztrlst vgz kdrszlet a kvetkez:
struct sigaction sa;
// timer_handler regisztrlsa a SIGALRM jelzsre
sigemptyset(&sa.sa_mask);
sa.sa_flags=0;
sa.sa_handler =timer_handler;
sigaction(SIGALRM, &sa, NULL);
Az sa_mash mezt res halmazra lltjuk, mert mst jelzst nem tiltunk le, a
SIGALRM pedig automatikusan letiltdik.
256
5.6.Jelz sek
Ha mr nincs szksgnk az idztsre, szeretnnk visszalltani a jelzs
elrendezsnek eredeti llapott:
structsigaction sa, saold;
//timer_handlerregisztr l saaSIGALRMj elz sre
sigempty set(&sa.sa_mask );
sa.sa_flags=0;
sa.sa_handler=timer_handler;
//Be ll t sk orelementj k azelz llapotot
sigaction(5I6AtRm,&sa,&saold);
sigaction(SIGALRm,&saold,0);//Afeladatv gezt v el
//v issza ll tj uk
Termszetesen alaprtelmezettre is llthatjuk az elrendezst:
sigemptyset(&sa.sa_mask);
sa.sa_flags=0;
sa.sa_handler = SIG_DFL;
sigaction(SIGALRM,&sa,NULL);
Ha a SIG_DFL helyett SIG_IGN-t hasznluk, akkor a processz figyelmen k-
vl hagyja a jelzst.
A sigqueue fggvny trgyalsnl emltettk, hogy jelzsekkel param-
tereket is lehet kldeni. Ennek az adatnak a fogadst egy ms prototpus
jelzskezelvel tehetjk meg, de ehhez meg kell adnunk az SA_SIGINFO jel-
zbitet is:
v oidhandler(intsignum,siginfo_t* nfo, void * param)
t
sa.sa_flags = SA_SIGINFO;
Az els paramter a jelzs azonostja, a msodik a jelzssel s kldjvel
kapcsolatos rszletes informcit tartalmaz struktra, s az utols a jelzs
kontextust ler ucontext_t tpus paramter, amelyet nem rszleteznk.
A jelzssel kapcsolatos informci tartalmazza az elkldt adatot is az si_value
mezben. A struktrt rszleteiben nem ismertetjk, a kziknyv sigaction le-
rsban megtallhatjuk a kifejtst.
A sigaction meglehetsen egyszer eldje a signal fggvny, amelynek
implementcii jelentsen eltrhetnek az egyes rendszereken, gy nehezen
hordozhat. Ugyanakkor az alaprtelmezett elrendezs s a jelzs figyelmen
kvl hagysa egyszeren (s hordozhatan) bellthat vele:
2 57
5. fejezet: Prhuzamos programozs
signal(sig, SIG_DFL);
signal(sig, SIG_IGN);
tmutat A fenti kt esettl eltekintve hasznljuk a sigaction fggvnyt a signal fggvny
helyett.
5.6.5.4. Szinkron jelzskezels
Szinkron jelzskezelskor egy fggvnnyel vrakozunk a jelzsre, amelyre a
vrakozfggvny visszatrsekor reaglunk. Ez a megolds klnsen hasz-
nos szlak esetben, ahol sokkal bonyolultabb szablyok rvnyesek a jelzs
kzbestsre. Ebben a rszben ezeket a vrakozfggvnyeket trgyaljuk.
Elsknt kt fggvny mutatunk be, amelyek nem tekinthetk a sz leg-
szorosabb rtelmben vett szinkron jelzskezelnek, hiszen jelzskezelt
hasznlnak. Ugyanakkor itt is azonosthat a program egy pontja, ahol a fu-
ts megll, s vrakozik a jelzsre. A kt fggvny kzl a legegyszerbb a
pause, amelynek alkalmazst mr az elvi megfontolsok alatt elvetettk.
A mr emltett sigsuspend0 fggvny a processz felfggesztsnek egy msik
lehetsgt jelenti:
#include <signal.h
int sigsuspend(const sigset_t * mask);
!!"
10
ffikr
A sigsuspendO meghvsakor a processz jelzsmaszkjt a paramterben meg-
adottra lltja, vagyis a halmazban szerepl jelzseket letiltja, s vrakozni
kezd a jelzsre. Ezt egy atomi mvelet keretben hajtja vgre: a processz nem
kaphat jelzst a jelzsmaszk belltsa s a vrakozs megkezdse kztt.
A fggvny a jelzs elrendezsnek lefutsa utn rgtn visszalltja a maszkot
a meghvs eltti llapotra, majd hibtlan mkds esetn EINTR rtkkel tr
vissza: a legtbb fggvnynl hiba a jelzs ltali megszakts, itt ppen a nor-
ml visszatrs oka.
Feladat rjunk olyan programot, amely felhz egy idztt, s vrakozik az ALRM jelzsre.
A feladat egy lehetsges megoldst az albbi kdrszlet mutatja be:
#nclude <signal.h>
#include <unstd.h>
#include <stdi.h>
static volati le sig_atomic_t timer;
static void timer_handler0
{
timer =1;
258
5.6. Jelzsek
intmain()
sigset_talarmMask ,suspendMask ;
structsigactionsa,saold;
timer=0;
sigempty set(&alarmmask );
sigaddset(&alarmmask ,SIGALRM);
//Atimer_handlerregisztr l saaSIGALRMj elz sre
sigempty set(&sa.sa_mask );
sa.sa_flags=0;
sa.sa_handler=timer_handler;
sigaction(SIGALRM,&sa,&saold);
//ASIGALRMletilt sa
sigprocmask (SIG_BLOCK,&alarmask ,&suspendMask );
//Haezeredetileglev olttiltv a,
//elt v ol tj uk ,hogy asigsuspendv isszat rj enr
sigdelset(&suspendMask ,SIGALRM);
alarm(10);//10masodpercmlv aSIGALRMj elz s
while(!timer)
{
//Kritik usszek civ ge-SIGALRMenged ly ez se,v rak oz s
sigsuspend(&suspendMask );//Az tadottj elz saSIGALRM
//Visszat r sut nah v sel tti llapotot ll tj av issza
printf("Meg rk ezett\n");
//Vissza ll tj uk azeredetielrendez st
sigaction(SIGALRM,&saold,0);
return(alarm(0));//Kik apcsolj uk azidz tt
Az igazi szinkron jelzskezels sorn letiltjuk a jelzskezelket, az sszes jel-
zst blokkoljuk, s a vrakozfggvnyek a processz privt s publkus vra-
kozsi sorbl veszik az adatot. Ezt kt fggvnnyel valsthatjuk meg:
#include<signal.h>
intsigwaitinfo(constsigset_t*set,siginfo_t*Info);
intsigtimedwait(constsigset_t*set,siginfo_t*info,
conststructtimespec*timeout);
A kt fggvny mkdse azonos, leszmtva, hogy a sigtimedwait lehets-
get ad egy ti meout paramter megadsra. Ha a timeout letelt, s nem rke-
zett alkalmas jelzs, visszatr.
2 59
5.fej ezet:Prhuzamos programozs
A fggvnyek els paramtere azon jelzsek halmaza, amelyre vrakozni
szeretnnk. Ha a jelzs megtallhat a szl privt vagy a processz publikus
vrakozsi sorban, rgtn visszatr. Ha nem, akkor addig vrakozik, mg gy
nem trtnik. A jelzseket ugyanolyan sorrendben kapjuk meg, mint a jelzs-
kezelk esetben. Ha az utols paramter nem nulla, a sigactionnl emltett
(de nem rszletezett) jelzsinformcit kapjuk vissza.
FeladatOldjuk meg azelbbifeladatot szinkron jelzskezelssel.
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
intmain()
f
sigset_talarmMask ,fullmask ;
sigempty set(&alarmmask );
sigaddset(&alarmmask ,SIGALRM);
/7 ASIGKILL sSIGSTOP j elz sek enk iv lazsszesj elz s
//letilt sa
sigf llset(&fullmask ):
sigprocmask (5IG_BLOck ,&fuliMask ,NULL);
}
alarm(10);//10masodpercmlv aSIGALRMj elz s
sigwaitinfo(&fullMask ,NULL);
printf("meg rk ezett\n");
return(alarm(0)); /7 Kik apcsolj uk azid zitt
Egy nagyon hasznos Linux-specifikus fggvny a signalfd, amely llomnyle-
rn keresztl is olvashatv teszi a jelzst:
wi
llik int signalfd(int fd, const sigset_t * mask, int flags);
Ha az els paramternek 1-et adunk t, akkor a visszatrsi rtk egy olyan
llomnyler, amelyet, ha szignl tallhat a privt vagy a publikus vrako-
zsi sorban, akkor olvashatunk is ekkor struct signalfd_siginfo tpus adatot
kapunk vissza, amely a jelzshez kapcsold informcit tartalmazza. A m-
sodik paramter azokat a jelzseket foglalja magban, amelyekre kvncsiak
#include<sy s/signalfd.h>
2 60
5.6.Jelzsek
vagyunk, vagyis amelyek adataihoz az llomnylerbl val olvasssal hozz
szeretnnk frni. Az utols paramter az albbi kt jelzbitet vagy azok VAGY
kapcsolatt tartalmazhatja: SFD_NONBLOCK s SFD_CLOEXEC ezek
megfelelnek az llomnyok megnyitsnl megismert O_NONBLOCK s
0 CLOEXEC jelzbiteknek. Ha az els paramter egy rvnyes, a fggvny
elz hvsval ellltott llomnyler, akkor a signalfd a maszk rtkt l-
ltja t a mr ltez lern.
Feladat Vrakozzunk a S/G_ALRM jelzsre s a szabvnyos bemenetre egyszerre.
A feladat egy lehetsges megoldsa az albbi:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include sys/select.h
#include sys/signalfd.h>
#include <fcntl.h>
,nt main()
sigset_t alarmMask, fullmask;
int fd;
struct signalfd_siginfo info;
11 I
I
int ret;
sigemptyset(&alarmmask);
sigaddset(&alarniMask, SIGALRM);
// Az sszes jelzs letiltsa
si gfi 1 1 set(8/ful 1 mask) ;
sigprocmask(5IG_BLOCK, &filllmask, NULL);
/7 Ler ltrehozsa
fd =signalfd(-1, &alarmmask, 5Fp_N0NBL0Ck);
alarm(10); // 10 masodperc mlva SIGALRM jelzs
// A select az stdinnre es a jelzs lerjra figyel
fd_set readfds;
FD_SET(STDIN_FILENO, &readfds);
FD_SET(fd, &readfds);
select(fd+1, &readfds, NULL, NULL, 0);
if(FD_ISSET(fd, &readfds)) // Na benne van az eredmnyhalmazban
{
ret =read(fd, &info, sizeof(struct signalfd_siginfo));
printf("%d processz jelzest kuldott.\n", info.ssi_pid);
}
26]
5. fejezet: Prhuzamos programozs
close(fd); // Le kell zrnunk az llomnylert
printf("megrkezett vagy megnyomtk.\n");
return(alarm(0)); // Kikapcsoljuk az idzitt
}
5.6.6. A SIGCHLD jelzs
A processzek trgyalsnl (lsd az 5.1. Processzek alfejezetben) mr emltet-
tk, hogy a processzek a kilps utn nem sznnek meg teljesen: nhny lekr-
dezhet statisztikt s a kilpsi rtket tartalmaz adatstruktrkat megrzik,
hogy a szlprocessz le tudja krdezni ezeket. Ezt a processzllapotot neveztk
zombinak. A zombiprocesszeket gy szabadthatjuk fel, hogy meghvjuk vala-
melyik wait fggvnyt vagy blokkok, vagy nem blokkolt mdon.
A gyermekprocessz kilpsrl, azaz zombillapotba kerlsrl a szl-
processz SIGCHLD jelzst kap. Mivel a wait fggvnyek jelzsbiztosak, a jel-
zsbl rgtn meg is hvhatjuk 'ket az albbiak szerint:
i nt oldErrno =errno;
while (waitpid(-1, NULL, WNOHANG) >0)
continue;
errno =oldErrno;
A fenti kdrszlet vgigiterl az sszes kilpett (zombi) gyermekfolyamaton. Ha
nincs tbb ilyen gyermekfolyamat, a fggvny nullval tr vissza, s a ciklus
vget r. Akkor is kilpnk, ha hiba trtnt. Mivel az errno vltozt a fprog-
ram is hasznlhatja, ezrt elmentjk, s visszaWtjuk, ha a waitpid esetleg
megvltoztatta volna. A zombik begyjtsre ez a leghordozhatbb megolds.
tmutat A jelzskezelkben mindig gondoskodjunk az errno vltoz elmentsrl s vissza-
lltsrl, ha olyan fggvnyt hvunk, amely tllthatja az errno vltozt.
Ha azt szeretnnk, hogy a szl rtestst kapjon arrl, hogy a gyermekpro-
cessz jelzst kapott, akkor a sigaction fggvnynek meg kell adnunk a
SA_NOCLDSTOP jelzbitet, amikor a SIGCHLD jelzskezeljt belltjuk.
Ha le szeretnnk tiltani azt, hogy egy mr ltez processz zombiv alakul-
jon, tbb mdszer is ltezik. A SIGCHLD jelzs alaprtelmezett belltsa a
figyelmen kvl hagys. Ennl az egy jelzsnl mst jelent, ha meghagyjuk az
alaprtelmezettet, vagy expliciten belltjuk a jelzs figyelmen kvl hagy-
st. Az utbbi esetben a processz gyermekprocesszeibl nem kpzdik zombi,
262
5.6. Jelzsek
kilpskor megsznnek A bellts eltt mr zombiv alakult folyamatok
viszont nem sznnek meg. Nagyon hasonl mkdst rhetnk el, ha a
sigaction hvs SA_NOCLDWAIT kapcsoljval lltjuk be e jelzskezelt.
Ilyenkor szintn nem alakulnak zombiv a gyermekprocesszek, viszont meg-
sznskrl jelzst kapunk. Ekkor termszetesen nem frnk hozz a statisz-
tikkhoz s a visszatrsi rtkekhez. Figyeljnk arra, hogy a jelzskezelt
vagy a figyelmen kvl hagyst mg az els gyermekprocessz ltrehozsa eltt
belltsuk, klnben lemaradhatunk az rtestsrl.
263
HATODIKFEJEZET
Hlzati kommunikci
Mai, szmtgp-hlzatokkal tsztt vilgunkban a Linux rendszerek egyik f
alkalmazsi terlett a hlzati alkalmazsok jelentik. Ebben a fejezetben
ezeknek a kommunikciknak a megvalstsi alapjait ismerjk meg. Nem fog-
lalkozunk az sszes protokollal, jllehet a Linux tbbet is tmogat (TCP/IP,
AppleTalk, IPX stb.). Ezek rszletes ismertetse meghaladn a knyv kereteit.
Vizsgldsunk egyik terlete a Berkeley socket-API, amely tulajdonkp-
pen egy ltalnos kommunikcis interfsz. Mi kt implementcijt trgyal-
juk. A legfontosabb a TCP/IP protokoll hasznlata, amely lnyegben mkd-
teti az internetet. A msik, egyszerbb protokoll a Unix domain socket, amely
tulajdonkppen nem hlzati kommunikci, hanem egy olyan IPC-mechaniz-
mus, amely csak egy gpen bell hasznlhat, m a programozs hasonlsga
miatt itt trgyaljuk.
Tovbb megismerhetjk a TCP/IP-re pl tvoli eljrshvst (Remote
Procedure Calling, RPC). Ez egy magasabb szint, ltalban egyszerbben
hasznlhat kommunikcis metdus.
6.1. A socket
Mint a Linux ms erforrsait, a socketeket is a fjlabsztrakcis interfszen
keresztl implementltk a rendszerbe. A hlzati kapcsolatnak azokat a
vgpontjait, amelyeket a programoz hasznlhat, socketeknek nevezzk, ezek
egyben egy llomnytpust is jelentenek. Ltrehozsuk a socket0 rendszerh-
vssal trtnik, amely egy llomnylerval tr vissza. Miutn a socketet ini-
cializltuk, a read0 s a write() fggvnyekkel kezelhet, mint minden ms
llomnyler, hasznlat utn pedig a close0 fggvnnyel le kell zrnunk.
j socketeket a socket0 rendszerhvssal hozhatunk ltre, amely az inici-
alizlt socket llomnylerjval tr vissza. Ltrehozsakor a sockethez egy
meghatrozott protokollt rendelnk, m ezek utn mg nem kapcsoldik se-
hov. Ebben az llapotban mg nem olvashat vagy rhat:
6. fejezet: Hlzati kommunikci
#include <sys/socket.h>
int .ocket (i nt domain, nt type, int protocol);
Mint az openO, a socket() is 0-nl kisebb rtkkel tr vissza hiba esetn, s ha
sikeres, az llomnylerval, amely 0 vagy annl nagyobb.
Hrom paramter definilja a hasznland protokollt. A domain a proto-
kollcsaldot adja meg, s rtke a 6.1. tblzatban tallhat lista valamelyike:
6.1. tblzat. A protokolcsctldokhoz tartoz rtkek
Protokoll Jelents
PF_UN1X, PF_LOCAL Unix domain socket (gpen belli kommunikci)
PF INET IPv4 protokoll
PF INET6 IPv6 protokoll
PF IPX Novell IPX
PF NETLINK A kernel felhasznli interfsze
PF X25 X.2 5 protokoll
PF AX25 AX.2 5 protokoll, a rdiamatrk hasznljk
PF ATMPVC Nyers ATM-csomagok
PF APPLETALK AppleTalk
PF PACKET Alacsony szint csomaginterfsz
A kvetkez paramter, a type, a protokollcsaldon bell a kommunikci
mdjt definilja a 6.2. tblzatban tallhat rtkek egyikvel.
6.2 . tblzat. A kommunikci lehetsges mdjai
Tpus Jelents
SOCK STREA11
,
1
Sorrendtart, megbzhat, ktirny, kapcsolatalap
byte-folyam-kommunikcit valst meg.
SOCK DGRA111
Datagramalap (kapcsolatmentes, nem megbzhat)
kommunikci.
SOCK SEQPACKET
Sorrendtart, megbzhat, ktirny, kapcsolatalap
kommunikcis vonal, fix mret datagramok szmra.
SOCK RAW Nyers hlzatiprotokoll-hozzfrst tesz lehetv.
SOCK RDM
Megbzhat datagramalap kommunikcis rteg. (Nem
sorrendtart.)
SOCK PACKET Elavult opci.
2 66
6.2 . Az sszekttets-alap kommunikci
Az utols paramter, a protocol, a protokollcsaldon bell konkretizlja a pro-
tokollt az adott kommunikcis mdhoz. A csaldokon bell ltalban csak
egy protokoll ltezik egy tpus kommunikcira, amely egyben az alaprtel-
mezett. gy ennek a paramternek az rtke leggyakrabban O. Pldul a
PF_INET csaldon bell a TCP (Transmission Control Protocol) az alapr-
telmezett folyamprotokoll, s az UDP a datagramalap.
m egy kivtelt is mutathatunk. Ez a SOCK RAW kommunikcis md.
A SOCK RAW md pldul a PF INET csald vlasztsval lehetv teszi
olyan socketek ltrehozst, ahol az IPv4 kommunikcis protokoll implemen-
tlst a felhasznli tartomnyban vgezzk el. m ennl tbbre is kpes.
Az utols, protocol paramterknt megadhatunk a 0 mellett olyan rtkeket
is, mint az IPPROTO_RAW, az IPPROTO_ICMP, az IPPOROTO_IGMP, az
IPPROTO TCP, az IPPROTO_UDP. Ezzel olyan protokollokat is elrhetnk
a csaldbl, amelyet a tbbi paramterrel nem (ICMP, IGMP).
78
A kommunikcis tpusok listjt vgignzve lthatjuk, hogy alapveten
kt rszre oszlanak: a kapcsolat- vagy sszekttets-alap, illetve a kapcsolat
vagy sszekttets nlkli kommunikci. Az sszekttets-alap kommuni-
kci egy kapcsoldsi folyamattal kezddik, amelynek eredmnyekppen egy
folyamatos kapcsolatot hozunk ltre kt fl kztt. Ennek sorn lnyegben
egy ktirny csatorna jn ltre, amelyen a programok oda-vissza kommuni-
klhatnak. A kommunikci vgn pedig le kell bontani a csatornt.
Az sszekttets nlkli kommunikci esetben viszont elmarad a kapcso-
ldsi folyamat. A kikldtt csomagjainkat kln-kln cmezzk s kldjk a
tbbi kommunikcis rsztvevnek. Tovbb brkitl kaphatunk is csomagot.
A kommunikci vgn a kapcsolatot sem kell lebontanunk, csak abbahagy-
juk a kommunikcit.
Analgiaknt nzhetjk a telefonlst s az SMS-kldst. A telefonls a
kapcsolatalap kommunikcira hasonlt. Trcsznunk kell a kommunikci-
s partnernket, neki fogadnia kell a hvst, beszlgetnk, s a vgn bon-
tunk. Az SMS esetn azonban nem kell vgigvinnnk a hvsi folyamatot,
csak megcmezzk az zenetet, s elkldjk. Ugyangy brmikor kaphatunk
msoktl is zeneteket.
6.2. Az sszekttets-alap kommunikci
Els lpsknt az sszekttets-alap kommunikcit tekintjk t. Ennek a
kommunikcis mdnak lnyeges rsze a kapcsolat felptse Amikor ez lt-
rejn, a kommunikci hasonlan trtnik, mint korbban a csvezetkeknl
lttuk. Majd a prbeszd vgn valamelyik fl bontja a kapcsolatot. Nzzk
meg sorban ezeket a mveleteket.
78
A SOCK RAW mdot csak rendszergazdai jogosultsgokkal fut folyamatokban hasznl-
hatjuk.
2 67
6. fejezet: Hlzati kommunikci
6.2.1. A kapcsolat felptse
Ha egy sszekttets-alap kapcsolatotadatfolyam-socketet (stream socket)
hoztunk ltre, akkor hozz kell kapcsoldnunk egy msik gphez. A socket
kapcsoldsa aszimmetrikus mvelet, vagyis a ltrejv kapcsolat kt oldaln
a feladatok eltrnek egymstl. A kapcsolat felptst kveten a kommuni-
kci viszont mr szimetrikus.
A kliensoldalon a socket ltrehozsa utn kapcsoldunk (connect) a szer-
verhez. Ha a kapcsolds sikeres (a szerver elfogadja a kapcsoldsi krel-
met), akkor a socketen mint llomnylern keresztl tudunk adatot kldeni
s fogadni. Ezt a tpus socketet klienssocketnek nevezzk.
A szerver s a kliens kzti lnyeges klnbsg a kapcsolat felptsben s
a kezelend socketek szmban rejlik. Ennek megfelelen a szerveroldalon kt-
fajta socket tallhat. Az egyiket a tovbbiakban szerversocketnek hvjuk.
Funkcija szerint vrakozik (listen) egy cmen, amelyet elre megadtunk (bind),
s arra vr, hogy a kliensoldali socketek kapcsoldjanak (connect) hozz. Ha
egy kapcsoldsi krelem rkezik, a szerver elfogadja (accept), ennek eredm-
nyekppen ltrejn egy klienssocket. Ezen keresztl trtnik az adatcsere.
A kapcsoldsi krelem elfogadsa utn a kommunikci a szerversockettl
fggetlenl zajlik, a szerversocket csak tovbbi kapcsoldsi krelmekre vr.
A szerveroldalon ezrt gyakran tbb klienssockettel kell trdnnk.
6.2.2. A socket cmhez ktse
Ahhoz, hogy a kliens meg tudja cmezni a szervert a kapcsoldskor, a szerver-
nek az adott cmhez kell ktnie a socketjt. Ez egy olyan helyi cm, ahol a szer-
ver a bejv kapcsolatokat vrja. A kliensprogramnl is lehetsg van loklis
cm megadsra, ez azonban nem ktelez, mert nem hivatkozunk a cmre.
Ilyenkor a rendszer automatikusan egy cmet generl a kapcsoldskor.
A cmhozzrendels mvelett ktsnek (binding) nevezzk, s a bind()
rendszerhvssal tehetjk meg:
#include <sys(socket.h>
int b nd(i nt sock , struct sockaddr *my_addr, socklen_t addrlen);
Az els paramter a socket lerja, a msodik a cmet ler struktra, az utol-
s a cmet ler struktra hossza. A cmstruktra alakja itt nincs specifiklva,
mivel protokollonknt eltr a cmbrzols. Mindig az adott protokoll cm-
alakjt hasznljuk. Mivel az egyes cmtpusoknak a mretignye eltr, ezrt
kell megadnunk a cm hosszt.
268
6.2. Az sszekttets-alap kommunikci
6.2.3. Vrakozs a kapcsoldsra
A cmhez kttt socketnk nmagban mg nem alkalmas a kapcsolatok fo-
gadsra, mg nem lesz belle szerversocket. A processz a listen() rendszerh-
vssal lltja be a socketre ahhoz, hogy fogadja a kapcsoldsokat, majd a
kernel kezeli a kapcsoldsi ignyeket. Egy kapcsoldsi igny berkezse
utn azonban mg nem pl fel azonnal a kapcsolat. A vrakoz processznek
az acceptO rendszerhvssal kell elfogadni a kapcsoldst. Azokat a kapcsol-
dsi ignyeket, amelyeket az accept0-tel mg nem fogadott, fggben lv
kapcsolatnak (pending connection) nevezzk.
Norml esetben az accept() fggvny blokkoldik, amg egy kliens kapcso-
ldni nem prbl hozz. Termszetesen tllthatjuk az fenti() rendszerhvs
segtsgvel nem blokkold mdba is. Ilyenkor az accept0 azonnal visszatr,
amikor egyetlen kliens sem prbl kapcsoldni. Mivel a szerversocket is llo-
mny, a selectQ vagy a poll() rendszerhvst is alkalmazhatjuk a kapcsoldsi
ignyek szlelsre. Ezekben az esetekben a szerversocketre rkezett kapcso-
ldsi igny mint olvassi esemny rzkelhet.
A listen() s az accept() fggvnyek formja a kvetkez:
#include <sy s/sock eth>
int listen(int sock, int backlog);
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
Els paramterknt mindkt fggvny a socket lerjt vrja. A listen() m-
sodik paramtere, a backlog, amely megadja, hogy hny kapcsoldni kvn
socket krelme utn utastsa vissza az jakat. Vagyis ez a fggben lv kap-
csolatok vrakozsi lista mrete.
Az accept0 fogadja a kapcsoldsokat. Visszatrsi rtke az j kapcsolat
lerja, egy klienssocket. Az addr s az addrlen paramterekben a msik ol-
dal cmt kapjuk meg. Az addr ltal mutatott struktrba a cm, az addrlen
ltal mutatott vltozba pedig a cm mrete kerl.
6.2.4. Kapcsolds a szerverhez
A kliens a ltrehozott socketet a szerverhez hasonlan a bind0 rendszerh-
vssal hozzrendelheti egy helyi cmhez. Ezzel azonban a kliensprogram lta-
lban nem trdik, a kernelre bzza, hogy ezt automatikusan megtegye.
Ezek utn a kliens a connectO rendszerhvssal kapcsoldhat a szerverhez:
#include <sys/socket.h>
int connect(int sock, struct sockaddr *addr, socklen_t addrlen);
269
Kliens
Szerver
socket()
connect()
socket()
bind()
(isten()
accept()
6. fejezet: Hlzati kommunikci
Az els paramter a socket lerja, a tovbbi paramterek a szerversocket c-
mt adjk meg.
A kapcsolat felplst a 6.1. bra mutatja.
Kommunikci
write() read()
read() 4 write()
close() close()
6.1. bra. Az sszekttets-alap kommunikci
6.2.5. A kommunikci
A kapcsolat felptst kveten a szerveroldalon az accept0 ltal visszaadott
klienssocketet, kliensoldalon pedig a kapcsolathoz ltrehozott socketet kt
sszekapcsolt llomnylerknt hasznlhatjuk, mint korbban a csvezet-
keknl. Amit az egyik oldalon a write() fggvnnyel belerunk, azt a msik ol-
dalon a read0 fggvnnyel olvashatjuk. m eltren a csvezetkektl a
kommunikci ktirny, vagyis mindkt oldalon rhatunk s olvashatunk is
6.2.6. A kapcsolat bontsa
A socketkapcsolat lebontsa tipikusan az llomnyoknl megismert close0
rendszerhvssal trtnik Ha a kapcsolat egyik vgt lezrjuk, akkor azt a
msik oldal is rzkeli, amikor legkzelebb olvassa a kapcsolat klienssocket-
jt. Ekkor a socket mr nem hasznlhat tovbbi kommunikcira, ezrt a le-
rt a tloldalon is lezrjuk.
270
6.2. Az sszekttets-alap kommunikci
A shutdown0 rendszerhvs lehetsget ad arra is, hogy a ktirny
kommunikcibl csak az egyik irnyt zrjuk le:
#include sys/socket.h>
int shutdown(int sockfd, int how);
Az els paramter a socket lerja. A msodik a lezrs mdjt adja meg a
6.3. tblzatban tallhat rtkek kzl.
6.3, tblzat. A shutdown mdjai
Tpus Jelents
SHUT RD Csak az olvassi gat zrjuk le. Az olvass llomny vge" jel-
zst (0 visszatrsi rtk) ad vissza. rni tovbbra is tudunk a
socketbe.
SHUT WR Csak az rsi gat zrjuk le. Amikor a tloldal teljesen kiolvasta
a korbban elkldtt tartalmat, egy llomny vge" jelzst kap.
A tovbbi rsi prblkozsra hibt kapunk, olvasni viszont to-
vbbra is tudjuk.
SHUT RDWR Mind az olvassi, mind az rsi gat lezrjuk. Mintha az elz
kt lezrst egyarnt elvgeznnk.
Ha a shutdown0 rendszerhvst a SHUT RDWR opcival hvjuk meg, akkor
a mkds hasonlt a close() rendszerhvsra. Nhny jelents eltrs azon-
ban van a kt megolds kztt.
A close0 az llomnylert zrja le, mg a shutdown0 a kommunikcis
csatornt. Vagyis ha a dup0 rendszerhvssal a socketlerrl msolatot k-
sztnk, akkor a close0 csak egy lert zr le. A kapcsolat csak akkor zrdik
le, ha minden lert lezrtunk. Ezzel szemben, ha a shutdown0-t brmelyik
msolatra meghvjuk, akkor lezrja a kapcsolatot, s a tbbi msolaton ke-
resztl sem folytathatjuk a kommunikcit. Ha a msolat a fark() rendszerh-
vs hatsra szletik, akkor is hasonl a helyzet.
Ugyanakkor a shutdown0 nem zrja le az llomnylert. Ezrt hasznla-
ta utn a close0 meghvsra van szksg.
6.2.7. Tovbbi kapcsolatok kezelse a szerverben
A 6.1. brn lthat kommunikcis folyamat sorn a szerver csak egy kap-
csolatot kpes kiszolglni, hiszen a kapcsolat felplse utn nem hvja meg
ismt az accept() fggvnyt. A szerverek tbbsgnl azonban nem ez a kvnt
mkdsi md. A tipikus elvrs az, hogy egy szerver tbb kapcsolatot is k-
pes fogadni, s prhuzamosan kiszolglja a klienseket. Ennek megvalsts-
hoz a szerverimplementcinkban prhuzamosan kell kommuniklnunk a
271
1. fl 2. fl
socket()
bind()
socket()
bind0
6. fejezet: Hlzati kommunikci
kliensekkel a klienssocketeken keresztl, kzben ismt meg kell hvnunk az
accept() fggvnyt a szerversocketre. (A 6.5.12.2. TCP szerver alkalmazs al-
fejezetben lthatunk majd pldkat a szerverfeladatok prhuzamostsra.)
6.3. Az sszekttets nlkli kommunikci
sszekttets-alap kommunikci esetn a kommunikcit megbzhat adat-
folyamknt foghatjuk fel. Ez egyrszt knyelmes megolds, mert nem kell fog-
lalkoznunk azzal, hogy az adat, amelyet elkldtnk, valban clba rt-e: a
kommunikcit vgrehajt fggvnyek jelzik a hibt vagy a kapcsolat bontst.
Msrszt azonban az adatok szinkronizcija tbb csomagforgalmat s
kernelerforrs-hasznlatot (CPU, memriabufferek, idztk) is jelent. Ezrt olyan
alkalmazsok esetn, ahol nem tl nagy problma", ha elveszik egy-egy"
csomag, ott alkalmazhatunk sszekttets nlkli megoldst, amely egyben
gyorsabb kommunikcit eredmnyez. Ilyenek tipikusan a multimdia-alkal-
mazsok, hiszen ha egy zene hangmintit kldjk el, nem jelent szmottev
minsgromlst egy-egy keret kimaradsa, valamint, ha ksn rkezik, nem
is tudunk mit kezdeni vele, hiszen mr elrbb tartunk a lejtszsban.
Az sszekttets nlkli kommunikci esetn ltrehozunk egy socketet
(socket()), s egy cmhez rendeljk (bind()). Ezen keresztl fogadjuk a hozznk
rkez csomagokat (datagram). Ugyanakkor nemcsak fogadjuk a csomagokat,
de kldnk is a tbbi alkalmazs szmra. m mivel ltrejtt kapcsolat hjn
a rendszer nem tudhatja, kinek sznjuk a csomagokat, ezrt egyesvel meg is
kell cmeznnk ket. gy a korbban ltott read/write fggvnyek itt nem
mkdnek.
Kommunikci
sendto() recvfrom()
recyfrom() sendto()
....... ................................ 4
,
close() close()
6.2. bra. sszekttets nlkli kommunikci
272
6.3. Az sszekttets nlkli kommunikci
A 6.2. bra mutatja az sszekttets nlkli kommunikci ltrehozsnak a
menett. A kt oldal ebben az esetben szimmetrikus, szemben a korbban l-
tott sszekttets-alap kommunikcival. Mindkt oldal mkdik kezdem-
nyezknt s fogadknt is. St valjban nem is csak kt oldal van, hanem
tbb kommunikcis fl is elkpzelhet.
Ahhoz, hogy a hozznk rkez csomagokat fogadni tudjuk, a socketnket
hozz kell ktnnk egy cmhez. Lehetsgnk van azonban arra, hogy a kt
kommunikcis fl esetben csak az egyiknl vgezzk el a cmhez ktst.
Ebben a struktrban a bind() fggvnyt hasznl oldal lesz a szerver, a di-
namikuscm-hozzrendelst hasznl oldal a kliens. Felvetdik a krds,
hogyan derti ki a szerver a kliens cmt, s kld neki csomagot. Ehhez az
szksges, hogy a kliens kezdemnyezze a kommunikcit az els csomag el-
kldsvel. A szerver fogadva a csomagot megtallja benne a kliens cmt.
Ezt kveten a szerver a kapott cmre vlaszcsomagot tud kldeni.
6.3.1. A kommunikci
Lthatan az sszekttets nlkli kommunikci esetben a korbban meg-
ismert readO s write() fggvnyek nem hasznlhatk. Ennek az az oka, hogy
nem adatfolyam-jelleg kommunikcit vgznk, hanem csomagokat keze-
lnk. Ez mg megoldhat is lehetne az absztrakcis interfszen keresztl,
msik nagy hinyossguk azonban az, hogy nem tmogatjk a cmkezelst.
gy helyettk a recufromQ s a sendto() fggvnyeket kell hasznlnunk.
sszekttets nlkli kapcsolat esetn teht az adatfogads az
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sock fd, void *buf, size_t len, int flags,
struct sock addr*src_addr, socklen_t *addrlen);
fggvnnyel trtnik. Az els hrom paramter a readO fggvnybl mr is-
mers lehet. A sockfd a socket lerja, a buf a buffer mutatja, amelybe az
adatokat vrjuk. A len a buffer mrete. Ha a megadott buffer rvidebb, mint
amekkora hosszsg adat rkezett, akkor a recyfrom() a csomag vgt au-
tomatikusan levgja.
A flags paramter socketspecifikus I/O belltsokra szolgl. Ezeket bveb-
ben a mm() fggvnynl trgyaljuk (lsd a 6.5.12. sszekttets-alap kommu-
nikci alfejezetben). A src_addr paramterben egy cmstruktra mutatjt
vrja a fggvny, ha szeretnnk visszakapni tle a csomag forrscmt. Ezt a
struktrt elre le kell foglalnunk, s az addrlen paramterben adjuk t
a mrett. A visszakapott cm mrett szintn az addrlen paramterben kap-
juk meg. Ha nem vagyunk kvncsiak a csomag forrsra, akkor NULL mu-
tatk megadsval ezt a szolgltatst kikapcsolhatjuk.
273
6. fejezet: Hlzati kommunikci
Ameddig nem rkezik adat, a recyfrom() fggvny vrakozik, majd ezt k-
veten az adatok mennyisgvel vagy hibt jelz mnusz rtkkel tr vissza,
ahogy a read0 fggvnynl trtnik.
Az sszekttets nlkli kapcsolatok esetn kldsre az
#include<sy s/ty pes.h>
#include<sy s/sock et.h>
ssize_tsendto(intsock fd,constv o d*buf,size_tlen,intflags,
conststructsock addr*dest_addr,sock len_taddrlen);
fggvnyt hasznljuk. Mint az elz esetben, az els hrom paramter hasonlt
a writeQ fggvny paramtereire. A sockfd a socket lerja, a buf a buffer muta-
tja, amelyben az adatok tallhatk. A len a bufferben lv adatok mrete.
A flags paramter socketspecifikus I/O belltsokra szolgl. Ezeket b-
vebben a send0 fggvnynl trgyaljuk (lsd a 6.5.12. sszekttets-alap
kommunikci alfejezetben). A dest_addr paramterben egy cmstruktra
mutatjt vrja a fggvny, amely a clcmet tartalmazza. A struktra mre-
tt az addrlen foglalja magban.
A fggvny addig blokkoldik, amg az adatokat a protokollkezel rend-
szer a kimen bufferbe bele nem tudja rni. Ezt kveten visszatr az elkl-
dtt byte-ok szmval.
6.3.2. A connect() hasznlata
Br az sszekttets nlkli kommunikci esetn nem ptnk fel kapcsolatot
a kt fl kztt, a connectO fggvny mgis hasznlhat Ekkor valjban nem
kapcsolatot hoz ltre, hanem csak bejegyzi a megadott clcmet. gy a csomagok
kldsnl nem kell megadnunk mindig a clcmet, mert a connectO-nl meg-
adottakat hasznlja. Ezltal lehetv vlik a readQ s a writeQ fggvnyek
hasznlata is csomagok kldsre s fogadsra.
Az albbi lista sszefoglalja a connectQ fggvny hatsait arra a socketre,
amelyre meghvtuk:
A writeQ fggvnnyel (vagy a ksbb trgyalt send() fggvnnyel) ki-
kldtt csomagok mind a connectO fggvnyben megadott cmre r-
keznek.
A socketen keresztl csak olyan csomagokat kapunk meg, amelyek a
connect0-ben megadott cmrl rkeznek.
A tloldal nem rzkeli, hogy a connect() fggvnyt hasznltuk, mivel
nem pl fel kapcsolat.
274
6.4. Unix domain socket
6.3.3. A socket lezrsa
A socketet mindkt oldalon a closeQ fggvnnyel zrhatjuk le. Kapcsolat hi-
nyban azonban ez nem jelent kapcsolatzrst, s a tloldal nem rzkeli,
hogy lezrtuk a socketet. Csupn annyi trtnik, hogy a tovbbiakban nem
fogadjuk a csomagokat.
6.4. Unix domain socket
A Unix domain socket a legegyszerbb protokollcsald, amely a socket-API-n
keresztl elrhet. Valjban nem hlzati protokoll. Csak egy gpen bell
kpes kapcsolatokat felpteni. Habr ez komoly korltoz tnyez, mgis sok
alkalmazs hasznlja, mivel flexibilis IPC-mechanizmust nyjt. A cmei l-
lomnynevek, amelyek az llomnyrendszerben jnnek ltre. Azok a socket-
llomnyok, amelyeket ltrehoz, a stat() rendszerhvssal vizsglhatk, m
nem lehet megnyitni az open() fggvnnyel ket. Helyette a socket API-t kell
hasznlni.
A Unix domain socket tmogatja mind az adatfolyam- (stream), mind a
csomag- (datagram) kommunikcis interfszt, a datagram interfsz azonban
ritkn hasznlatos. A stream interfsz a megnevezett csvezetkekhez hason-
lt, m nem teljesen azonos velk.
Ha tbb processz megnyit egy megnevezett csvezetket, akkor egyikk ki-
olvashatja belle, amit egy msik belert. Lnyegben olyan, mint egy hirdet-
tbla. M egyik processz elkld egy zenetet r, egy msik pedig elveszi onnan.
Ezzel szemben a Unix domain socket kapcsolatorientlt. Minden kapcso-
lat egy-egy j kommunikcis csatorna. A szerver egyszerre tbb klienskap-
csolatot kezelhet, s mindegyikhez kln ler tartozik. E tulajdonsgok
rvn alkalmasabb az IPC-feladatokra, mint a megnevezett csvezetk, ezrt
sok Linux-szolgltats alkalmazza, tbbek kzt az X Window System s a
naplrendszer s.
6.4.1. Unix domain socket cmek
A Unix domain socket cmek llomnynevek a fjlrendszerben. Ha az llo-
mny nem ltezik, akkor a rendszer, amikor meghvjuk a bind() fggvnyt,
socket tpus llomnyknt ltrehozza. Ha az llomnynv mr hasznlt, ak-
kor a bindQ hibval tr vissza (EADDRINUSE). A bind() a 0666-t lltja be
jogosultsgnak (mdostva az umask rtkvel).
Ahhoz, hogy a connect() rendszerhvssal kapcsoldhassunk a sockethez,
olvassi s rsi joggal kell rendelkeznnk a socketllomnyra.
275
6.fej ezet:H lzatik ommunik ci
A Unix domain socket cmeinek megadshoz a struct sockaddr_un struk-
trt hasznljuk:
#include<sy s/sock et.h>
#include<sy s/un.h>
structsock addr_un
unsignedshortsun_fam ly ; /*AF_UNIX
*/
charsun_path[uNIX_P ATH_MAx];/*eleresi u t * /
;
A sunjamily meznek, AF UNIX-nak kell lennie. Ez jelzi, hogy Unix domain
socket cmet tartalmaz. A sun_path tartalmazza az llomnynevet C-string-
knt, vagyis egy '\0' karakterrel lezrva. A rendszerhvsokban hasznlt cm-
struktramret az llomnynv hossza, plusz a sunjamily elem mrete. Br
hasznlhatjuk a teljes struktramretet is, hiszen az llomnynevet lezrtuk.
6.4.2. Unix domain socket adatfolyam
szerveralkalmazs
Az sszekttets-alap szerveralkalmazs felptse megegyezik a korbban
a 6.2. Az sszekttets-alap kommunikci alfejezetben trgyaltakkal, kieg-
sztve a Unix domain socket kommunikciban hasznlt cmzssel.
Feladat K sz tsnk egy Unixdomainsock etszerv eralk almaz st,amely fogadj aak liensek k ap-
csolatait(egy szerreegy et), satlk k apottadatok atk i rj aazalap rtelmezettk imenetre.
A megolds a kvetkez:
/*uszerv er.c- Egy szeru peldaszerv eraUnixdomainsock et
hasznalatara.*/
#include<stdio.h>
#include<sy s/sock et.h>
#include<sy s/un.h>
#include<unistd.h>
intmain(v oid)
structsock addr_unaddress;
intsock ,conn;
sock len_taddrlen;
charbuf[102 4];
intamount;
276
/*Fogadj uk azadatok at.*/
printf("Adatok erk eznek ...\n");
while((amount=read(conn,buf,sizeof(buf)))>0)
if(write(STDOUT_FILENO,buf,amount)!=amount)
perror("write");
return-1;
}
}
if(amount<0)
perror("read");
return-1;
277
6.4. Unix domain socket
/*Letrehozzuk asock etet.*/
1f((sock =sock et(FF_UNIX,SOCK_STREAM,0))<0)
perror("sock et");
return-1;
/*Letorolj uk ak orabb sock etallomany t.*/
unlink ("./sample-sock et");
memset(&address,0,sizeof(address));
address.sun_family =AF_UNIX;
strncpy (address.sun_path,"./sample-sock et",
sizeof(address.sun_path)-1);
/*Atelj es Cirrl hossztartalmazzaasun_family elemetesaz
eleresiuthosszat.*/
addrlen=sizeof(address.sun_family )+
strnlen(address.sun_path,sizeof(address.sun_path));
/*Asock etethozzak otj uk ac mhez.*/
if(bind(sock ,(structsock addr*)&address,addrlen))
perror("bind");
return-1;
/*Bek apcsolj uk ak apcsolodasrav alov arak ozast.*/
if(listen(sock ,5))
perror("listen");
return-1;
}
/*Fogadj uk ak apcsolodasok at.*/
while((conn=accept(sock ,(structsock addr*)&address,
&addrlen))>=0)
{
6. fejezet: Hlzati kommunikci
prntf("...vege\n");
/* Bontjuk a kapcsolatot.
* /
close(conn);
if(conn < 0)
perror("accept");
return -1;
/* Lezarjuk a szerver socketet. */
close(sock);
return 0;
Ez az elg egyszer pldaprogram bemutatja a szksges rendszerhvsokat,
viszont egyszerre egy kapcsolat lekezelsre alkalmas. (Termszetesen k-
szthetnk ennl bonyolultabb, tbb kapcsolat prhuzamos kezelsre is al-
kalmas megoldsokat.)
Az ltalnos socketkezelshez kpest lthatunk a programban egy unlink0
hvst. Erre azrt van szksg, mert ha mr az llomny ltezik, a bind0 hib-
val trne vissza, akkor is, ha az llomny socketllomny.
6.4.3. Unix domain socket adatfolyam
kliensalkalmazs
A kliensalkalmazs termszetesen ugyancsak kveti a socketeknl mr ismerte-
tett mdszereket, a Unix domain socket kommunikcinl trgyalt cmzssel.
Feladat Ksztsk el az elz fejezetben ltott szerver kliensprjt. A kliens az alaprtelme-
zett bemeneten fogadja az ltalunk bert szveget, s ezt a kapcsolaton keresztl kldje el a
szervernek.
A kvetkez program egy plda a megoldsra:
/* ukliens.c - Egyszeru peldakliens a Unix domain socket
hasznalatara. */
#include <stdio.h>
#include <stdlib.h
#include <sys/socket.h>
#include <sys/un.h>
#include <unstd.h>
278
6.4. Unix domain socket
(
intmainCv oid)
I {
structsock addr_unaddress;
intsock ;
size_taddrlen;
charbuf[102 4];
intamount;
/*Letrehozzuk asock et-et.*/
if((sock =sock et(P F_UNIX,SOCK_STREAM,0))<0)
perror("sock et");
return-1;
memset(&address,0,sizeof(address));
address.sun_family =AF_UNIX;
strncpy (address.sun_path,"./sample-sock et",
sizeof(address.sun_path)-1);
/
4
Atelj escimhossztartalmazzaasun_family elemetesaz
eleresiuthosszat.*/
addrlen=sizeof(address.sun_family )+
strnlen(address.sun_path,sizeof(address.sun_path));
/*Kapcsolodunk aszerv erhez.*/
if(connect(sock ,(structsock addr*)&address,addrlen))
perror("connect");
return-1;
/*Elk uldj uk azadatok at.*/
while((amount=read(STDIN_FILENO,buf,sizeof(buf)))>0)
if(write(sock ,buf,amount)!=amount)
I
{
perror("wTite");
ret urn
.
i
} }
if(amount<0)
{
perror("read");
O
.
i l f i l
return-1;
}
/*Bontj uk ak apcsolatot.*/
close(sock );
return0;
279
6. fejezet: Hlzati kommunikci
6.4.4. Unix domain socket datagram kommunikci
Az elz fejezetekben lthattuk az ltalnos sszekttets-alap kommunik-
cis megoldsok alkalmazst a Unix domain socket protokollra. Ezekkel
analg mdon az sszekttets nlkli datagramkommunikci is az ltal-
nos fggvnyeket alkalmazza kiegsztve a Unix domain socket cmzssel.
Ezrt datagramkommunikcira pldt majd csak az IP-kommunikci tr-
gyalsnl mutatunk
tmutat Br a datagramkommunikci nem megbzhat s nem sorrendtart a specifikcik
rtelmben, ez a Unix domain socket protokoll esetben nem igaz. Mivel a kommunikci csak
loklisan, a kernel mechanizmusain keresztl trtnik, gy garantlt, hogy nem vesznek el
csomagok, s nem cserldik fel a sorrendjk.
6.4.5. Nvtelen Unix domain socket
Mivel a Unix domain socket egy sor elnnyel rendelkezik a csvezetkekkel
szemben (ilyen pldul a ktirny kommunikci), ezrt gyakran alkalmaz-
zk IPC-kommunikcihoz. A hasznlatukat megknnytend ltezik egy
socketpair0 rendszerhvs, amely egy pr sszekapcsolt, nv nlkli socketet
hoz ltre:
include <sys/types.h>
#include <sys/socket.h>
i nt socketpai r(int domain, int type, int prot, int sockfdsl2]);
Az els hrom paramter megegyezik a socket0 rendszerhvsnl trgyaltak-
kal. Az utols paramter, a sockfds, tartalmazza a visszaadott socketlerkat.
Szemben a nvtelen csvezetkekkel a kt ler egyenrtk.
6.4.6. A Linux absztrakt nvtere
A Unix domain socket kommunikci sorn cmknt socketllomnyokat
hasznlva szembeslhetnk nhny problmval:
A socketllomnyokat rendszeresen trlnnk kell, mert ha az llo-
mny ltezik, akkor a bindO hibval tr vissza.
Ha megszakad a program, akkor ott marad az llomnyrendszerben a
socketllomny.
280
6.4. Unix domain socket
Elfordulnak olyan helyzetek, amikor nincs jogosultsgunk llomnyt
ltrehozni.
Hasznlhatunk olyan llomnyrendszert, amely nem tmogatja a soc-
ketllomnyokat.
Ezek a problmk mnd azt mutatjk, hogy az llomnyok hasznlata cm-
knt sokszor gondot jelent. Ugyanakkor a Linux ms rendszerektl eltren
tartalmaz egy plusz szolgltatst, amellyel elkerlhetjk az llomnynevek
hasznlatt. Ez a szolgltats az absztrakt nvtr.
Az absztrakt nvtr hasznlata egyszer. Alapesetben a cmstruktra
sun_path eleme egy C-sztringet tartalmaz, vagyis nem null karakterek soro-
zatt a vgn lezrva egy '\0' karakterrel. Ha absztrakt nevet szeretnnk
megadni, akkor ettl eltren egy '\0' karakterrel kell kezdennk a mezt,
majd az ezt kvet karakterek tartalmazzk az azonostt. m ebben az eset-
ben nem jelezhetjk 0' karakterrel az azonost vgt. gy a megadott sz-
veget teljesen a cmstruktra vgig veszi figyelembe a rendszer. Ezt azonban
befolysolhatjuk, amikor megadjuk a cmstruktra hosszt.
Nzznk erre egy pldt:
struct sockaddr_un address;
size_t addrlen;
memset(&address, 0, sizeof(address));
address.sun_family =AF_UNIX;
address.sun_path[0] =0;
strncpy(address.sun_path + 1, "myaddr",
sizeof(address.sun_path) - 2);
addrlen =sizeof(address.sun_family) +
strnlen(address.sun_path + 1, sizeof(address.sun_path) - 1) + 1;
A sun_path mez els elemnek belltjuk a 0-t. Ezt kveten a msodik byte-
tl bemsoljuk az ltalunk megadott szveget. A mret kiszmolsnl fi-
gyelnnk kell arra, hogy a szveg hosszt csak a msodik karaktertl mrjk,
illetve a kezd '\0' karaktert is hozzadjuk.
Hasonlan sszelltva a cmet mind a szervernl, mind a kliensnl a ko-
rbbi pldk tovbbra is mkdnek, de nem ignylik llomnyok ltrehoz-
st, illetve trlst.
tmutat Br ebben az esetben nem lthatjuk az llomnyrendszerben a cmeket, a netstat
programmal lehetsgnk van kilistzni a Unix domain socket szervereket, illetve kapcsolato-
kat. gy a cmknt hasznlt absztrakt neveket is lthatjuk.
281
6. fejezet: Hlzati kommunikci
6.5. IP
Az elz fejezetben a Unix domain socket protokoll hasznlatval csak egy
gpen bell kommuniklhattak a folyamataink. Ebben a fejezetben bemutat-
juk az Internet protokoll (IP) hasznlatt, amellyel mr lehetsgnk van
szmtgp-hlzaton keresztl kommunikcit felpteni klnbz szmt-
gpeken fut folyamatok kztt.
Az IP-kommunikci sorn is az eddig megismert socketkezel fggv-
nyeket alkalmazzuk. Eltrst nagyrszt csak a cmzsnl ltunk.
A fejezetben prhuzamosan ismertetjk az IP protokoll korbbi 4 -es ver-
zijnak (IPv4 ) s az j 6-os verzijnak (IPv6) hasznlatt. Jelenleg az IPv4
protokoll hasznlatos szles krben, m a programjainkban clszer felk-
szlnnk az IPv6 tmogatsra is, hogy a jvben hasznlhatk legyenek.
6.5.1. Rviden az IP-hlzatokrl
Mieltt ismertetnnk az IP protokollok hasznlatt, illetve az internetes
kommunikcit, rviden bemutatjuk az IP-hlzatok mkdst, hogy a k-
sbb trgyalt fogalmak rtelmet nyerjenek.
Kommunikci a hlzaton
Az internet loklis hlzatokbl pl fel, sok kisebb-nagyobb hlzatbl, ame-
lyeket tvonalvlasztk (routerek) kapcsolnak ssze. Ez azt is jelenti, hogy a
hlzati kommunikci egy loklis hlzaton bell lv szmtgpek kztt
mskppen zajlik, mint az egymstl tvoli, klnbz loklis hlzatokba
tartoz szmtgpek kztt.
Loklis hlzat
Loklis hlzatnak tekintend az a hlzat, amelyen bell kt szmtgp k-
ztt router kzbeiktatsa nlkl, kzvetlenl lehet kommuniklni. Ez tipiku-
san egy switchre,
79
vagy tbb switchbl ll struktrra UTP-kbellel kapcso-
ld szmtgpeket jelent. Szoktk ezt szegmensnek vagy alhlzatnak is
neve zni.
90
79
A switch olyan hlzati eszkz, amely a portjaira (csatlakozira) kapcsolt eszkzk kzt-
ti kommunikcit biztostja. Eldje a HUB, amely az egyik portjra rkez jeleket a tbbi
portjra tovbbtja. A switch ehhez kpest annyi tbbletintelligencival rendelkezik,
hogy a csomagokat megvizsglja, s csak arra a portjra tovbbtja, ahol a cmzett eszkz
tallhat.
8
Msfajta hlzattpusok is lteznek (Token bus, Token ring), m ezekkel a htkznapok
sorn ritkn tallkozunk
282
6.5. IP
Klasszikus esetben egy loklis hlzaton bell, ha az egyik szmtgp
elkld egy csomagot, akkor azt az sszes tbbi szmtgp megkapja, de csak
az hasznlja fel, amelyiknek szl. Hogy kinek szl, azt a cmzett gp hlzati
krtyjnak fizikai cme (MAC-cm, hardvercm stb.) hatrozza meg. Ez a cm
minden hlzati krtyra egyedi, s csak ennek ismeretben lehetsges a kt
szmtgp kztt kommunikcit megvalstani.
Manapsg a mkds csak annyiban tr el, hogy a switcheszkzk is
kpesek rtelmezni a fizikai cmet s megjegyezni, hogy melyik portjukon ta-
llhat az ezt hasznl gp. gy az optimalizci rdekben csak arra kldik
tovbb a csomagot.
Vagyis a kommunikci kt gp kztt a fizikai cmmel trtnik. Mirt
van szksg akkor az IP-cmre, mirt nem hasznlja a protokoll a fizikai c-
meket? Elszr is, mert knyelmetlen, nehezen megjegyezhet. De ami sokkal
fontosabb: elvileg mg megvltoztathatatlan
81
a hlzati krtya legyrtsa
sorn adott egyedi cm. gy garantljk, hogy egy loklis hlzaton vletlenl
se legyen kt egyforma fizikai cmmel rendelkez gp.
Mivel a fizikai cmeket a gyrtskor hatrozzk meg, ezrt semmilyen in-
formcit nem hordoz az alhlzattal kapcsolatban. nmagban a cmbl
nem tudjuk eldnteni, hogy a loklis hlzatunk tagja-e, vagy ha nem, akkor
hol tallhat a vilgban. Elvileg sszellthatnnk egy nyilvntartsi tblza-
tot, de ennek karbantartsa lehetetlen feladat lenne. Ezrt van szksg egy
msik cm hasznlatra is, s ez az IP-cm.
Hogyan dnthet el, hogy egy adott IP-cmmel rendelkez gpnek (cm-
zettnek) mi a fizikai cme? Erre szolgl az ARP (Address Resolution Protocol).
Ha egy gp egy msiknak akar csomagot kldeni, akkor els krben a
cmzett IP-cme s a hlzati maszk alapjn eldnti, hogy a clgp vele egyez
alhlzatnak a tagja-e, vagy sem (a mdszert lsd a 6.5.3. IPv4-es cmzs alfe-
jezetben).
Ha a clgp ugyanannak az alhlzatnak a tagja, akkor elkld egy broad-
cast- (mindenkinek szl) zenetet, amelyben megkrdezi, hogy melyik is az
adott IP-cmmel rendelkez szmtgp, s mi a fizikai cme. Az zenetet
mindenki veszi, de csak az vlaszol r, aki az adott IP-cm tulajdonosa, s el-
kldi a kezdemnyeznek a sajt fizikai cmt (a kezdemnyez a sajtjt ter-
mszetesen feltntette az zenetben). Ezt kveten a kezdemnyez hogy
ne kelljen folyton ARP-zeneteket kldzgetni elhelyezi a cmzettre vonat-
koz informcikat egy gyorsttrba (ARP Cache), s legkzelebb, ha ugya-
nazzal a cmzettel akar kommuniklni, akkor mr ebbl veszi az adatokat.
A fizikai cm kidertse utn mr csak annyi a feladat, hogy ezzel a fizikai
clcmmel kell a gpnek csomagokat kldenie, gy a clgp megkapja ket.
81
Gyakorlatban a gyrtsi folyamat egyszerstse miatt megvltoztathat, illetve szoftve-
resen fell is rhat.
2 83
6. fejezet: Hlzati kommunikci
Globlis hlzat
Mi trtnik akkor, ha olyan cmzettel akar egy szmtgp kommuniklni,
amelyik nincs vele egy szegmensen? Ekkor jut szerephez a router. A router
(tvlaszt) egy kitntetett szmtgp a szegmensen, amely egyszerre tbb
loklis hlzathoz is kapcsoldik, s amelyik ppen ezrt tbb szegmensbe is
tud adatot kldeni, gy lehetv teszi a szegmensek kztti kommunikcit.
Ha egy szmtgp egy msik szegmensben (ezt az alhlzati maszk segts-
gvel llaptja meg) lv gppel akar kommuniklni, akkor nem kzvetlenl a
cmzettel kezdemnyez kapcsolatot, hanem az alaprtelmezett routerrel (ez
minden gp esetben be van lltva). Ehhez persze elszr ARP-vel kiderti a
router fizikai cmt, majd elkldi az adatcsomagot, azzal az utastssal, hogy
a megadott IP-cmre kell eljuttatni.
Ezt kveten, ha a clcm valamelyik, a routerhez kapcsold alhlzathoz
tartozik, akkor a router ARP-vel kiderti ennek a fizikai cmt, s elkldi a
csomagot. Ha a cmzett semelyik, a routerhez kapcsold szegmenshez sem tar-
tozik, akkor a router is egy msik routerrel veszi fel a kapcsolatot, amely tbb
msik alhlzatot kezel routerrel is kapcsolatban ll, s annak kldi tovbb
a csomagot. Ezt a megoldst addig ismtli a rendszer, amg eljut egy olyan
szintre, ahol a router tudja, hogy a clgp alhlzata merre tallhat. Ezt k-
veten a csomag eljut a clalhlzat routerhez, amely tovbbtja a clgpnek.
Fontos megjegyezni, hogy kt szmtgp kztt ebben az esetben is csak
egy szegmensen bell s a fizikai cmek alapjn zajlik a kzvetlen kommuni-
kci. Szegmenseken kvlre kzvetetten (routerek kzbeiktatsval) kerl-
nek a csomagok.
6.5.2. Az IP protokoll rtegzdse
Az IP protokoll csaldot tbb protokollra s tbb rtegre bontjuk. A rtegeket
s a protokollokat a 6.3. bra szemllteti:
Alkalmazsok
TCP UDP
IP
Ethernet
Szlltsi rteg
Hlzati rteg
Adatkapcsolati rteg
6.3. bra. Az IP protokoll csald gyakrabban hasznlt elemei
284
6.5. IP
Az adatkapcsolati rteg biztostja a kommunikcit a hlzat elemei kztt.
A hlzati rteg teszi lehetv a csomagok eljutst a kldtl a cmzettig.
Az IP protokoll is ebben a rtegben tallhat, vagyis a legfbb feladata az,
hogy az interneten tallhat kt gp kztt megoldja a cmzst s az adatok
tovbbtst.
A szlltsi rteg biztostja, hogy az alkalmazsok kztt az adattvitel
transzparensen megvalsulhasson. Az UDP protokoll lnyegben az alkalma-
zsok megcmezhetsgvel (portok kezelse) egszti ki az IP-t. A TCP a por-
tok kezelse mellett mg a kapcsolat megbzhatsgt is garantlja.
6.5.3. IPv4-es cmzs
Az IP-cmek egyedek mnden hoszt esetben, s 32 bitbl (4 byte-bl) llnak.
Szoksos megjelensk a 4 byte pontokkal elvlasztva. Prbljuk meg lekr-
dezni sajt gpnk IP-cmt:
8ipaddr
1: lo:<LOOP BACK,UP ,LOwER_uP >mtu1643 6qdiscnoqueuestateUNKNOWN
link /loopback 00:00:00:00:00:00brd00:00:00:00:00:00
inet12 7.0.0.1/8scopehostlo
inet6::1/12 8scopehost
v alid_lftforev erpreferred_lftforev er
2 : eth0:<BROADCAST,mULTICAST,UP ,LOWER_UP >mtu1500qdisc
pfifo_faststateUP qlen1000
link /ether00:2 2 :3 f:dl:d3 :a7brdff:ff:ff:ff:ff:ff
i net192 .168.1.10/2 4brd192 .168.1.2 55scopeglobaleth0
i net6fe80::2 11:2 fff:fedl:d3 a7/64scopelink
v alid_lftforev erpreferred_lftforev er
Amikor egy szervezet hlzati adminisztrtora ignyel egy cmtartomnyt,
akkor kap egy 32 bites hlzati cmet s egy 32 bites hlzati maszkot. Ez a
kt szm meghatroz egy cmtartomnyt. Ezt a 6.4. bra szemllteti.
Hlzati cm
Hlzati maszk
Helyi cm
Idegen cm
il000000liolol000 ocw0000ll00000000
11111111111111111
4 - Hlzati Hoszt -
11000000 10101000 00000001 0 0 0 0 1010
10 0 110 0 0 01 0 0 0 0 1 0 101 111 01 0 0 0 0 1 0 10
6.4. bra. IPv4-es hlzati cm s maszk
~a
2 85
6. fejezet: Hlzati kommunikci
Egy IP-cmbl azok a bitek, ahol a hlzati maszk 1-est tartalmaz, a hlzati
cmet hatrozzk meg. Azok a bitek, ahol a maszkban 0 szerepel, az adott gp
egyedi hosztcmt adjk meg.
Vagyis egy hlzaton bell a szmtgpek egyedi IP-cmei csak azokban
a bitekben trhetnek el a hlzati cmtl, ahol a maszkban 0 szerepel. Ha az
IP-cm a maszk 1-es rtkeinl is eltr, akkor az mr egy msik alhlzatnak
az eleme.
Egy szmtgpen csak a gp egyedi IP-cmt s a hlzati maszkot szoktuk
megadni, mivel az elz sszefggsek alapjn ebbl a kt rtkbl a hlzati
cm elllthat. A megads sorn mg egy egyszerstssel szoktunk lni.
A hlzati maszkban nem keveredhetnek az 1-es s a 0-s rtkek. A maszk
elejn x darab 1-es, majd ezt kveten (32 x) darab 0 bit kvetkezik. gy a
maszk teljesen lerhat x-szel, amely egy szm 0 s 32 kztt. Ezt a szmot az
IP-cm utn egy 1" jellel elvlasztva rjuk. Pldul:
X.01Atitt ..10, -
A /2 4 " azt jelzi, hogy a maszk 2 4 darab 1-est majd 8 darab 0-t tartalmaz. Va-
gyis az els 2 4 bit a hlzati cmhez, a maradk 8 bit a hosztcmhez tartozik.
Ugyanez a maszk pontozott formtumban gy nz ki:
.Z. 5. 295. a ~: _
Egy tartomny els s utols cmnek specilis jelentse van. Ezeket szm-
tgpeknek nem adjuk ki. Az els cm, amikor a hosztcm bitjei vgig 0-k, a
hlzati cm. Az utols cm, amikor a hosztcm vgig 1-es a broadcastcm.
A broadcastcmre kldtt csomagokat az alhlzat minden gpe megkapja.
6.5.4. IPv4-es cmosztlyok
Manapsg a hlzati cmtartomnyok meghatrozst hlzati cm s hlzati
maszk alapjn vgezzk. Korbban azonban a tartomnyok meghatrozsa
az n. cmosztlyok alapjn trtnt. Ezt jelenleg mr nem hasznljk, m
idnknt mg mindig tallkozunk a cmosztlyok fogalmval.
Az IPv4 32 bites cme ebben az esetben is ktfel oszlik. Az els M bit egy
azonost, amely megmutatja a hlzat tpust, a kvetkez N bit a hlzat
cme, a maradk 32-M-N bit pedig az adott hlzaton bell egy szmtgp
cme. Attl fggen, hogy N rtkt mekkorra vlasztjuk, tbb hlzatot c-
mezhetnk meg (N-et nvelve), illetve tbb gpbl ll hlzatot cmezhetnk
meg (N-et cskkentve).
A cmosztlyokat a 6.4. tblzat foglalja ssze:
286
6.5. IP
6.4. tblzat. Cmosztlyok
Cm Els cm Utols cm Azonost
A osztly 1.0.0.0 12 7.2 55.2 55.2 55 0 7
B osztly 12 8.0.0.0 191.2 55.2 55.2 55 10 14
C osztly 192 .0.0.0 2 2 3.2 55.2 55.2 55 110 2 1
D osztly 2 2 4 .0.0.0 2 39.2 55.2 55.2 55 1110 Tbbes klds
E osztly 2 4 0.0.0.0 2 4 7.2 55.2 55.2 55 11110 Fenntartva
Feladat llaptsuk meg, hogy a www.aut.bme.hu szerver IP-cme milyen osztlyba tartozik.
$ping www.aut.bme.hu
PING www.aut.bme.hu (152.66.188.11) 56(84) bytes of data.
Amint a tblzat alapjn lthat, ez egy B osztly IP-cm, s ez nem megle-
p, hiszen a BME-hez elg sok gp tartozik, gy a hosztok megcmzshez 16
bitre van szksg (az A osztly esetn adott 2 4 sok lenne, a C osztlyban
hasznlt 8 kevs).
6.5.5. IPv4-es specilis cmek
A teljes IPv4 -es cmtartomnyban vannak olyan tartomnyok, amelyeknek
specilis a jelentse.
A 12 7.0.0.1 cm tipikusan a loopbackcm, amely arra hasznlatos, hogy a
folyamatok a sajt gpket megcmezzk, vagyis egy gpen bell folytassanak
IP-kommunikcit. Valjban a 12 7.0.0.0/8 tartomny brmelyik cmt lehet
erre a feladatra hasznlni, de az els cmet szoktk.
A 10.0.0.0/8, a 172 .16.0.0/12 s a 192 .168.0.0/16 privt IP-cmtartom-
nyok. Ez azt jelenti, hogy az interneten nem tallkozunk ilyen cmeket hasz-
nl gpekkel, mivel az tvonalvlasztk (router) nem tovbbtjk ezeket a
csomagokat. A sajt hlzatunkban szabadon hasznlhatjuk a privt cmtar-
tomny cmeit, kzvetlenl ezek a gpek azonban nem kommuniklhatnak az
interneten.
82
A 2 2 4 .0.0.0/4 D osztly cmtartomny cmeit a tbbes kldshez hasz-
nlhatjuk. A tbbes klds sorn egy-egy csomagot nemcsak egy gpnek, ha-
nem hosztok csoportjnak kldjk el. (Hasznlatt bvebben lsd a 6.5.13.2.
Tbbes klds alfejezetben.)
82
Ha privt cmeket hasznl szmtgpekkel el akarjuk rni az internetet, akkor cmfor-
dtst (network address translation, NAT) kell hasznlnunk.
287
6. fejezet: Hlzati kommunikci
6.5.6. IPv6-os cmzs
A 6-os verziszm IP-cmek ltrejttnek elsdleges oka az, hogy az eredeti
(4 -es verzij) IP-cmekbl kifogytunk. A problma megoldsra dolgoztk ki
az IPv6-ot, amely mr 12 8 bites cmeket hasznl.
Az IPv6 a 16 byte-os cmeken kvl szmos tbbletszolgltatst nyjt, gy
pldul:
automatikuscm-konfigurci,
fejlettebb tbbes klds,
az tvonalvlasztk (router) feladata egyszersdtt,
tbb tvonalvlasztsi opci,
mobilits,
hitelests,
adatbiztonsg.
A 16 byte-os IP-cmek lershoz rtelemszeren ms formtumot haszn-
lunk: a szmokat hexadecimlisan 4 -es csoportokra osztjuk kettsponttal el-
vlasztva, ez sszesen 8 csoportot jelent. Pldul:
0000:4200010000:0000}203Z: ~1~0CM.'"'
Vrhat, hogy az IPv6-os cmek kiosztsnl (s valsznleg mg elg sok-
ig) a cm kezdetben sok, nullkkal teli blokkot tartalmaz. Egyszerstskp-
pen bevezettk azt, hogy a kezd nullk minden blokkon bell elhagyhatk,
egy vagy tbb nullbl ll blokk kt kettsponttal helyettesthet:
0000t, t n 546A4: FEEI)4 DEAL
Az ttrs megknnytsre a rgi IP-cmek kt kettsponttal kezdden a
hagyomnyos, pontokkal elvlasztott mdon rhatk le:
A rgi IP-cmek a kvetkez minta alapjn illeszkednek az j cmbe:
000'400.~0004:s00~~,;gxxX_
-
_
-
_ _
Itt az XXXX:XXXX az IPv4 -es cm hexadecimlis formtumban. A lehetsges
rvidtseket alkalmazva az trsi sma a kvetkez:
_
288
6.5.IP
Igya
152 .66.188.11
IPv4 -es cm IPv6- os formtumban az albbi:
::FFFF:9842 :BCOB
6.5.7. Portok
Eddig az IP-rteg cmzst vizsgltuk, amely a szmtgp-hlzaton lv g-
pek azonostsra szolgl. Egy gpen azonban ltalban tbb szolgltats is
fut, amelyeket meg kell klnbztetnnk egymstl. Vagyis az egyes alkal-
mazsokat is meg kell cmeznnk valahogyan.
A TCP- s az UDP-rteg lehetv teszi tbb virtulis csatorna" ltrehozst
kt gp kztt. A szlltsi rteg ezt a kommunikcit a portokkal azonostja.
Egy TCP/UDP kommunikciban mindkt fl kln portszmmal rendelkezik.
Az 102 4 -nl kisebb szm portokat jl ismert portoknak (well-known
ports) nevezzk, amelyek meghatrozott szolgltatsoknak vannak fenntartva.
A felhasznli programok az 102 4 -tl 4 9 151-ig lv tartomnyt hasznlhatjk
(regisztrlt portok registered ports). A dinamikus s a magnportok
(Dynamic and Private Ports) a 4 9 152 65 535 intervallumban helyezkednek
el. Az Internet Assigned Numbers Authority (TANA, az internet szmhozzren-
del hatsga) szervezet ltal definilt portok listja a http:/ /www.iana.org/
assignments/port-numbers oldalon tallhat. A legismertebb szolgltatsok
portjait a 6.5. tblzat foglalja ssze.
6.5. t bl zat.Szolgltatsok portjai
Szolgltats neve Port
ftp-daca 2 0
ftp 2 1
ssh 2 2
telnet 2 3
smtp 2 5
http 80
port map 111
https 4 4 3
Linux alatt a szolgltatsok az /etc/services fjlban vannak felsorolva.
2 89
6. fejezet: Hlzati kommunikci
6.5.8. A hardverfgg klnbsgek feloldsa
A hlzati kommunikci byte-ok sorozatn alapszik. Egyes processzorok azon-
ban klnbz mdon troljk a klnbz adattpusokat. Mivel a klnbz
processzorra! szerelt gpeknek is szt kell rtenik egymssal, ezrt ennek a
nehzsgnek az thidalsra definiltak egy hlzati byte-sorrendet (network
byte order). A hlzati byte-sorrendben az alacsonyabb helyrtk byte jn
elbb (a nagyobb van htul" big endian). Azoknl az architektrknl, ahol
az n. hoszt byte-sorrendje ellenkez (a kisebb van htul" little endian)
ilyenek pldul az Intel 8086-os alap processzorok konverzis fggv-
nyek llnak rendelkezsnkre, amelyeket a 6.6 tblzat foglal ssze.
6.6. tblzat. Byte-sorrend-konverzis fggvnyek
Fggvny Lers
ntohs Egy 16 bites szmot a hlzati byte-sorrendbl a hoszt byte-sorrendbe
(big-endianlittle-endian) vlt t.
ntohl Egy 32 -bites szmot a hlzati byte-sorrendbl a hoszt byte-sorrend-
jbe (big-endianlittle-endian) vlt t.
htons Egy 16-bites szmot a hoszt byte-sorrendjbl hlzati byte-sorrendbe
(little-endianbig-endian) vlt t.
htonl Egy 32 -bites szmot a gp byte-sorrendjbl hlzati byte-sorrendbe
(lttle-endianbig-endian) vlt t.
Azokon az architektrkon, ahol nem szksges ez a konverzi, ezek a fgg-
vnyek a megadott argumentumrtkekkel trnek vissza, vagyis hordozhat
kd esetn mindenkppen alkalmazzuk ezeket a fggvnyeket.
A byte-sorrend problmjval elssorban a cmzsnl tallkozunk. Az t-
vitt adatok rtelmezst mr mi definiljuk az alkalmazsszint protokoll
specifiklsnl, m az implementci sorn rdemes szben tartani ezt a
problmt.
6.5.9. A socketcm megadsa
A 6.2. Az sszekttets-alap kommunikci alfejezetben bevezettk a connectO
fggvnyt, amellyel a szerverhez tudunk kapcsoldni, illetve a bind0 hvst,
amellyel cmet rendelhetnk a socketekhez. Mindkt fggvny egy-egy cmet
vr paramterl. Nzzk meg kzelebbrl a cm megadsnak a mdjt.
IPv4
Az IPv4 -es cmeket a sockaddr_in struktra definilja, amelyet a netinet/ in.h
llomny tartalmaz:
2 90
6.5. IP
structsock add_in
sa_family _t sin_family :
in_port_t sin_port;
structin_addrsin_addr;
unsignedcharsin_zero[8];
/*
/"
/
*
C mcsal d=AF_INET*/
Aportsz ma*/
IP v 4cim*/
structsock addrv ge*/
} ;
Az in_addr struktra felptse a kvetkez:
structin_addr
in_addr_ts_addr;/*elj eln lk li3 2 bitessz m*/
IPv6
Az IPv6-os struktra hasonlt az IPv4 -hez, m ebben az esetben a cm 32 bit
helyett 12 8 bites. A cmet a sockaddr_in6 struktra trolja, amely szintn a
netinetlin.h llomnyban tallhat:
structsock addr_in6
sa_family _t
in_port_t
uint3 2 _t
structin6_addr
uint3 2 _t
} : shememmew
sin6_family ; /*C mcsal d=AF_INET6
sin6_port; /*Aportsz ma*/
s n6_flowinfo;
sin6_addr; /*IP v 6c m*/
sin6_scope_id;
A sin_flowinfo s a sin6 scope_id mezk rtelmezsre jelen keretek kzt
nem trnk ki. 0 rtket hasznlunk az esetkben.
Az in6 addr struktra felptse az albbi:
structin6_addr
a
41"-
MMM
uint8_ts6_addr[16];
N _
;
Mind az IPv4 , mind az IPv6 esetben a rendszer a cmet binris formban, h-
lzati byte-sorrendben vrja. Ezek megadsa azonban a felhasznl szmra
nehzkes lenne. A 6.5.3. IPv4-es cmzs s a 6.5.6. IPv6-os cmzs alfejezetekben
lthattuk az elterjedt cmmegadsi formtumokat. Ezek szveges formtumok,
amelyekbl a binris cm ellltsa fggvnyek segtsgvel lehetsges.
Az IPv4 -es protokoll esetn az inet_aton() s az inet_ntoa() fggvnyeket
hasznlhatjuk arra, hogy a pontozott szveges formtumbl a binris form-
tumot ellltsuk, illetve fordtva. Ezek a fggvnyek azonban csak IPv4 ese-
tben hasznlhatk, ezrt manapsg mr elavultnak szmtanak.
2 91
6. fejezet: Hlzati kommunikci
Az inet_pton0 s az inet_ntop0 fggvnyek hasonltanak az inet_aton0 s
az inet_ntocco fggvnyekre, m mind az IPv4 pontozott szveges formtu-
mt, mind az IPv6 hexadecimlis szveges formtumt tmogatjk. Ezrt
ezeket a fggvnyeket rdemes megvizsglni.
Az inet_pton0 fggvny nevben a p prezentcit (presentation), az n h-
lzatot (network) jelent. Vagyis a fggvny az ember ltal kezelhet szveges
formtum cmbl hlzati byte-sorrendes binris formtumot llt el.
i n c l u d e < a r p a t i n e t . h >
i n t i n e t _ p i t o n e i n t a f , c o n s t c h a r * s r c , v o i d * 4 s t )
-
4
Az af a cmcsald, vagyis esetnkben AF INET vagy AF INET6. Az src pa-
ramter az IP-cm szveges reprezentcijt tartalmazza. A dst paramternek
egy nem tipizlt mutatt kell belltanunk. Ennek valjban egy in_addr
vagy egy in_addr6 tpus struktrra mutat rtknek kell lennie, attl fg-
gen, hogy IPv4 -es vagy IPv6-os cmet alaktunk t.
A fggvny visszatrsi rtke sikeres konverzi esetn 1. Ha 0 rtket
kapunk vissza, akkor az azt jelenti, hogy a szveges reprezentci nem meg-
felel. Hibs af rtk esetn pedig 1 rtket ad vissza a fggvny.
Az inet_ntop0 fggvny az ellenkez irny konverzit vgzi el. A hlza-
ti binris cmbl egy olvashat szveges cmet llt el:
#include<arpa/inet.h>
constchar*inet_ntop(intaf,constv oid*src,char*dst,
sock len_tsize);
Az af rtke ebben az esetben is AF INET s AF INET6 lehet. Az src para-
mternek egy in_addr vagy egy in_addr6 struktrra kell mutatnia, amely a
binris cmet tartalmazza. A dst paramterknt meg kell adnunk egy karak-
tertmb-mutatt, amelybe a fggvny a szveges reprezentcit elhelyezi nul-
lval lezrva. A tmb mrett a size paramterrel kell specifiklnunk. Ha tl
kicsi tmbt adunk meg, akkor a konverzi sikertelen lesz.
Sikeres konverzi esetn a fggvny a szveges reprezentci mutatjval
tr vissza (a dst paramter). Ellenkez esetben NULL rtkkel jelzi a hibt.
A megfelel szvegbuffermret megvlasztshoz a netinet/in.h llomny
tartalmaz kt segddefincit az IPv4 -es s az IPv6-os cmekhez:
#dgfine 4 4 W' 10,
afilite 1~A011~
292
6 . 5. I P
6.5.10. Loklis cm megadsa
A 6.2.2. A socket cmhez ktse alfejezetben megmutattuk a socketek cmhez
ktst. A cmhez kts mvelete egy loklis cm megadst ignyli. Az eddig
ltott fggvnyek segtsgvel ssze tudunk lltani egy olyan struktrt,
ahol a programunkat futtat szmtgp IP-cmt adjuk meg, tovbb egy
portot. Ezt kveten az adott cmhez kthetjk a socketet. Ezzel a mdszerrel
azonban tbb gond is van. Egyrszt ki kellene dertennk a programot futtat
gp cmt. Msrszt egy internetre kttt gpnek legalbb kt IP-cme van:
egy hlzati s egy loopbackcme
A megolds egy specilis cmbellts hasznlata, amely a futtat gp min-
den IP-cmhez hozzkti a socketet. Ez a cm IPv4 esetn az INADDR ANY,
amely ngybyte-os, 0-t tartalmaz rtk.
Megfog INAOD,LANY ttin.A4dr_t) No0000000)
Az IPv6 is rendelkezik egy hasonl defincival, ennek neve IN6ADDR ANY
INIT, s rtke 16 darab 0 byte-ot tartalmaz tmb:
#define IN6ADORANYXNZ1
-
Ot0,0~9404nAMilb04
Br a kt konstans hasonl, a hasznlatukban van egy klnbsg. Az INADDR_
ANY skalrtpus, ezrt brhol hasznlhatjuk rtkadsra. Viszont az
IN6ADDR_ANY _INIT tmbrtk, amelyet a C nyelv szintaktikja szerint egy
egyszer egyenlsgjellel nem msolhatunk le, kivve a tmb ltrehozst:
torsi strUOt InLiddr*100,0 0 .XN6APORANYLXNZ
,
A rendszer tartalmazza az ebben a pldban szerepl rtkadst, gy az
in6addr_any globlis vltoz fel is hasznlhat rtkadsra.
Bizonyos szolgltatsok esetn elfordul, hogy azokat csak loklisan elr-
hetv akarjuk tenni, s nem publikljuk az internet fel. Ilyenkor csak a
loopbackinterfszhez ktjk hozz a socketet. Ennek meghivatkozsra is
tartalmaz konstansokat a rendszer. IPv4 esetn a loopbackinterfsz cme
INADDRLOOBACK:
Iftlefine IkAnDILL001%
,
.ax7fOoGLIII1127 .4.tra.
IPv6 esetn egy tmbkonstansunk van IN6ADDR_LOOPBACK_INIT nven:
4ht!ifil* DtOtikE0OPWIUSTY
*- _ Att4:0.0A41.4.44';04
-
gti;04tUl
.
,11k t,t144
293
6. fejezet: Hlzati kommunikci
A definci mellett in6addr_loopback nven globlis vltoz is rendelkez-
snkre ll:
c o n s t s t r u c t i n 6_ a d d r i n 6a d d r _ l o o p ba c k
tmutat Figyeljnk arra, hogy az IPv4-es konstansok hosztbyte-sorrendben vannak, ezrt
mg konvertlni kell ket hlzati byte-sorrendre a htonI0 fggvnnyel. Ez a 0-t tartalmaz
INADDR_ANY esetn mg nem fontos, de az INADDR_LOOPBACK rtke mr nem O. Az IPv6-os
konstansok viszont hlzati byte-sorrendben vannak.
6.5.11. Nv- s cmfelolds
Az IP-cmek hasznlata a felhasznlk szmra nehzkes, mivel sok szmot
kellene fejben tartaniuk. Emellett, ha a szerver IP-cmt trjuk, akkor a fel-
hasznlk nem talljk meg tbb. Ezrt a gyakorlatban nem is IP-cmeket,
hanem hosztneveket hasznlunk. Ha a hoszt nevbl az IP-cmt szeretnnk
megllaptani, akkor nvfeloldsrl beszlnk.
A nvfelolds trtnhet szmos forrs alapjn:
loklis llomny (/etc/hosts),
kzponti szerverek (DNS, mDNS, Yellow pages stb.),
Szerencsre programozknt nem kell minden lehetsges forrst leimplemen-
tlnunk. Helyette a Linux egysges nvfeloldst vgz fggvnyeket nyjt.
6.5.11.1. A getaddrinfo() fggvny
A getaddrinfo0 fggvny a hosztnevet s a szolgltatsnevet (lsd 6.5.7. Portok
alfejezetben) kpes tkonvertlni IP-cmm s portszmm.
83
A fggvny egya-
rnt kezeli az IPv4 -es s az IPv6-os cmeket. Hasznlata sorn olyan kritriumo-
kat adunk meg, amelyekkel meghatrozzuk a megfelel cmeket. Ennek hatsra
a fggvny egy cmekbl ll listt ad vissza. A fggvny alakja a kvetkez:
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
const char *gai trerror(int errcode);
83
A getaddrinfo() fggvny eldeinek tekinthet a gethostbynaine(), amely hosztnv felol-
dsra kpes, illetve a getservbyname(), amely a szolgltatsok portjt adja vissza. Ezeket
a fggvnyeket azonban szmos korltjuk miatt manapsg nem hasznljuk.
294
6.5. IP
A lista memriafoglalsnak felszabadtshoz s a hibakezelshez tovbbi
fggvnyek llnak rendelkezsre.
A node paramterben kell megadnunk a hosztnevet, a service paramter-
ben pedig azt a szolgltatst, amelyeknek a cmre kvncsiak vagyunk Mind
a kt esetben szveges formtumot hasznlunk. A hosztnvnl megadhatunk
IP-cmet a szoksos formtumokban ekkor az inet_pton0 fggvnyt helyet-
testheti , illetve a hoszt nevt. A szolgltatsnl is hasznlhatjuk a megne-
vezs mellett a port szmt szveges, decimlis formtumban. Ha a service
paramternek NULL rtket adunk meg, a fggvny a vlaszban a portsz-
mot nem lltja be.
A hints paramterben adhatjuk meg azokat a kritrumokat, amelyek
meg kell, hogy feleljenek a tallatoknak. A res paramterben kapjuk meg
a vlaszt lncoltlista-formban. Ksbb a lncolt lista felszabadtsban a
freeaddrinfo() fggvny segt, amellyel egy lpsben megoldhat a feladat.
A getciddrinfo0 fggvny visszatrsi rtke 0, ha sikeresen vgrehajt-
dott. Hiba esetn a visszatrsi rtk egy olyan hibakd, amelynek szveges
informciv alaktst a gai_strerrorO fggvnnyel vgezhetjk el.
Mind a kritriumok, mind a vlasz tpusa struct addrinfo, ennek felpt-
se a kvetkez:
struct addrinfo
int ai_flags ;
int ai _fami 1 y ;
int ai_socktype;
int ai_protocol ;
si ze_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *al_next;
};
Az ai_family mez a cmcsaldot adja meg. rtke lehet AF INET s AF_INET6
is. Kritriumknt AF UNSPEC rtket is bellthatunk. Ekkor a vlaszlistban
IPv4 -es s IPv6-os cmek is szerepelhetnek.
Az ai_socktype mezben a SOCK STREAM s a SOCK DGRAM rt-
keket vagy 0-t adhatunk meg. 0 rtk esetn mind TCP-, mind UDP-bejegyz-
seket tartalmazhat a vlaszlista, ha az adott szolgltats mindkt protokollt
tmogatja.
Az ai_protocol a protokollindexet adja meg. Kritriumknt 0-t megadva
azt jelenti, hogy a protokollrtket nem ktjk meg.
Az eddig felsorolt hrom mez rendre a socketO fggvny paramterei le-
hetnek, amikor felhasznlunk egy vlaszbejegyzst.
Az ai_addrlen mez a cm mrett adja meg byte-okban. A cmet az
ai_addr mez tartalmazza byte-osan sockaddr_in (IPv4 ) vagy sockaddr_in6
(IPv6) formtumban. Ezeket az rtkeket hasznlhatjuk a cm megadsnl.
295
6, fejezet: Hlzati kommunikci
Az ai_canonname mez csak a lista els elemnl van kitltve, s a hoszt
nevt tartalmazza abban az esetben, ha kritriumknt az ai_flags mezben az
AI CANONNAME rtket megadtuk.
Az ai_next mez a lncolt lista kvetkez elemre mutat, illetve a lista
utols elemnl az rtke NULL.
A lista vgre hagytuk az ai_flags mezt, amely egy kicsit hosszabb ma-
gyarzatot ignyel. Ez a mez a kritriumok sszelltsnl kap szerepet.
Egy bitmaszkrl van sz, amely klnbz opcikat kapcsolhat be. A hasznl-
hat rtkeket a 6.7. tblzat foglalja ssze:
6.7. tblzat. A cmmegads s -sz
-
rs opcii
Jelzbit Lers
AI ADDRCONFIG A vlaszlista csak akkor tartalmaz IPv4 -es cmet, ha a loklis
gpnek legalbb egy IPv4 -es cme van, amely nem a
loopbackcm. Illetve IPv6-os cmek esetn hasonlkppen.
AI ALL Csak az AI V4MAPPED rtkkel van jelentse. rtelmezst
lsd ott.
AI CANONNAME Ha a node paramter rtke nem NULL, akkor a vlaszlista el-
s elemnek ai_canonname mezje tartalmazza a hoszt nevt.
AI NUMERICHOST Kikapcsolja a nvfeloldst, s a node paramter rtke csak
numerikus cmreprezentci lehet. Ezzel megtakarthatjuk a
nvfelolds idejt.
AI NUMERICSERV Kikapcsolja a szolgltats nvfeloldst. Szolgltatsnak csak
szmot adhatunk meg (szvegesen).
AI PASSIVE A cmstruktra egy szerversocket cmhez ktshez hasznl-
hat loklis cmet tartalmaz, ha ez az opci be van lltva, s a
node paramter NULL. Vagyis a cm INADDR ANY vagy
IN6ADDR ANY INIT lesz.
Al V4MAPPED Ha ez az opci be van kapcsolva, s mellette a kritrium
aijamily mez rtke AF INET6, s a fggvny ennek ellen-
re csak IPv4 -es cmet tall, akkor az IPv4 -es cmet IPv6-os
formtumban adja vissza. Ha az AI ALL opcival egytt al-
kalmazzuk, akkor IPv6-os s IPv4 -es cmeket is visszaad, de
utbbiakat IPv6-os formtumba alaktva.
Jrjuk krbe az AI PASSIVE opcit egy kicsit jobban. Ha ezt az opcit bel-
ltjuk, s nem adunk meg hosztnevet, akkor a kapott cm tipikusan a bind0
fggvnnyel hasznlhat (INADDR ANY vagy IN6ADD_ANY INI7). Ha nem
lltjuk be ezt az opcit, akkor a kapott cm a connect() s a sendto0 fggv-
nyek szmra hasznlhat. Ez esetben, ha megadunk hosztnevet, akkor an-
nak a cmt vagy cmeit kapjuk vissza. Arra is lehetsgnk van azonban,
hogy nem adunk meg hosztnevet, s akkor a loopbackcmet kapjuk vissza
(INADDR_LOOPBACK vagy IN6ADDR_LOOPBACK INIT).
296
6.5. IP
Br a kritriummegadsra s a vlaszlista ellltsra ugyanazt a
struktrt hasznljuk, valjban a mezk hasznlatban van nmi eltrs.
Kritrium megadsakor csak az aijlags, az aiJamily, az ai_socktype s az
aiprotocol mezknek van szerepe. A tbbi mez rtkt nem hasznljuk, r-
tkknek 0-nak vagy NULL-nak kell lennie. A vlaszban pedig az aijlags
meznek nincsen szerepe.
Ha semmilyen kritriumot nem kvnunk belltani, csak a hoszt nevre
s a szolgltatsra szrni, akkor kritriumknt NULL rtket is belltha-
tunk. Ez azzal egyenrtk, mintha az aijlags meznek (AI V4MAPPED I
Al ADDRCONFIG) rtket, az aijamily meznek AF UNSPEC rtket, mg
a tbbi meznek 0-t lltottunk volna be.
Feladat Alkossunk egy egyszer programot, amely a paramterknt kapott hosztnevet IP-
cmm alaktja s kirja.
/* getpaddr.c - internetes nvfelolds. */
#include <stclio.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
struct addrinfo* p;
int err;
char ips[INET6_ADORSTRLEN];
if(argc !=2)
printf("Hasznlat: %s <nv>\n", argv[0]);
return -1;
}
memset(&hints, 0, sizeof(hnts));
hints.ai_family =AF_UNSP EC;
hints.ai_socktype =SOCK_STREAM;
err = getaddrinfo(argv[11, NULL, &hints, &res);
if(err !=0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return -1;
}
for(p =res; p !=NULL;p=p->ai_next)
if(p->ai_family ==AF_INET)
{
297
6.fej ezet:H lzatik ommunik ci
i f(inet_ntop(AF_INET,
&((structsock addr_in*)(p->ai_addr))->
sin_addr, ps,sizeof(ips))!=NULL)
{
printf("IP :%s\n", ps);
}
elseif(p->ai_family ==AF_INET6)
if(inet_ntop(AF_INET6,
&((structsock addr_in6*)(p->ai_addr))->
sin6_addr,ips,sizeof(ips))!=NULL)
printf("IP :Yos\n",ips);
}
}
freeaddrinfo(res);
return0;
Teszteljk is le:
./getipaddrwww.aut.bme.hu
IP :152 .66.188.11
S . /getipaddrwww.google.com
IP :173 .194.3 5.176
IP :173 .194.3 5.177
IP : 173 .194.3 5.178
IP : 173 .194.3 5.179
IP : 173 .194.3 5.180
IP :2 a00:1450:4016:801::1011
S . /getipaddrthat.s.not.funny .com
getaddrinfo:Nameorserv icenotk nown
6. 5 . 1 1 . 2 . A g e t n a n n * ; f i 3 O f ggv n y
A getnameinfo0 fggvny nagyjbl a getaddrinfoo fggvny inverze. Az a fe-
ladata, hogy a socketcmet hoszt- s szolgltatsnvv konvertlja." A fgg-
vny alakja az albbi:
84
Ez a fggvny egyesti a korbban, az IPv4 esetn hasznlatos gethostbyaddr0 s
geiservbyport0 fggvnyek funkcionalitst, m azoknl flexibilisebb.
298
#include <sys/socket.h>
#include <netdb. h>
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags);
Az sa paramter a socketcmstruktra (sockaddr_in vagy sockaddr_in6) muta-
tja. A struktra mrett a salen paramterben kell megadnunk. A host s a
serv paramterknt egy-egy ltalunk lefoglalt karaktertmbt kell tadnunk,
amelyeknek mrett a hostlen s a servlen paramterekkel tudjuk kzlni. Eb-
ben a kt tmbben kapjuk vissza a hoszt s a szolgltats nevt NULL termi-
nlt sztringknt. Ha valamelyik rtkre nem vagyunk kvncsiak, akkor NULL
rtket s 0 hosszsgot megadva ezt jelezhetjk. Termszetesen legalbb az
egyiket krnnk kell, mert klnben nincs rtelme meghvni a fggvnyt.
A flags paramter mdosthatja a fggvny mkdst a 6.8. tblzat szerint.
6.8. tblzat. A getnameinfo fggvny jelzbitjei
Jelzbit Lers
NI DGRAM Egyes portoknl TCP s UDP protokollok esetben ms-ms
szolgltats fut. Alaprtelmezetten a TCP-szolgltats nevt
kapjuk vissza. Ezzel a paramterrel az UDP-szolgltatst kap-
juk meg.
NI NAMEREQD Alaprtelmezetten, ha a hosztnevet nem tallja a fggvny,
akkor szveges IP-cmet ad vissza. Ha megadjuk ezt az opcit,
akkor ebben az esetben hibval tr vissza a fggvny.
NI NOFQDN Alaprtelmezetten teljes hosztnevet (Fully Qualified Domain
Name) kapunk vissza, ezzel az opcival csak a rvid
hosztnevet.
NI NUMERICHOST Ha megadjuk, akkor nem trtnik nvfelolds, hanem csak
szveges IP-cmet kapunk vissza. Ez trtnik akkor is, ha nem
sikerl a hosztnevet kiderteni.
NI NUMERICSERV Numerikusan, egy decimlis szmot tartalmaz szvegknt
kapjuk vissza a portot.
Sikeres vgrehajts esetn a fggvny 0-val tr vissza. Sikertelensg esetn
hibakdot kapunk visszatrsi rtkknt, amelyet ekkor is a gai_strerror()
fggvnnyel tudunk szvegg alaktani.
A getnameinfo() fggvnyt elssorban az acceptQ vagy a reevfrom() fggv-
nyek ltal visszaadott cmekre alkalmazzuk. Tipikusan a naplzshoz alaktjuk
vissza a socketcmeket a felhasznl szmra is rtelmezhet formtumba.
Feladat Az elz fejezet pldjt alaktsuk gy t, hogy a socketcmet szveges IP-cmm a
getnameinfo0 fggvnnyel alaktjuk vissza.
2 99
6. fejezet: Hlzati kommunikci
/*getipaddr.c-Internetesn v felold s.*/
#include<stdio.h>
#include<string.h>
#include<netdb.h>
intmain(intargc,char*argv [])
{
structaddrinfohints;
structaddrinfo*res;
structaddrinfo*p;
interr;
charip5[INET6_ADDRSTRLEN];
if(argc!=2 )
printf("Haszn lat:%s<n v >\n",argv [0]);
return-1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family =Ar_uNSP EC;
hints.ai_sock ty pe=SOCK_STREAM;
err=getaddrinfo(argv [1],NULL,&hints,&res);
i f(err!=0)
{
fpr ntf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
for(p=res;p!=NULL;p=p->ai_next)
{
if(getnameinfo(p->ai_addr,p->ai_addrlen,
ips,sizeof( ps), NULL,0,NI_NUMERICHOST)=0)
printf("IP :%s\n",ips);
}
}
freeaddrinfo(res);
return0;
m nemcsak a cmet hozhatjuk szveges formba ezzel a fggvnnyel, hanem
inverz nvfeloldst is vgezhetnk vele.
Feladat Ksztsnk egy programot, amely a paramterknt megkapott IPv4-es cmet hoszt-
nvv alaktja.
300
6.5.IP
/*gethost.c-IP c mheztartozn v felold sa.*/
# nclude<stdio.h>
#include<string.h>
#include<netdb.h>
#include<arpa/inet.h>
intmain(intargc,char*argv [])
structsock addr_ naddr;
charname[Ni_mAxH0ST];
interr;
if(argc!=2 )
printf("Haszn lat:%s<IP c m>\n",argv [0]);
return-1;
}
memset(&addr,0,sizeof(addr));
addr.sin_family =AF_INET;
i fOnet_ptOn(AF_INET,argv [1],&addr.sin_addr)==0)
perror("inet_pton");
return-1;
err=getnameinfo((structsock addr*)&addr,sizeof(addr),
name,sizeof(name),NULL,0,NI_NAMEREQD);
if(err!=0)
fprintf(stderr,"getnameinfo:%s\n",gai_strerror(err));
return-1;
printf("Ag pnev e:%s\n",name);
return0;
}
A programot letesztelve a kvetkez kimenetet kapjuk:
$./gethost152 .66.188.11
Agepnev e:www.aut.bme.hu
$./gethost152 .66.188.111
qetnameinfo:Nameorserv icenotk nown
emmemer
-
11
301
6. fejezet: Hlzati kommunikci
A pldaprogramban szembesltnk azzal a problmval, hogy foglalnunk kell
egy megfelel mret buffert a gp nevnek. Szeretnnk akkort foglalni,
hogy belefrjen a teljes nv, de nem tudhatjuk, mi elg. Hasonl problmval
a szolgltatsnevek feloldsnl is szembeslhetnk. A programoz dolgt az
albbi kt definci megknnyti:
Ez a kt rtk akkora, hogy a vrhat nevek belefrnek ekkora bufferekbe.
6.5.12. sszekttets-alap kommunikci
A 6.2. Az sszekttets-alap kommunikci alfejezetben mr bemutattuk az
sszekttets-alap kommunikci egyes lpseit. IP-kommunikci esetn is
ezeket a lpseket kvetjk, csak annyi kiegsztssel, hogy IP-socketet hozunk
ltre, s a cmet az elz fejezetekben megismert mdon lltjuk ssze. gy je-
lenlegi ismereteink alapjn mr kpesek vagyunk egy TCP-kommunikci
felptsre s hasznlatra.
A kommunikci sorn hasznlhatjuk a reado s a write() fggvnyeket,
a rendszer tartalmaz azonban kt olyan msik fggvnyt, amely tbb lehet-
sget nyjt.
Az adatok kldshez hasznlhatjuk a send0 fggvnyt:
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, , si ze_t len, int flags) ;
Az els argumentum a socket lerja, a msodik az elkldend adat buffernek
a mutatja, a harmadik az elkldend adat mrete. Eddig a paramterezs
megegyezik a write() fggvnyvel. A klnbsget az utols, flags argumen-
tum jelenti, amelyben tovbbi opcikat llthatunk be. A flags argumentum-
ban megadott jelzbitek jelentst a 6.9. tblzat mutatja.
6.9. tblzat. A send jelzbitjei
4 04 0bit _ Lelt4
MSG_DONTROUTE A csomag nem mehet keresztl az tvlasztkon, csak kzvet-
lenl ugyanazon a hlzaton lv gp kaphatja meg.
MSG_DONTWAIT Engedlyezi a nem blokkol I/O-t. EAGAIN hibval tr vissza,
ha vrakozni kellett volna a kirsra, mert tele van a buffer.
MSG_MORE Tovbbi adatot szeretnnk mg kikldeni. Ezrt nem kldi el a
csomagot addig, amg nem kap egy sendO hvst MSG_MORE
opci nlkl.
302
6.5. iP
'
4 8126 b it Ler s
MSG_NOSIGNAL Adatfolyam-alap kapcsolat esetn a program nem kap
SIGPIPE jelzst, amikor a kapcsolat megszakad. Ez azonban
az EPIPE hibajelzst nem rinti.
MSG_OOB Soron kvli srgs adatcsomagot (out-of-band data) kld.
ltalban jelzsek hatsra hasznljk.
A sertd() visszatrsi rtke hasonlt a write() fggvnyhez. Sikeres klds
esetn az elkldtt byte-ok szmt kapjuk vissza, hiba esetn pedig negatv
rtket. Utbbinl az errno globlis vltoz tartalmazza a hibt.
A send0 prja a recv() fggvny, amely a readO fggvnyre hasonlt:
4 include <sys/socket.h>
ssize_t recv(int sockfd, void * buf, size_t len, int flags);
A fggvny els hrom paramtere a read() fggvnynl is megszokott alak.
Sorban a socketler, a fogad buffer s a buffer mrete. Ezt kveti a flags pa-
ramter, amellyel tovbbi opcikat llthatunk be. A flags paramter rtke a
6.1(). tblzatban sszefoglalt jelz'bitekbl llhat ssze:
6.10. tblzat. A recv jelzbitjei
Jelzbit
d
r Ler s
MSG_DONTWAIT Engedlyezi a nem blokkol 1/0-t. EAGAIN hibval tr vissza, ha
vrakozni kellett volna az olvassra, mert nem rkezett adat.
MSG_OOB Soron kvli adat fogadsa.
MSG_PEEK Az adat beolvassa trtnik meg anlkl, hogy a beolvasott
adatot eltvoltan a bufferbl. A kvetkez recv0 hvs ugya-
nazt az adatot mg egyszer kiolvassa.
MSG_WAITALL Addig nem tr vissza, amg a megadott buffer meg nem telik,
vagy egyb rendhagy dolog nem trtnik, pldul jelzs rkezik.
A recv0 fggvny visszatrsi rtke megegyezik a read() fggvnyvel. Sike-
res olvass esetn a bufferbe bert byte-ok szma, hiba esetn mnusz rtk,
valamint 0, ha a tloldal lezrta a kapcsolatot.
Gyakori feladat, hogy a TCP-kapcsolaton keresztl egy llomnyt kell el-
kldennk. Ezt leimplementlhatjuk gy, hogy egy ciklusban a readO fgg-
vnnyel beolvassuk az adatokat egy bufferba, majd a send0 fggvnnyel el-
kldjk a TCP-kapcsolaton. Ez a megolds jl mkdik, m nagyobb mret
llomny esetben sokszor meghvdna a ciklus, s egyre inkbb eljnne a
htrnya, miszerint az adatokat az egyik rendszerhvssal a kernelbl egy
tmbbe msoljuk, majd egy msik rendszerhvssal vissza a kernelbe. Egy-
szerbb s gyorsabb egy lpsben a kernelben elvgezni az egsz mveletet.
Ezt valstja meg a sendfileQ rendszerhvs:
303
6.fej ezet:H lzatik ommunik ci
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset,
size_t count);
A fggvny az in_fd llomnylerval megadott llomnybl az out_fd llo-
mnylerval lert socketkapcsolatba kldi az adatokat. Ha az offset param-
ter nem NULL, akkor egy olyan vltoz mutatjt kell, hogy tartalmazza,
amely megadja az eltolst az in_fd llomny elejhez kpest. Az olvasst s a
kldst csak ettl a pozcitl kezdi el a fggvny. Amikor a fggvny vissza-
tr, akkor mdostja az eltols rtkt. Az j rtk az utols elkldtt byte + 1
lesz. Ha az offset nem NULL, akkor a fggvny nem mdostja a bemeneti l-
lomny aktulis pozcijt.
Ha az offset rtke NULL, akkor az olvass a bemeneti llomny aktulis
pozcijtl indul, s a fggvny vgn frissl is.
A count paramter a msoland byte-ok szmt adja meg. Ha tbb lenne,
mint amennyi byte-ot az llomny tartalmaz, akkor csak az llomny vgig
tovbbtja a byte-okat.
Sikeres visszatrskor a visszatrsi rtk az elkldtt byte-ok szma. Hiba
esetn mnusz rtk, s az errno globlis vltoz tartalmazza a hibakdot.
A sendfile0 rendszerhvs mellett a Linux tmogat mg tovbbi nem
szabvnyos rendszerhvsokat is hasonl clokra: spliceO, vmspliceO, teeO.
Ezekre jelen keretek kzt nem trnk ki.
6.5.12.1. TCP kliens-szerver plda
Eddigi ismereteink alapjn knnyen meg tudunk valstani egy egyszer
TCP-szervert s a hozzkapcsold klienst.
Feladat Alkossunk egy egyszer TCP-szervert, amely kpes egy kapcsolat fogadsra, majd a
klienstl kapott adatokat kirja az alaprtelmezett kimenetre.
A feladatot az albbi, IPv6-ot tmogat szerverprogram megoldja:
#include<stdio.h>
#include<stdlib.h>
#include<unistdh>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<netdb.h>
#definePO RT "112 2 "
304
I
if(listen(ssock ,5)<0)
perror("listen");
return1;
6.5.IP
intmain()
structaddrinfohints;
structaddrinfo*res;
nterr;
structsock addr_in6addr;
sock len_taddrlen;
charips[Ni_mAXHOST];
charserv s[NI_MAXSERV];
intssock ,csock ;
charbuf[2 56];
intlen;
intreuse;
memset(&hints,0,sizeof(h nts));
h nts.a _flags=AI_P ASSIVE;
hints.ai_family =AF_INE76;
hints.ai_sock ty pe=SOCK_STREAM;
err=getaddrinfo(NULL,P ORT,&hints,&res);
i f(errI--0)
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
if(res==NULL)
{
return-1;
}
ssock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
if(ssock <0)
perror("sock et");
return1;
reuse=1;
setsock opt(ssock ,SOL_SOCKET,SO_REUSEADDR,&reuse,
sizeof(reuse));
if(bind(ssock ,res->ai_addr,res->ai_addrlen)<0)
{
perror("bind");
return1;
}
3 05
6. fejezet: Hlzati kommunikci
freeaddrinfo(res);
addrlen =sizeof(addr);
while((csock =accept(ssock,
(struct sockaddr*)&addr, &addrlen)) >=0)
{
if(getnameinfo((struct sockaddr*)&addr, addrlen,
i ps, sizeof(ips), servs, sizeof(servs), 0) ==0)
{
printf("Kacsolds: %s:%s\n", ips, servs);
}
while((len =recv(csock, buf, sizeof(buf), 0)) > 0)
write(STDOUT_FILENO, buf, len);
printf("Kapcsolat zrsa.\n");
close(ssock);
close(ssock);
return 0;
A cmhez ktshez ssze kell lltanunk egy loklis cmet. Ezt megtehetjk kz-
vetlenl a sockaddr_in6 struktra kitltsvel, vagy rbzhatjuk a getaddrinfo()
fggvnyre. Pldnkban az utbbit vlasztottuk, hogy bemutassuk a hasznlatt.
A szervercmhez a fggvny kritriumban meg kell adnunk az Al PASSIVE op-
cit. Ugyanakkor a paramterek kzt hosztnvnek NULL rtket adtunk meg.
A kt bellts hatsra a cm rtke 1N6ADDR ANY INIT lesz.
A cm ellltsa utn ltrehozunk egy socketet, majd a setsockoptQ fgg-
vny segtsgvel belltjuk, hogy a programunk lellsa utn a szolgltats
portja azonnal smt hasznlhat legyen. (A setsockopt() fggvnyt bvebben
a 6.6. Socketbellt sok alfejezetben ismertetjk.)
Ezt kveten hozzktjk a socketet a cmhez, s bekapcsoljuk a szerver-
mdot. Majd egy cikluson bell fogadjuk a kapcsoldsokat, kirjuk a kliens
cmt, portjt s a kapott adatokat. Amikor a kliens lezrja a kapcsolatot, ak-
kor a recv() fggvny nullval tr vissza, s megszakad a ciklus. Ezt kveten
a szerver is zrja a socketet, s vrja a kvetkez kapcsolatot.
Feladat Alkossuk meg az elz szerver kliensprjt. A kliens kapcsoldjon a paramterknt
megadott szervergphez, s a socketkapcsolaton kldje el az alaprtelmezett bemenetn ka-
pott szveget.
Az albbi pldaprogram valstja meg a feladatot:
306
6.5.IP
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#defineP ORT"112 2 "
intmain(intargc,char*argv [])
{
structaddrinfohints;
structaddrinfo*res;
interr;
intcsock ;
charbuf[102 4];
i ntlen;
if(argc!=2 )
{
printf("Haszn lat:%s<szerv er>\n",argv [0]);
return1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family =AF_UNSP EC;
hints.ai_sock ty pe=SOCK_STREAM;
err=getaddrinfo(argv [1], P ORT, &hints,&res);
if(err!=0)
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
}
csock =sock et(res->ai_family ,res->ai_sock ty pe,
res ->ai_protocol);
if(csock <0)
{
perror("sock et");
return-1;
if(connect(csock ,res->ai_addr,res->ai_addrlen)<0)
perror("connect");
return-1;
307
6. fejezet: Hlzati kommunikci
while((len = read(STDIN_FILENO, buf, sizeof(buf))) >0)
{
send(csock, buf, len, 0);
}
close(csock);
freeaddrinfo(res);
return 0;
}
A pldaprogramban a getaddrinfo() fggvny segtsgvel ellltjuk a clgp
megadott portjhoz tartoz cmstruktrt. Ha tbb cmet is visszakapunk, ak-
kor a lista els elemt vlasztjuk a kapcsoldshoz. A kapcsolat ltrejtte utn
a program folyamatosan olvassa az alaprtelmezett bemenetet, s a szveget
elkldi a socket, kapcsolaton keresztl Amikor a bemenetet a CTRL +D gom-
bokkal lezrjuk, akkor a program zrja a socketkapcsolatot, s vget r.
6.5.12.2. TCP szerver alkalmazs
Az elz fejezetbeli szerverplda alkalmazsa tartalmaz egy slyos hinyos-
sgot. Az alkalmazs egyszerre csak egy kapcsolatot kpes fogadni. Addig,
amg ezt kiszolglja, nem hvdik meg az aceept() fggvny, s nem fogad
jabb kapcsolatot. Az ilyen jelleg szervereket iteratv szervernek nevezzk,
s legfeljebb olyan esetekben alkalmazzuk, amikor a kliensek kiszolglsa
nagyon gyors.
ltalban a kliens-szerver kommunikci hosszabb, s a szerverektl azt
vrjuk el, hogy konkurensen egyszerre tbb klienst is kiszolgljanak. Ilyenkor
prhuzamosan kell futnia a kapcsolatok fogadsnak s a kliensek kiszolg-
lsnak. Erre a problmra tbb szerveroldali megkzeltst alkalmazhatunk.
Kapcsolatonknt egy szl (folyamat)
Minden bejv kapcsolatnak j szlat (vagy folyamatot) indtunk, amelynek
tadjuk a kapcsoldott klienssocketet. A klienssocketet ezt kveten mr a
szl (folyamat) kezeli. Ekkor minden kapcsolatot a kd szempontjbl szim-
metrikusan kezelnk, de a szlak (folyamatok) kztti vlts lasst tnyez.
Illetve a sajt stack miatt nem sklzdik jl nagy szervereken.
Processzek esetben a Linux copy-on-write technikja (forkQ hasznlata-
kor csak akkor msolja le a memriaterletet, ha arra a gyermekprocessz r)
jelentsen cskkenti az j processz ltrehozsnak az idejt, jllehet egy j
processz ltrehozsa kln erforrst emszt fel a rendszerbl, s az indthat
processzeknek fels korltja van.
308
6.5. IP
Ugyanakkor processzek esetben az 5.1. Processzek alfejezetben trgyalt
exec() fggvnycsald segtsgvel knnyen indthatunk ms programokat."
Robusztussg szempontjbl viszont, ha j processzt indtunk, annak esetle-
ges sszeomlsa nem rntja magval az sszes tbbi processzt.
Elre elindtott szlak (folyamatok)
A fenti mdszert gyorsthatjuk azzal, hogy a szerverprogram elindtsa utn
rgtn egy meghatrozott szm szlat (folyamatot) indtunk el (process
pool", thread pool"), s ha valamelyik szabad, az kezeli az jonnan bejv
kapcsolatot. A korbbi megoldshoz kpest ekkor egy feladatkioszt algorit-
must is kell ksztennk.
A megolds elnye az, hogy a szlak (folyamatok) szmnak korltozs-
val optimlisan kihasznlhatjuk a gp erforrsait. Emellett egy DoS-tma-
ds
86
csak a szolgltatst rinti, s nem fojtja" meg az egsz gpet.
A mdszer htrnya az, hogy esetleg feleslegesen sok szlat (processzt)
futtat foglalva az erforrsokat. Ennek kezelsre a komolyabb programok
menedzsmentalgoritmust alkalmaznak, amely a terhels figyelembevtelvel
megszntet vagy ltrehoz szlakat (folyamatokat). m egy ilyen algoritmus
implementlsa bonyoltja a programot.
Nzznk egy egyszer pldt az elre alloklt szlak hasznlatra. A pl-
daprogramban egy vletlen szmokat visszaad szervert mutatunk be:
#include <stdo. h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#nclude <sys/socket. h>
#include <netinet/in.h>
#include <pthread. h>
#define PORT 2 2 33
#define THREAD_NUM 3
int ssock;
pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER ;
85
Ha paramterknt vesszk t a futtatand program nevt, mindig gondoljuk t a szerver
tmadhatsgt. Ha egy nem ellenrztt sztringet tadunk az execQ fggvnynek, a tvoli
felhasznl akrmit lefuttathat a gpnkn a fut szerverprogram jogosultsgval.
A lelemnyes betr ilyenkor pldul lefuttatja a sendmail segdprogramot, hogy az kldje
el neki a jelszavakat tartalmaz fjlt, amellyel aztn otthon eljtszadozhat". Alapszably
teht: futtats eltt mindig ellenrizzk a kvlrl kapott paramtereket.
K
6
Az elrasztsos tmads (DoS, denial-of-service attack) vagy elosztott elrasztsos t-
mads (DDoS, distributed denial-of-service attack) sorn olyan sok kapcsoldsi krelem
rkezik a szerverszolgltatshoz, amelyet az nem tud kezelni. A tmad gy teszi elrhe-
tetlenn a szolgltatst, de akr az egsz szervergpet is megbnthatja.
309
sleep(3 );
spr ntf(buf,"%d.sz l:%d\n",ix,rand()%10);
send(csock ,buf,strnlen(buf,sizeof(buf)),0);
close(csock );
returnNULL;
}
intmain()
f
structsock addr_in6addr;
pthread_tth[THRE4o_Num];
inti;
intreuse;
int*pix;
if((ssock =sock et(P F_INET6,SOCK_STREAM,0))<0)
{
perror("sock et");
return1;
}
reuse=1;
setsock opt(ssock ,SOL_SOCKET,SO_REUSEADDR,&reuse,
sizeof(reuse));
memset(&addr,0,s zeof(addr));
addr.sin6_family =AF_INET6;
addr.sin6_addr=in6addr_any ;
addr.sin6_port=htons(P ORT);
6. fejezet: Hlzati kommunikci
v oid*comth(v oid*arg)
f
intix;
intcsock ;
charbuf[64];
ix=*((int*)arg);
free(arg);
while(1)
pthread_mutex_lock (&smutex);
csock =accept(ssock ,NULL,NULL);
pthread_mutex_unlock (&smutex);
310
S.S. IP
if(bind(ssock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
perror("bind");
return 1;
if(listen(ssock, 5)<0)
perror("listen");
return 1;
srand(time(NULL));
for(i =0;i<THREAD_NUM;i++)
pix = malloc(sizeof(int));
*pix = i;
pthread_create(&th[i], NULL, comth, pix);
}
// vgtelen vrakozs
while(1) sleep(1);
return 0;
A program indulskor elvgzi a szerversocket belltsait, majd ltrehoz hrom
szlat. A kapcsolatok sztosztsra a szlak kztt egy arnylag egyszer
trkkt alkalmazunk. Egy mutex segtsgvel elrjk, hogy egyszerre egy szl
hvhassa meg az acceptQ fggvnyt, s fogadhasson kapcsolatot. gy nem kell
tadnunk a klienskapcsolatokat a szlaknak.
A szerver kiprblshoz a telnet program segtsgvel kapcsoldjunk a
tcp 2 2 33-as porthoz. Kis vrakozs utn visszakapunk egy vletlen szmot, s
a szerver bontja a kapcsolatot.
Tbb kliens kezelse egy szlon
Az llomnyok prhuzamos kezelsnl megismert seleet(), pollQ s
epoi/0
fggvnyeket hasznlhatjuk a socketek esetn is. gy egy szlon, esemnyvez-
relten kezeljk az sszes klienssocketet. Emellett a szerversocketet is kezelhet-
jk ezzel a megoldssal, mert a kapcsolds egy olvassi esemnyt generl
ebben az esetben.
Az egyszl megvalsts lehetv teszi, hogy az egyes klienskapcsolatok
kztt adatokat mozgassunk szinkronizls nlkl. gy leginkbb ilyen jelle-
g alkalmazsokban ltszik az elnye.
Ugyanakkor a mdszer htrnya az, hogy a kd bonyolultabb, nem annyi-
ra szimmetrikus, mint a korbbiakban ltottak.
3 11
6.fej ezet:H lzatik ommunik ci
Az albbi program egy csevegszervert valst meg. Egy ilyen szolglta-
tsnl a felhasznlk egymsnak kldik az zeneteiket, vagyis az egyik kli-
enskapcsolaton rkez szveget a tbbi kapcsolatra kell kikldennk.
A kapcsolatok kztti adattvitel miatt a szolgltatst egy szlon rdemes le-
implementlni:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
# nclude<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<poll.h>
#defineP ORT3 3 44
#defineMAXCONNS5
, iI 1 1 1
#defineFULLMSG"megtelt!"
intssock ;
intconnect_list[mAxCONNs];
structpollfdpoll_list[mAXcoNNS+1];
intbuild_poll_list()
{
inti,count;
poll_list[0].fd=ssock ;
poll_list[0].ev ents=P OLLIN;
count=1;
for(i=0; <MAXCONNS;i++)
{
if(connect_list[1]>=0)
poll_list[count].fd=connect_list[i];
poll_list[count].ev ents=P OLLIN;
count++;
returncount;
v oidhandle_new_connection()
inti,csock ;
csock =accept(ssock ,NULL,NULL);
if(csock <0)return;
for(i=0;i<MAXCONNS;i++)
{
if(connect_list[i]<0)
3 12
6.5.1p
{
connect_list[i]=csock ;
csock =-1;
break ;
if(csock >=0)
send(csock ,FULLMSG,strlen(FULLMSG),0);
close(csock );
v oidprocess_read(intcsock )
{
charbuf[2 56];
intlen;
inti;
len=recv (csock ,buf,sizeof(buf),0);
if(len>0)
{
for(i=0;i<MAXCONNS;i++)
{
i f((connect_list[i]>=0)&&(connect_list[i]!=csock ))
send(connect_list[i],buf,len,0);
}
intmain()
structsock addr_in6addr;
i ntreuse;
inti;
int i;
if((ssock =sock et(P F_INET6,SOCK_STREAM,0))c0)
{
perror("sock et");
return1;
}
reuse=I;
setsock opt(ssock ,SOL_SOCKET,SO_REUSEADDR,&reuse,
sizeof(reuse));
memset(&addr,0,sizeof(addr));
addr.sinfl_family =AF_INET6;
addr.sin6_addr=in6addr_any ;
addr.sin6_port=htons(P ORT);
313
return0;
6.fej ezet:H lzatik ommunik ci
i f(bind(ssock ,(structsock addr*)&addr,sizeof(addr))<0)
perror("bind");
return1;
}
if(listen(ssock ,5)<0)
{
perror("listen");
return1;
}
for(i=0;i<MAXCONNS;i++)connect_list[i]=-1;
while(1)
i ntcount=build_poll_list();
if(poll(poll_list,count,-1)>0)
{
if(poll_list[0].rev ents&P OLLIN)
{
handle_new_connection();
for(i=1; <count;i++)
if(poll_list[i].rev ents&(P OLLERRIP OLLHUP ))
for(ii=0;ii<MAXCONNS;ii++)
i f(connect_list[ii]=pol1_1 st[iI . fd)
{
connect_list[ii]=-1;
close(pol1_11st[i].fd);
else f(poll_list[i].rev ents&P OLLIN)
process_read(poll_l st[i].fd);
_..
1
11
111
A program bellt egy szerversocketet, majd sszellt egy kapcsolatlistt. Ezt
kveten a poll0 rendszerhvssal vrja, hogy kapcsoldsi krelem rkezzen.
Amikor egy olvassi esemny rkezik a szerversocketre, akkor fogadja a kap-
csolatot, s elhelyezi a listba (vagy visszautastja, ha a szerver megtelt). Ezt
kveten ismt meghvdik a pollQ. Ha valamelyik klienskapcsolatra rkezk
adat, akkor a program beolvassa, s kikldi a tbbi kapcsolatra.
3 14
6.5. IP
A szerverre a telnet program segtsgvel tudunk csatlakozni (tcp 334 4 -es
port). rdemes egyszerre tbb kapcsolatot felpteni. Ezt kveten, amit az
egyik kapcsolaton elkldnk, az a szveg a tbbi kapcsolaton megjelenik.
6.5.12.3. TCP-kliensalkalmazs
A kliensalkalmazs az esetek tbbsgben egyetlen klienssocketet tartalmaz,
amely kapcsolatot kezdemnyez valamilyen szerver fel. Majd a kapcsolat
felvtele utn megindul a kommunikci. Itt az adatfogads jelenthet nmi
problmt, ugyanis alaprtelmezsben a recv0 hvs blokkoldik, s mindaddig
nem tr vissza, amg nem rkezik valamilyen csomag. Radsul kliensoldalon
gyakran grafikus felhasznli fellet tallhat, amely ltszlag lefagy", mert
az alkalmazs blokkolt llapotban nem tudja frissteni a kpernyt s reaglni
a felhasznli interakcikra. Ugyanez a problma lphet fel szveges termi-
nl esetben is, hiszen blokkolt llapotban nem tudunk olvasni a szabvnyos
bemenetrl. Lehetsges megoldsok a kvetkezk.
Szveges mdban tovbbra is hasznlhatjuk a selectO, poll(), epoll() fgg-
vnyt, amellyel nemcsak a socketre, hanem a szabvnyos bemenetre (stdin) is
vrakozunk.
Egy msik megolds a kln szl indtsa. Ilyenkor azonban sokszor meg
kell oldanunk a szlak kommunikcijt s a kzs adathozzfrs szinkroni-
zcijt. Kln folyamatot is indthatunk a socketkommunikcira, de a ne-
hzsgek hasonlak a szlakihoz.
Grafikus felhasznli fellet esetn aszinkron socket kezelsre van szk-
sgnk. A grafikus fejleszti knyvtrak tartalmaznak ennek megvalsts-
hoz mechanizmusokat. Hasznljuk ezeket.
A socketkommunikciban lehetsgnk van a magas szint fjlkezels
hasznlatra is. Erre mutat pldt az albbi kliensprogram, amely a HTTP
0.9-es protokoll segtsgvel lement egy internetoldalt. A kapcsolds utn a
szerveralkalmazsnl mr ltottaknak megfelelen hasznlhatnnk a recv()
s a send() hvsokat a kommunikcira (amelyek, mint kiderlt, sokkal tbb
lehetsget adnak a kommunikci szablyozsra), de a plda egyszers-
gnl fogva knyelmesebb a magas szint megoldst alkalmazni:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sysisocket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
315
6.fej ezet:H lzatik ommunik ci
struccaddrinfo*p;
nterr;
charips[INET6_ADDRsTRLEN];
intcsock ;
charbuf[102 4];
FILE*fpsock ;
FILE*fpfile;
intlen;
if(argc!=4)
{
printf("Haszn lat:%s<szerv er><oldal><f j l>\n",argv [0]);
return1;
memset(&hints,0,sizeof(hints));
hints.ai_family =AF_UNSP EC;
hints.ai_sock ty pe=SOCK_STREAM;
1105err=getaddrinfo(argv [1],"http",&hints,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
fpfile=fopen(argv [3 ],"w");
if(fpfile==NULL)
{
perror("fopen");
return-1;
}
for(p=res;p!=NULL;p=p->ai_next)
{
lf(getnameinfo(p->ai_addr,p->ai_addrlen,
ips,sizeof(ips),NULL,0,NI_NUMERICHOST)==0)
{
printf("Kacsold s:%s\n",ips);
}
csock =sock et(p->ai_family ,p->ai_sock ty pe,p->ai_protocol);
i f(csock <0)continue;
if(connect(csock ,p->ai_addr,p->ai_addrlen)==0)
{
printf("Sik eresk apcsold s.\n");
fpsock =fdopen(csock ,"r+");
I
//HTTP 0.9oldallek r s
fpr ntf(fpsock ,"GET%s\r\n",argv [2 ]);
fflush(fpsock );
printf("Adatok ment se.\n");
316
6.5. IP
wh le((len=fread(buf,1,sizeof(buf),fpsock ))>0)
fwrite(buf,1,len,fpfile);
printf("Kapcsolatbont sa.\n");
fclose(fpsock );
break ;
}
else
perror("connect");
close(csock );
fclose(fpfile);
freeaddrinfo(res);
return 0;
Prbljuk ki a programot.:
./httpmentwww.aut.bme.hu/test.html
6.5.13. sszekttets nlkli kommunikci
sszekttets nlkli kapcsolathoz az IP-csald esetben a szlltsi rtegben
UDP-t (User Datagram Protocol, felhasznli datagramprotokoll) haszn-
lunk Az UDP protokoll mkdse egyszerbb, a fejlce kisebb, gy gyors kom-
munikcit tesz lehetv.
m nem garantlt, hogy
a csomag clba r;
az elkldtt adatok ugyanabban a sorrendben rkeznek meg, amely-
ben kldtk ket.
Az UDP-csomagok mrete legfeljebb 64 kB lehet.
6.5.13.1. UDP-kommunikci-plda
A 6.3. Az sszekttets nlkli kommunikci alfejezetben bemutattuk a kapcso-
lat nlkli kommunikci hasznlatt, az elz fejezetekben pedig az IP-cmek
kezelst. gy egy UDP-kommunikcit megvalst programot is sszellt-
hatunk.
3 17
6.fej ezet:H lzatik ommunik ci
A datagram-alap kommunikciknl ltalban nem klnbztetnk
meg szerver- s kliensszerepet, mivel mindkt oldal fogad s kld is adatokat.
A kvetkez pldban azonban a knnyebb rthetsg kedvrt a kt funkcit
sztvlasztottuk. gy lesz egy fogad- s egy kldprogramunk.
A fogadprogram UDP-csomagokat fogad. Kirja a kldt s a csomag tar-
talmt:
#include<stdio.h>
#include<stdl b.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<netdb.h>
#defineP ORT"112 2 "
intmain()
{
structaddrinfohints;
structaddrinfo*res;
interr;
structsock addr_in6addr;
sock len_taddrlen;
charips[NI_MAXHOST];
charserv s[NI_MAXSERV];
intsock ;
charbuf[2 56];
ntlen;
memset(&hints.0,sizeof(hints));
hints.ai_flags=AI_P ASSIVE;
hints.ai_family =AF_INET6;
h nts.ai_sock ty pe=SOCK_DGRAM;
err=getaddrinfo(NULL,P ORT,&hints,&res);
i f(err!=0)
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
3 18
b5. IP
if(sock <0)
perror("sock et");
return1;
i f(bind(sock ,res->ai_addr,res->ai_addrlen)<0)
perror("bind");
return1;
}
freeaddr nfo(res):
addrlen=s zeof(addr);
while((len=recv from(sock ,buf,sizeof(buf),0,
(structsock addr*)&addr,&addrlen))>0)
{
if(getnameinfoUstructsock addr*)&addr,addrlen,
ips,sizeof(ips),serv s,sizeof(serv s),0)==0)
fprintf(stdout,"%s:%s:",ips,serv s);
fflush(stdout);
}
write(STDOUT_FILENo,buf,len);
close(sock );
return0;
A kldprogram a szabvnyos bemeneten fogad szveget, s soronknt egy-
egy csomagban elkldi a szervernek. Egszen addig csinlja ezt, amg a
CTRL + D billentykkel lelltjuk a bevitelt:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#define PO RT "112 2 "
intmain(intargc,Ihar*argv [])
structaddrinfohints;
structaddrinfo*res;
3 19
i nterr;
intsock ;
charbuf[102 4];
intlen;
if(argc!=2 )
f
printf("Haszn lat:%s<szerv er>\n",argv [0]);
return1;
memset(&hints,0,sizeof(hints));
hints.a _family =AF_UNSP EC;
hints.ai_sock ty pe=SOCK_DGRAM;
6.fej ezet:H lzatik ommunik ci
err=getaddr nfo(argv [1], P ORT, &hints,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",ga _strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
}
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->a _protocol);
if(sock <0)
perror("sock et");
return-1;
while((len=read(ST0IN_FILENO,buf,sizeof(buf)))>0)
{
sendto(sock ,buf,len,0,res->ai_addr,res->ai_addrlen);
freeaddr nfo(res);
close(sock );
return0;
6.5.13.2. T bbe s kl d s
Amikor nemcsak egy vgpontnak, hanem egyszerre tbbnek szeretnnk elkl-
deni valamit, elg egyszer dolgunk van: specilis IP-cmre kell kldennk a
csomagot. A tbbes kldst (multicast) az IP-hlzaton az tvlasztk bo-
nyoltjk le.
3 2 0
6.11. tblzat. Elredefinilt IPv4-es multicastcsoportok
Az egy LAN-on lv tvlasztk
Az egy LAN-on lv tvlasztk
6.5. IP
IPv4 esetn valamelyik D osztly (2 2 4 .0.0.0-2 39.2 55.2 55.2 55) cmet kell
hasznlnunk. Minden D osztly cm egy hosztcsoportot jelent Vannak ideig-
lenes hosztcsoportok, amelyhez csatlakozhatunk, vagy amelybl kivlhatunk.
Van azonban nhny lland cm is.
87
Az IPv6 esetn a tbbes klds cmeinek az ff00::/ 8 tartomny van fenntart-
va. Ebben az esetben is szmos elre definlt csoport van.
88
6.12. tblzat. Elredefinilt IPv6-os multicastcsoportok
A tbbes klds fogadsa elre definilt csoportoknl nem ignyel plusz m-
veletet. Ha azonban dinamikusan ltrehozott csoportot szeretnnk hasznlni,
akkor a socketnket hozz kell rendelnnk a kivlasztott csoporthoz. Ezt a
setsockopt0 fggvnnyel (bvebben lsd a 6.6. Socketbelltsok alfejezetben)
vgezhetjk el:
#include<sy s/sock et,h
intsetsock opt(intsock fd,intlev el,int optname,
const void *optval, socklen_t optlen);
A fggvny igen sok funkcit valst meg. Tbbes kldsnl az els paramter
a socketler, a level IPv4 esetn IPPROTOJP, IPv6 esetn IPPROTOJPV6.
Az optname argumentum rtkeit IPv4 esetn a 6.13. tblzat foglalja ssze.
6.13. tblzat. /P1)4-es multicastbelltsok
Opci neve Lers
1P_MULTICAST LOOP Ezzel tilthatjuk/engedlyezhetjk azt, hogy az elkldtt
multicast zeneteket mi is megkapjuk.
" A teljes listt a http:/ /www.iana.org /assignments/ multicast-addresses/multicast-addresses.
txt cmen tallhatjuk meg.
88 A teljes listt a http:/ / www.iana.org / assignments/ipv6-multicast-addresses / ipv6-multi-
cast-addresses.xml cmen rhetjk el.
32 1
6. fejezet: Hlzati kommunikci
Opci neve Leirs
IP MULTICAST TTL Ezzel llthatjuk a time-to-live (TTL) mezt.
IP MULTICAST 1F Itt adhatjuk meg, hogy melyik hlzati interfszrl
kldjk a csomagokat. A rendszer-adminisztrtor alap-
rtelmezsben megad egyet, de fellrhatjuk.
IP ADD_MEMBERSHIP Csatlakozs egy csoporthoz.
IP DROP MEMBERSH1P Kivls egy csoportbl.
IPv6 esetn az albbi opcikat hasznlhatjuk:
6.1 4. tblzat. IPv6-os multicastbelltsok
Opci neve Lers
IPV6 MULTICAST LOOP Ezzel tilthatjuk/engedlyezhetjk azt, hogy az elkldtt
multicast zeneteket mi is megkapjuk.
IPV6 MULTICAST HOPS Ezzel llthatjuk a hop limit mezt.
IPV6 MULTICAST IF Itt adhatjuk meg, hogy melyik hlzati interfszrl
kldjk a csomagokat. A rendszer-adminisztrtor alap-
rtelmezsben megad egyet, de fellrhatjuk.
IPV6_JOIN GROUP Csatlakozs egy csoporthoz.
IPV6 LEAVE GROUP Kivls egy csoportbl.
Nzznk pldt a fontosabb funkcikra. Ha szeretnnk vagy nem szeretnnk
visszakapni az elkldtt csomagokat, akkor a kvetkezkppen engedlyez-
hetjk vagy tilthatjuk le:
i_charloop;
loop=1;/*Tiltas:loop=0; */
"1~
setsock opt(sock et,IP P ROTO_IP ,IP _MULTICAST_LOOP ,&loop,
sizeof(loop));
Az IP-csomag fejlcben elhelyezked TTL- (Time-To-Live, letbenmaradsi
id) rtk minden tvlasztn val thaladskor eggyel cskken, s ha elri a
0 rtket, az tvlaszt eldobja a csomagot. Ez meggtolja, hogy a csomagok
az idk vgtelensgig keringjenek a hlzaton. Tbbes klds esetn ez a
mez egy msik szerepet is betlt: minden egyes tvlaszt-interfszhez egy
kszbszm (threshold) van rendelve, amellyel a tbbeskldtt csomagban
szerepl rtket ssze kell hasonltani, s csak akkor lehet a csomagot to-
vbbengedni, ha a TTL-rtk nagyobb, mint a kszbszm. A 6.15. tblzat-
ban talljuk a gyakorlatban alkalmazott kszbszmokat:
3 2 2
6.5.IP
6.15. tblzat. T7'L- rtkek
TTL-rtk rvnyessg
0 Csak ugyanarra a hosztra mehet el a csomag. Nem lesz tovbbkldve
egyetlen interfszen sem.
1 Csak ugyanazon az alhlzaton kapjk meg. Egy tvlaszt sem
tovbbtja.
< 2 55 Az egsz internet megkapja.
A csomag TTL-rtkt az albbi kdrszlet mintjra llthatjuk be:
u_charttl;/70-2 55-igv ehetfelertek et
ttl-1;
setsock opt(sock et, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
sizeof(ttl));
Ha nem lltjuk be a TTL-mezt, az alaprtelmezett rtk 1, s ez megakad-
lyozza, hogy a csomag kikerljn az alhlzatbl.
Ha egy csoporthoz csatlakozni akarunk, IPv4 esetn az albbi struktrt
kell kitltennk:
structip_mreq
structin_addrimr_multiaddr; /* A csoportIP cime*/
structin_addrimr_interface; /* A lok alis IP cim */
1;
IPv6 esetn a struktra a kvetkez:
structipv 6_mreq
structin6_addr'ipv 6mr_multiaddr;/*A csoport I P cime*/
unsignedintipv 6mr_ nterface; /* A lok alisinterf sz */
;
A korbbi UDP-fogad pldaprogram kibvtett vltozatn mutatjuk be a cso-
portcmek hasznlatt:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<netdh.h>
#include<arpa/inet.h>
3 2 3
6. fejezet: Hlzati kommunikci
#define PO RT "112 2 "
intmain()
{
structaddrinfohints;
structaddrinfo*res;
nterr;
structsock addr_in6addr;
sock len_taddrlen;
charips[Ni_mAxHOST]:
charserv s[NI_MAXSERV];
intsock ;
charbuf[2 56];
intlen;
structip_mreqmreq;
structipv 6_mreqmreq6;
memset(&hints,0,sizeof(hints));
hints.ai_flags=AI_P ASSIVE;
hints.ai_family =AF_INET6;
hints.ai_sock ty pe=SOCK_DGRAM;
err=getaddrinfo(NULL,P ORT,&hints,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err))
return-1;
}
if(res==NULL)
{
return-1;
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
if(sock <0)
{
perror("sock et");
return1;
if(bind(sock ,res->ai_addr,res->ai_addrlen)<0)
{
perror("bind");
return1;
freeaddrinfo(res);
memset(&mreq,0,sizeof(mreq));
inet_pton(AF_INET,"2 2 4.1.1.1",&mreq.imr_multiaddr);
324
6.5. IP
if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) ! = 0 )
perror("IP_ADO_MEMBERSHIP");
return -1;
M
I
memset(&mreq6, 0, sizeof(mreq6));
net_pton(AF_INET6, "ff02 : :13D" , &mreq6, pv6mr_mul ti add r) ;
i f(setsockopt(sock, IPPROTO_IPv6, IPV6_JOIN_GROUP, &mreq6,
sizeof(mreq6)) ! = 0 )
perror("IPV6_JOIN_GROUP");
return -1;
}
addrlen = sizeof(addr);
while((len = recvfrom(sock, buf, sizeof(buf), 0,
(strucc sockaddr*)&addr, &addrlen)) > 0)
i f(getnameinfo((struct sockaddr*)&addr, addrlen,
ips, sizeof(ips), servs, sizeof(servs), 0) == 0)
{
fprintf(stdout, "%s:%s: ", ips, servs);
fflush(stdout);
1
write(STDOUT_FILENO, buf, len);
close(sock);
return 0;
A szolgltatsunkat hozzrendeljk a 2 2 4 .1.1.1 IPv4 -es s az f'f()2 ::13D IPv6-os
csoportcmekhez. Ha lefuttatjuk a mdostott fogadprogramot, akkor a ko-
rbbi kldprogrammal tesztelhetjk.
Feladat Teszteljk a mdostott UDP-fogad programot gy, hogy a kldprogramnl a kvet-
kez cmeket hasznljuk: 224.1.1.1, ff02::13D, ff02::1.
325
6. fejezet: Hlzati kommunikci
6.6. Socketbelltsok
A socketbelltsokkal a socket mkdsnek szmos jellemzjt tudjuk m-
dostani. Egy-egy socketmvelet sorn tbb protokollszintet is hasznlunk
egyszerre. Egy TCP-kommunikci sorn pldul hasznljuk a TCP-, az IP-
s a socketszintet. Az egyes szinteken klnbz opcikat tudunk belltani
s ezzel hangolni a kommunikcit.
A belltsokat a getsockoptQ rendszerhvssal krdezhetjk le, s a set-
sockoptO rendszerhvssal mdosthatjuk:
#include<sy s/sock et.h>
intgetsock opt(intsock fd,intlev el,intoptname,
v oid*optv al,sock len_t*optlen);
intsetsock opt(intsock fd,intlev el,intoptname,
const v oid*optv al, socklen_t optlen);
Az els paramter a socket lerja. Ezzel hivatkozunk arra a socketre, amely-
nek a belltsait mdostani szeretnnk. A level paramterrel adjuk meg,
hogy melyik protokollszinthez tartozik az a bellts, amelyet kezelni szeret-
nnk. A 6.16. tblzatban sszefoglaljuk a tipikusan hasznlt rtkeket.
6.16. tblzat. IP protokoll szintek
rtk Szint man" oldal
SOL_SOCKNT socket s egyben Unix socket(7), unix(7)
1PPROTO_IP IPv4 ip(7)
rPPROTO IP6 IPv6 ipv6(7)
IPPROTO_TCP TCP tcp(7)
1PPROTO_UDP UDP udp(7)
Az optname paramterben adjuk meg a kivlasztott opcit. A lehetsges bel-
ltsok a protokollszinttl fggenek. Az elz tblzat utols oszlopban meg-
adtuk az adott szintet ler man" oldal nevt. Ezek a lersok tartalmazzk a
teljes belltslistt.
Az optval paramter tartalmazza a bellts rtkt, mg az optlen a vl-
toz mrett. Az rtk tpusa fgg a belltstl, s az elbb emltett lersok
tartalmazzk.
Az albbiakban kiemelnk nhny gyakrabban hasznlt belltst. A tb-
bes klds belltsaira nem trnk ki (ezeket lsd a 6.5.13.2. Tbbes klds al-
fejezetben).
326
6.6. Socketbelltsok
SO_KEEPALIVE
A socketszint tartalmazza. Kapcsolatalap socket esetn
.
n. letben tart
(keep-alive) zeneteket kld. Ennek segtsgvel abban az esetben is rzkel-
hetjk a kommunikcis hibt, ha egybknt hosszan nem forgalmazunk
adatot. Az rtk tpusa integer. 0 s 1 rtkkel kapcsolhatjuk ki, illetve be.
SO_REUSEADDR
A socketszint tartalmazza. A bindo rendszerhvs szmra jelzi, hogy a lok-
lis portot jra felhasznlhatja, ha ppen nincs aktv socket az adott porton.
Az rtk tpusa integer. 0 s 1 rtkkel kapcsolhatjuk ki, illetve be.
tmutat Ahogy a korbbi pldinkban is lthat volt, ennek a belltsnak a hasznlata igen
gyakori. Ha nem hasznlnnk, akkor a folyamat lelltst kveten nem lehetne az alkalma-
zst azonnal jraindtani, mert ekkor a bind() mvelet hibval trne vissza. Azt jelezn, hogy
a portot mr msik folyamat hasznlja. Ekkor ki kell vrnunk egy bizonyos idt, amg a port j-
ra hasznlhatv vlik. A SO_REUSEADDR bellts hasznlatval viszont a port azonnal jra-
hasznosthat, ha lezrtuk a szerversocketet.
TCP_CORK, UDP_CORK
A TCP-, illetve az LTDP-rteg tartalmazza ket. Ha belltjuk ezt az opcit,
akkor a sendO, illetve a sendto0 fggvnyek meghvsakor nem kldi el
azonnal a csomagokat, hanem egy vrakozsi sorban gyjtgeti ket. Ezt k-
veten az opci kikapcsolsakor az adatok kikldse egy csomagban trtnik.
Az rtk tpusa integer, s 0/1 rtkekkel kapcsolhatjuk ki s be az opcit.
Ezek a belltsok nem hordozhatk, csak Linux rendszereken mkdnek.
Az albbi pldban a korbbi UDP-kld program mdostsval de-
monstrljuk a bellts mkdst:
#include <stclio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#nclude <netinet/udp.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT "1122"
#define SAYS "Simon mondja: "
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
nt err;
BEI
327
6. fejezet: Hlzati kommunikci
intsock ;
charbuf[102 4];
intlen;
intstate;
i f(argc!=2 )
printf("Haszn lat:%s<szerv er>\n",argv [0]);
return1;
memset(&hints,0,sizeof(hints));
hints.ai_family =AF_UNSP EC;
h nts.ai_sock ty pe=SOCK_DGRAM;
err=getaddrinfo(argv [1],P ORT,&h nts,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
i f(sock <0)
{
perror("sock et");
return-1;
}
state=1;
setsock opt(sock ,IP P ROTO_UDP ,UDP _CORK,&state,sizeof(state));
while((len=read(STDIN_FTLENO,buf,sizeof(buf)))>0)
{
sendto(sock ,buf,len,0,res->ai_addr,res->ai_addrlen);
}
freeaddrinfo(res);
state=0;
setsock opt(sock ,IP P ROTO_UDP ,UDP _CORK,&state,sizeof(state));
close(sock ):
return0;
3 2 8
6.6. Socketbelltsok
Fordtsuk le s prbljuk ki a programot. Azt tapasztaljuk, hogy a bert sz-
veget nem soronknt kldi el a fogadnak, hanem egyben, egy csomagban.
A gyakorlatban finomabban tudjuk szablyozni a csomagok sszevonst
a sendO, illetve a sendto() rendszerhvs MSG_MORE opcijval. Ilyenkor az
MSG MORE opcival kldtt adatok belekerlnek a vrakozsi sorba, majd a
soron kvetkez MSG_MORE opci nlkli hvs sorn az adatok kikldse
egyben trtnik meg. Ennek mkdst a kvetkez pldaprogram mutatja be:
#include <stdio.h>
#include <stdlb.h>
#include <unistd.h>
#include <stri ng h>
#include <sys/socket.h>
#include <net net/i n h>
# nclude <arpa/inet.h>
#include <netdb.h>
#define P ORT"1122"
#define SAYS "Simon mondja: "
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
int err;
int sock;
char buf[1024];
int len;
if(argc !=2)
{
printf("Hasznlat: %s <szerver>\n", argv[0]);
return 1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_famly =AF_UNSP EC;
hints,ai_socktype =SOCK_DGRAM;
err =getaddrinfo(argv[1], PO RT, &hints, &res);
if(err !=0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return -1;
if(res ==NULL)
t
return -1;
sock =socket(res->ai_family, res->a_socktype,
res->ai_protocol);
329
6. fejezet: Hlzati kommunikci
i f(sock < 0)
perror("socket");
return -1;
while((len = read(STDIN_FILENO, buf, sizeof(buf))) > 0)
{
sendto(sock, SAYS, strlen(SAYS), MSG_MORE,
res->ai_addr, res->ai_addrlen);
sendto(sock, buf, len, 0, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
cl ose(sock) ;
return 0;
Ha a programot kiprbljuk, akkor azt tapasztalhatjuk, hogy a kt
sendto0
hvs adatai egyben, egy csomagban klddnek ki.
6.7. Segdprogramok
A hlzati kommunikci implementlsakor belefuthatunk hibkba, amikor
a kommunikci valamirt nem tud felplni a programjaink kztt. Ilyenkor
segdprogramok segthetnek kiderteni, hogy meddig jutottunk el a kapcsolat
felptsben.
Az egyik legfontosabb program a netstat, amely szmos informcit kir a
hlzati alrendszerrl. Paramterek nlkl kirja az ppen l hlzati kap-
csolatokat. A -a paramterrel a lista kiegszl a szerver- s az UDP-socketek-
kel. A -t s a -u opcival kiegsztve a listt leszkthetjk a TCP-, illetve
UDP-socketekre. Emellett a -n opcival kikapcsolhatjuk a nvfeloldst, s
mindent numerikusan lthatunk
A netstat a forgalmazott csomagokrl nem ad informcit, m a tcpdump
program igen. Segtsgvel monitorozhatjuk a hlzati csomagforgalmat, s
alacsony szinten megnzhetjk, hogy a programunk tnyleg kld-e vagy kap-
e csomagokat.
A tcpdump program szveges interfsze miatt nagyobb forgalom esetn
nehezen kezelhet. m a feladatra ltezik egy grafikus felhasznli fellettel
rendelkez program, a wireshark.
89
A grafikus fellet nagyban segti a prog-
ram hasznlatt s az adatok rtelmezst.
89
A Wireshark program weboldala: http://www.wireshark.org/.
330
-
-
.11 II
Frame 1, 42 bytes un wtre (336 birs), 42 bytes captured ( 336 blts)
Ethernet II. Src: Hewlett. fS:de:la ( 68:b5:99:f3:de: la), 0st: Broadcast ( ff:ff:ff:ff:ff:ff)
6.8. Tvoli eljrshvs
C4r8.uril8Frer8 wON0(.3
,
p
,
rdr,,,t 147 66 188 111 rWcres'neri: 1671
, Q.7 ,Caoture mkae Tele.$.71lt Jpols Irccm,lls he(:.
'
a a a ZT ITU J i ts "
8488388:0
,
0>sbnac
e
,
Lenath
1 0.000000 Hetimtett-_f3:de:ta Broadcast ARP 42 who has 152.66.188.11?
2 0.000514 tlicrosof_fb. ld: f Hewlett - t3 de la ARP 65 I52.66 188.11 is a1 00:15
6.5. bra. A Wireshark fablaka
A Wireshark program fellett a 6.5. bra mutatja. A program fablaka h-
rom rszre tagoldik. A fels rszben egy listt tallhatunk, amely az elkapott
csomagokat tartalmazza. Ha ebbl a listbl kivlasztunk egy csomagot, ak-
kor az als rszben lthatjuk a binris tartalmt, mg a kzps rsz ezt r-
telmezett formban mutatja. A vizsgldsaink sorn elssorban a kzps
rszt hasznljuk.
A kzps mez a kivlasztott csomag ltal tartalmazott keretek listjt
mutatja. Ahogy a csomag az egyes hlzati rtegeken keresztl haladva fel-
pl, minden rteg egy j keretet alkot belle. Minden keret rendelkezik n-
hny fejlcmezvel s egy adatrsszel. A lista elemeit lenyitva a fejlcmezk
tartalmt tekinthetjk meg.
6.8. Tvoli eljrshvs
A tvoli eljrshvs (Remote Procedure Call, RPC) egy magas szint
kommunikcis paradigma. Lehetv teszi tvoli gpeken lv eljrsok
meghvst, mikzben elrejti a felhasznl ell az alsbb hlzati rtegeket.
Az RPC logikai kliens-szerver modellt valst meg. A kliens szolgltatsi
ignyeket kld a kiszolglnak. A szerver fogadja az ignyeket, vgrehajtja a
krt funkcit, vlaszt kld, majd visszaadja a vezrlst a kliensnek.
331
6. fejezet: Hlzati kommunikci
Az RPC megkmli a felhasznlt az alsbb hlzati rtegek ismerettl s
programozstl. A hvsok transzparensek. A hvnak explicite nincs tudom-
sa az RPC-rl, a tvoli eljrsokat ugyangy hvja, mint egy helyi eljrst.
6.8.1. Az RPC-modell
A tvoli eljrshvs modellje hasonlt a helyi eljrshvs modelljre. A helyi
eljrs hvja a hvs argumentumait egy jl meghatrozott helyre teszi,
majd tadja a vezrlst az eljrsnak. A hvs eredmnyt a hv egy jl
meghatrozott helyrl elveszi, s tovbb fut. Tvoli eljrshvs esetn a vg-
rehajtsi szl kt folyamaton (kliens s szerver) halad keresztl. A hv zene-
tet kld a szervernek, majd vlaszra vr. A hv zenete tartalmazza a hvs
paramtereit, a vlaszzenet pedig az eljrs eredmnyt. A kliens kiveszi a
vlaszzenetbl az eredmnyt, s tovbb fut.
A gp
Kliensprogram
B gp
Szerverdmon
RPC-hvs
Szolgltats
meghvsa
17
Szolgltats
vgrehajtsa
Szolgaltats
ksz
Program
folytatdik
6.6. bra. RPC-kommunikci
A szerveroldalon egy vrakoz alv processz vrja a hvk zeneteit.
Az rkez zenetbl kiveszi az eljrs paramtereit, elvgzi a feladatot, majd
visszakldi a vlaszzenetet. A kt processz kzl egy idben csak az egyik
aktv, a msik vrakoz llapotban van.
6.8.2. Verzik s szmok
Minden RPC-eljrst egyrtelmen meghatroz egy programszm s egy elj-
rsszm. A programszm az eljrsok egy csoportjt jelli. A csoporton bell
minden eljrsnak egyedi eljrsszma van. Ezen kvl minden programnak
van verziszma is. gy a szolgltatsok bvtse vagy vltoztatsa esetn
Vlasz
332
6.8. Tvoli eljrshvs
nem kell j programszmot adni, csak a verziszmot nvelni. A programsz-
mok egy rsze elredefinilt, ms rszk fenntartott. A fejlesztk szmra a
0x2 0000000-0x3fffffff tartomny ll rendelkezsre.
6.8.3. Portmap
Minden hlzati szolgltatshoz dinamikusan vagy statikusan hozz lehet
rendelni portszmot. Ezeket a szmokat regisztrltatni kell a gpen fut
portmap dmonnal. Ha egy hlzati szolgltats portszmra van szksg,
akkor a kliens egy RPC-kr zenetet kld a tvoli gpen fut portmap d-
monnak. A portmap RPC-vlaszzenetben megadja a krt portszmot. Ezu-
tn a kliens mr kzvetlenl kldhet zenetet a megadott portra. A fentiek-
bl kvetkezik, hogy a portmap az egyetlen olyan hlzati szolgltats,
amelynek mindenki ltal ismert, dediklt portszmmal kell rendelkeznie. Je-
len esetben ez a portszm a 111.
6.8.4. Szllts
Az RPC fggetlen a szlltsi protokolltl. Nem foglalkozik azzal, hogy miknt
addik t az zenet az egyik processztl a msiknak. Csak az zenetek specifi-
kcijval s rtelmezsvel foglalkozik. Ugyancsak nem foglalkozik a megbz-
hatsgi kvetelmnyek kielgtsvel. Ez egy megbzhat szlltsi rteg
- pldul az sszekttets-alap TCP - felett kevsb okoz gondot. Egy kevsb
megbzhat szlltsi rteg - pldul UDP - felett fut RPC-alkalmazsnak
magnak kell gondoskodnia azonban az zenetek megbzhat tovbbtsrl.
Linux alatt az RPC tmogatja mind az UDP-, mind a TCP-szlltsi rte-
get. Az egyszersg kedvrt a TCP-t ajnlatos hasznlni.
6.8.5. XDR
Az RPC felttelezi az n. kls adatbrzols (eXternal Data Representation,
XDR) megltt. Az XDR gpfggetlen adatler s kdol nyelv, amely jl
hasznlhat klnbz szmtgp-architektrk kztti adattvitelnl.
Az RPC tetszleges adatstruktrk kezelsre kpes, fggetlenl az egyes
gpek bels adatbrzolstl. Az adatokat elklds eltt XDR-formra ala-
ktja (serializing), a vett adatokat pedig visszaalaktja (deserializing).
333
6. fejezet: Hlzati kommunikci
6.8.6. rpcinfo
Az rpcinfo parancs hasznlatval informcikat krhetnk a portmap d-
monnl bejegyzett programokrl: program neve, szma, verzija, portszma,
a hasznlt szlltsi rteg. Ezen kvl meg lehet vele krdezni, hogy egy prog-
ram adott verzija ltezik-e, illetve vlaszol-e a krsekre.
A loklis gpre az informcik lekrdezse a kvetkez:
6.8.7. rpcgen
A tvoli hvst hasznl alkalmazsok programozsa nehzkes s bonyolult
lehet. Az egyik nehzsget ppen az adatok konverzija jelenti. Szerencsre
ltezik egy rpcgen nev program, amely segti a programozt az RPC-alkal-
mazs elksztsben.
Az rpcgen egy fordt. Az RPC-program interfsznek defincijt az el-
jrsok nevt, az tadott s visszaadott paramterek tpust az gynevezett
RPC nyelven kell lerni. A nyelv hasonlt a C-re. A fordt az interfszdefinci
alapjn nhny C nyelv forrslistt llt el: a kzsen hasznlt defincikat
(headerfjlt), a kliens- s a szerveroldali RPC-programok vzt (skeleton).
A vzak feladata az, hogy elrejtsk az alsbb hlzati rtegeket a program
tbbi rsztl.
A programfejlesztnek mindssze az a feladata, hogy megrja a szerverol-
dali eljrsokat. Az eljrsok tetszleges nyelven megrhatk, figyelembe v-
ve termszetesen az interfszdefincit s a rendszerhvsi konvencikat.
Az eljrsokat sszeszerkesztve a szerveroldali vzzal, megkapjuk a futtatha-
t szerveroldali programot.
A kliensoldalon a fprogramot kell megrni, ebbl hvjuk a tvoli eljrsokat.
Ezt linkelve a kliensoldali vzzal, megkapjuk a futtathat kliensprogramot.
Az rpcgen-nek ltezik egy a kapcsolja is, amely tovbb egyszersti a
feladatunkat Hasznlatval az interfszllomnybl mg a megrand prog-
ramrszekre is kapunk egy C nyelv vzat, amelyet mr csak ki kell egsz-
tennk, hogy hasznlhassuk. (gyeljnk arra, hogy egy ismtelt generlssal
a C-vzak fellrdnak, ezrt clszer tneveznnk ket.)
gy ltalban a kvetkez parancsot hasznljuk:
-rpoOr-41
,
-Irltferfa
~.
ahol az interface.x az interfszllomny.
334
1
6.8. Tvoli eljrshvs
6.8.8. Helyi eljrs talaktsa tvoli eljrss
Tegyk fel, hogy van egy eljrsunk, amely loklisan fut. Ezt az eljrst sze-
retnnk tvoliv tenni. Az talaktst egy egyszer pldn vizsgljuk meg.
A loklis program a hvskor megadott paramtert, mint zenetet, kirja a
kpernyre. A cl az, hogy tvoli gp kpernyjre is tudjunk zenetet kirni.
A program loklis vltozata a kvetkez:
/*printmsg.c-uzenetk iirasaak eperny ore.*/
#include<stdio.h>
intprintmessage(char*msg)
printf("%s\n",msg);
return1;
intmain(intargc,char*argv [])
{
char*message;
i f(argc!=2 )
t
fprintf(stderr,"Hasznalat:%s<uzenet>\n",argv [0]);
return-1;
message=argv [1];
tf(!printmessage(message))
fprintf(stderr,"%s:nemmegj elenithetoazuzenet.\n",
argv [0]);
return-1;
}
printf("Azuzenetelk uldv e!\n");
return0;
A protokoll kialaktshoz szksg vannak annak ismeretre, hogy az elj-
rsnak milyen tpus paramterei s visszatrsi rtkei vannak. Jelen eset-
ben a printmessage0 fggvny szveget vesz t paramterknt, s egy egsz
szmot ad vissza. A protokollt hagyomnyosan egy .x kiterjeszts llomny-
ban rjuk meg:
/*msg.)(-Tav ol uzenetny omtatasprotok ollj a.''/
programMESSAGEP ROG /*programnev */
v ersionMESSAGEVERS{ /*v erzionev */
intP RINTMESSAGE(string)=1; /*1.fuggv eny */
} =1; /*v erzioszam*/
} =0x2 0000099; /*programszam*/
335
6.fej ezet:Hlzati kommunikci
A tvoli program egyetlen eljrst tartalmaz, amelynek szma 1. Az RPC auto-
matikusan generl egy O. eljrst is. Ez a szerver megszltsra (pinging)
hasznlhat A nagybetk hasznlata nem szksges, csak hasznos konvenci.
szrevehet, hogy az argumentum tpusa nem char*, hanem string. Ez
azrt van, mert a klnbz nyelvek msknt rtelmezik a szveges tpust,
st a char* mg a C nyelvben sem egyrtelm. A hasznlhat vltoztpuso-
kat az XDR dokumentcija tartalmazza.
Nzzk a tvoli eljrs implementcijt:
/* msg_proc.c - Tavoli printmessage eljaras. */
#include <stdio.h>
#include <rpc/rpc.h>
#include "msg.h"
int* printmessage_1(char** msg)
f
static int result;
printf("%s\n", *msg);
result =1;
return (&result);
A printmessage_10 tvoli eljrs hrom dologban klnbzik a printmessage()
helyi eljrstl.
Argumentumknt stringre mutat pointert vesz t string helyett. Ez min-
den tvoli eljrsra rvnyes. Ha nincs argumentum, akkor void*-ot kell
megadni.
Vissza egsz szmra mutat pointert ad, egsz helyett. Ez szintn jellemz
a tvoli eljrsokra. A pointer-visszaads miatt kell a result vltozt staticknt
megadni. Ha nincs visszatrsi rtk, akkor void*-ot kell hasznlni.
A tvoli eljrs nevnek a vgre _1" kerlt. ltalban az rpcgen ltal
generlt eljrsok neve a protokolldefinciban szerepl nv kisbetkkel, egy
alhzsi karakter, vgl pedig a verziszm.
Vgl kvetkezzen a kliensprogram, amely a tvoli eljrst meghvja:
/* rprintmsg.c - A printmsg.c tavoli verzioja. */
#include <stdo.h>
#include <rpc/rpc.h>
#include "msg.h"
nt man(int argc, char* argv[])
{
CLIENT* cl;
int* result;
char* server;
char* message;
336
6.8. Tvoli eljrshvs
i f(argc ! = 3)
{
fprintf(stderr,"Hasznalat:%s.szerv er><uzenet>\n",
argv [0]);
return-1;
serv er=argv [1];
message=argv [2 ];
/* A k liensleiroletrehozasa,k apcsolatfelv etelea
szerv errel.
-
V
cl=clnt_create(serv er, MESSAGEPROG, MESSAGEVERS,
"tcp");
if(c1 == NULL)
{
clnt_pereateerror(serv er);
return-1;
}
7* A tav olielj arasmeghiv asa.*/
result=printmessage_1(&message,cl);
if(*result==NULL)
{
clnt_perror(cl,"callfailed");
return-1;
}
if(result==0)
f
fprintf(stderr,"%s:%snemmegj elenithetoazuzenet\n",
argv [0],serv er);
return-1;
printf("Azuzenetelk uldv ea%sszerv ernek !\n",serv er);
return0;
Els lpsknt a kapcsolatot hozzuk ltre a clnecreate0 meghvsval. A vissza-
kapott lert a tvoli eljrs argumentumaknt hasznljuk. A cInt_create0 utol-
s paramtere a szlltsi protokollt adja meg. Jelen esetben ez TCP, de lehet
UDP is.
A printmessage_1O eljrs meghvsa pontosan ugyangy trtnik, ahogy
azt az msg_proc.c llomnyban deklarltuk, de itt utols paramterknt meg
kell adni a kliens-kapcsolatazonostt is.
A tvoli eljrshvs ktfle mdon trhet vissza hibval. Ha maga az
RPC-hvs nem sikerlt, akkor a visszatrsi rtk NULL. Ha a tvoli eljrs
vgrehajtsa kzben kvetkezik be hiba, akkor az alkalmazstl fgg a hiba-
jelzs. Esetnkben a 0 visszatrsi rtk mutatja a hibt.
3 3 7
6. fejezet: Hlzati kommunikci
A kiegsztend kdvzat (skeleton) tartalmaz llomnyokat az
r> 00:1 1 1 ~
x
paranccsal generlhatjuk. Ez a kvetkez llomnyokat hozza ltre:
Egy msg.h headerllomnyt, amelyben definilja a MESSAGEPROG,
MESSAGEVERS s PRINTMESSAGE konstansokat, tovbb a fgg-
vnyeket kliens- s szerveroldali formban is.
A kliensprogram vzt az msg_clnt.c llomnyban. Ebben szerepel a
printmessage_1() eljrs, amelyet a kliensprogram hv.
A kiszolglprogram vzt az msg_suc.c llomnyban. Ez a program
hvja az msgproc.c llomnyban tallhat printmessage_10 eljrst.
Az rpcgen a a kapcsol hasznlatakor ezek mellett a kliens- s a szerver-
program egyszer implementcijt s a makefile-t is ltrehozza. (Vigyzzunk
a make clean hasznlatval, mert itt a szoksos megvalstssal szemben a
generlt kliens- s szerverprogram forrst is letrli.)
338
HETEDIKFEJEZET
Fejleszts a Linux-
kernelben
Az opercis rendszer egyik feladata az, hogy egy egysges, magas szint prog-
ramozsi felletet nyjtva elrejtse a felhasznl ell a rendszer hardverelemei-
nek a kezelst. Az llomnykezels sorn pldul nem kell foglalkoznunk a
konkrt troleszkz kzvetlen vezrlsvel, mivel az opercis rendszer meg-
teszi ezt helyettnk.
Ha a fejlesztk belemerlnek a Linux-kernelbe, annak az az egyik leg-
gyakoribb oka, hogy specilis eszkzeikhez meghajtprogramot szeretnnek k-
szteni. Ilyenkor az a feladat, hogy az eszkz alacsony szint interfszre ptve
megvalstsk az opercis rendszer magas szint interfszt. A Unix vilg-
ban az eszkzket llomnyknt, az gynevezett fjlabsztrakcis interfszen
kezeljk (lsd a 2.1. A Linux-kernel felptse alfejezetben). Ez a Linux-meg-
hajtprogram esetben azt jelenti, hogy az eszkz kezelst llomnymvele-
tekre kell lekpeznnk.
9
A Linuxnl ez a feladat sok esetben nem is olyan
nehz, m komoly odafigyelst ignyel, mivel a kernel a rendszer rzkeny
rsze: egy elrontott kd ezen a helyen a rendszer sszeomlst is eredm-
nyezheti.
Termszetesen az eszkzk sklja, gy az eszkzvezrlk is, elg szles.
Radsul a kernel kapcsold fggvnyeit gyakran vltjk fel j verzik.
Ezrt ebben a fejezetben tfog bevezetst nyjtunk a leggyakrabban hasz-
nlt technikkba, fknt a kevss vltoz alapelvek ismertetsre s azok il-
lusztrlsra szortkozunk, mintegy kiindulsi alapknt azok szmra, akik
ebben a tmban szeretnnek elmlyedni.
Linux alatt az eszkzvezrlket kernelmodulknt valstjuk meg. A ker-
nelmodul a betlts utn hozzkapcsoldik a kernelhez, s annak szerves r-
szt alkotja. gy lnyegben a kernelmodul-fejleszts Linux-kernel-fejlesztst
jelent.
9
A Linuxban nem minden meghajt rendelkezik llomnyinterfsszel, m a tbbsg igen.
7. fejezet: Fejleszts a Linux-kernelben
7.1. Verzifggsg
A kernel a Linux egyik legdinamikusabban fejld rsze. Ebbl kvetkezen a
verzivltsok sorn gyakran kerlnek bele strukturlis s szintaktikai vlto-
zsok. A 2 .4 -es stabil kernel verzirl a 2 .6-os stabil verzira trtn vlts a
modulok jelents trst tette szksgess, mert a kt kernelverzi kztti k-
lnbsgek jelentsek voltak. A 2 .6-os verzitl kezdden a kernel fejlesztsi
ciklusa megvltozott. Megsznt a stabil mellett prhuzamosan megjelen fej-
leszti kernelvltozat, gy a vltozsok kzvetlenl a kernel egyetlen fejlesztsi
vonalba kerltek. Ennek egyik hatsa az, hogy szinte folyamatosan kisebb t-
alaktsokat kell vgeznnk a moduljainkon. Termszetesen, ha kt egymstl
szmozsban tvolabb es 2 .6.X-es kernelverzi kztt vltunk, akkor a kis
mdostsok szma is megnvekszik. Ugyanakkor nem jellemz olyan draszti-
kus nagy talakts, mint a korbban emltett 2 .4 ---> 2 .6 vlts esetben. Ebbl
is kvetkezik, hogy a kernel f verziszmai rgta nem is vltoztak.
9
' A nem-
rg megjelent 3.0-s kernel verziszma is valjban csak szimbolikus, s nem
tartalmaz jelents eltrseket a 2 .6.39-es verzihoz kpest.
A folyamatos fejlds tkrben fontos felhvni a figyelmet arra, hogy az
ebben a fejezetben tallhat forrskdok a knyv rskor aktulis 2 .6.39-es
kernelverzihoz kszltek. Jllehet ksbbi verzik hasznlatakor elfordul-
hat, hogy a szintaktika egyes pontokon eltr, m a kd mgtt ll alapelvek
lassabban vltoznak, gy remnyeink szerint a fejezet a ksbbi kernelverzi-
knl is aktulis marad.
A kisebb szintaktikai mdostsokat ltalban a fordtskor kapott hiba-
jelzsek alapjn rgtn szrevesszk. Ilyenkor a helyes szintaktika knnyen
felderthet az aktulis kernelforrs tanulmnyozsval. Ha keresnk pld-
ul egy olyan eszkzvezrlt, amely a problms rszletben hasonlt a mi esz-
kzvezrlnkre, akkor innen kiderthetjk, hogy az aktulis kernelverzi ese-
tben mi a helyes szintaktika.
Idnknt a kernelforrs mellett tallhat dokumentcik is segthetnek.
Sajnos a kernel nem tartozik a Linux jl dokumentlt rszei kz, ugyanis a
forrskd fejlesztse ltalban gyorsabb, minthogy a dokumentci kvetni
tudn. Szerencsre az utbbi vekben jelents fejlds tapasztalhat ezen a
tren is: a kernelfejleszt'k egyre inkbb dokumentljk a munkjukat.
91
A 2 .6.0-s kernelverzi 2 003. december 17-n jelent meg. A 2 .6.X-es kernelek korszaka
egszen 2 011. jlius 2 1-ig tartott, amikor Linus Torvalds bejelentette a 3.0-s verzit a Li-
nux-kernel 2 0. szletsnapja alkalmbl.
34 0
7.2. A kernel- s az alkalmazsfejleszts eltrsei
7.2. A kernel- s az alkalmazsfejleszts
eltrsei
Elszr rszleteznnk kell a kernel s az alkalmazsok fejlesztse kzti k-
lnbsgeket. A ksbbi fejezetekben elssorban kernelmodulok fejlesztst
trgyaljuk, m nincs klnbsg a modulknt elksztett s a kernelbe kzvet-
lenl belefordtott kdok kztt a megktsek tekintetben.
Elszr is a kernelrszek ksztsnl lehetleg felejtsnk el ms nyelve-
ket, s dolgozzunk C-ben, esetleg assemblyben.
ltalban az alkalmazsok egy feladaton dolgoznak az indtstl a folya-
mat vgig. Ezrt ezeknek egyetlen belpsi pontjuk van, C nyelv programok
esetn tipikusan a main fggvny. A kernelmodulok letciklusa sokkal jobban
hasonlt a nem statikus programknyvtrakhoz: a programknyvtr rendel-
kezsre llst regisztrlssal adjuk a rendszer tudtra, ettl kezdve arra
vr, hogy egy program betltse s meghvja a szolgltatsait. Hasonlkppen a
kernelmodulok elszr csak regisztrldnak, hogy ksbb feladatokat teljest-
hessenek, s ezzel az inicializl fggvnyk mr vget is r. A modul msik
belpsi pontja a tisztogatfggvny, amely a modul eltvoltsakor aktivizl-
dik, pontosabban kzvetlenl eltte. A modul szolgltatsait kttt prototpus
fggvnyek valstjk meg, amelyeket a programok a kernel kzvettsvel
pldul az llomnyabsztrakcis interfszen keresztl hasznlhatnak. Szek-
vencilisan lefut kdot csak gy implementlhatunk, ha kernelszlat ind-
tunk (lsd a 7.17. Vrakozs alfejezetet).
A programok fejlesztsekor gyakran hasznlunk olyan fggvnyeket,
amelyek fejleszti knyvtrakban vannak. Ilyenkor maga a program nem tar-
talmazza a fggvnyt, hanem a fordtsi fzis utn a linker vagy a betlt-
program a linkelsi fzisban oldja fel ezeket a kls hivatkozsokat. Ilyen
pldul a printf() fggvny, amely a libc knyvtrban tallhat. Ezzel szem-
ben a modulok csak a kernellel linkeldnek, ezrt csak olyan fggvnyeket
hasznlhatnak, amelyek a kernelben (belertve ms modulokat) mr ltez-
nek. Termszetesen a modulok fejlesztsben nem hasznlhatunk semmilyen
libc fggvnyt, hiszen az egy jval magasabb szint, felhasznli zemmd-
ban hasznlatos fggvnyknyvtr. A kernel ltal rendelkezsre bocstott
fggvnyeket a / proc /kallsyms virtulisszveg-llomnyban tudjuk megnz-
ni. Ez csak az ppen aktulis fggvnylistt jelenti meg, amely a modulok
betltsvel s eltvoltsval bvlhet, illetve cskkenhet.
Mivel nem hasznlhatunk fejleszti knyvtrakat, gy a hagyomnyos
headerllomnyok sem szerepelhetnek a kdunkban. Helyettk a kernelforrs
include alknyvtrban tallhat llomnyok kerlnek bele, s errl a kernel-
forrs Makefile-ja gondoskodik azzal, hogy a megfelel elrsi utakat adja meg
a fordtnak. Ebben a knyvtrban tallunk egy linux s egy asm knyvtrat,
amelyek az ltalunk hasznlhat headerllomnyokat tartalmazzk.
341
7. fejezet: Fejleszts a Linux-kernelben
A kernelrszek kdjait s adatait ltalban a fizikai memriban trol-
juk, vagyis nem kerlhetnek ki egy lapcsere folytn a merevlemezre. Hogy
megrtsk ennek az okt, nzznk meg egy pldt. Tegyk fel, hogy a kernel
adatait is olyan virtulismemria-terleten tartjuk, mint az alkalmazsokit.
Ebben az esetben elfordulhat, hogy egyes lapok kikerlnek a lapcsere-
partcira, ha kevs a hely a fizikai memriban. Ha ppen a lapcsere algo-
ritmuskdja vagy adatai kerlnnek ki: tbbet nem lehetne visszatlteni sem
ezt a lapot, sem ms lapokat a rendszerbe.
Termszetesen a fizikai memria vges, ezrt ne szabad elpazarolni. Nagy
mennyisg adathoz kernelfejlesztskor is lehetsgnk van arra, hogy virtu-
lis memrit is allokljunk. Ezekre a terletekre csak adatokat helyezhetnk
el, s szmolnunk kell az esetleges lapcsere okozta lassabb hozzfrssel.
Lebegpontos szmtsokat ne hasznljunk. Ha mgis szksges lenne,
akkor neknk kell gondoskodnunk az FPU llapotnak lementsrl s visz-
szalltsrl.
Az utols nagy eltrs a hibk lekezelsnl tapasztalhat. Amg a prog-
ramok fejlesztsekor egy hibs memria, illetve I/O mvelet (segmentation
fault) a rendszer szempontjbl nem veszlyes, s knnyen kiszrhet, a ker-
nelmodulban elkvetett hasonl hiba komoly kvetkezmnyekkel, akr mg a
rendszer sszeomlsval is jrhat. Ugyanakkor a kernel fejldsvel a hiba-
kezel metdusok is fejldtek, gy manapsg az esetek tbbsgben a rendszer
mg mkdkpes marad, s olyan hibajelzst (a jl ismert Oops zenet) k-
pes produklni, amely nagyban segti a fejlesztst. Ugyanakkor egy hiba utn
a rendszer instabil llapotba kerlhet, ezrt clszer jraindtani. Ellenkez
esetben furcsa, nem determinisztikus hibajelensgeket tapasztalhatunk,
amelyek lehetetlenn tehetik a hiba feldertst.
A hibakeress is nehzkesebb: az alkalmazsoknl hasznlt mdszerek
nem eredmnyesek, vagy csak komolyabb elkszletek utn, s akkor is csak
megktsekkel. m ms mdszerek is rendelkezsnkre llnak, br ezek sok-
szor nem nyjtanak olyan segtsget, mint amit az alkalmazsoknl megszok-
hattunk. A tovbbiakban bemutatunk majd nhny jl hasznlhat mdszert.
7.2.1. Felhasznli zemmd kernelzemmd
A felhasznli alkalmazsok sajt virtulis cmteret kapnak indtskor: eb-
ben a cmtrben tudnak dolgozni a futsuk sorn. Ugyanakkor az egyms
mellett fut prhuzamos folyamatok el vannak vlasztva egymstl. Egyms
terleteihez nem frhetnek hozz, csak szablyozott csatornkon rintkez-
hetnek (lsd a korbbi fejezetekben).
A folyamat virtulis cmtartomnya 32 bites rendszerben 2
32
, vagyis 4 GB.
Ezt a Linux rendszer kt rszre osztja. Az als 3 GB a felhasznli cmtarto-
mny, mg a fels 1 GB a kernel szmra fenntartott tartomny. A mretek
fggetlenek attl, hogy a szmtgp valjban mennyi fizikai memrit tar-
talmaz, mert itt csak virtulis cmterletekrl van sz.
342
7.3. Kernelmodulok
A mai processzorok tbb privilgiumszint hasznlatt teszik lehetv.
Ezek azt szablyozzk, hogy a folyamatok mihez frhetnek hozz. Kzlk a
Linux kt szintet hasznl: a felhasznli zemmdot s a kernelzemmdot.
A f klnbsg a kt zemmd kztt az, hogy felhasznli zemmdban a fo-
lyamatok a fels kernelcmtrhez nem frhetnek hozz, nem olvashatjk, r-
hatjk vagy futtathatjk a rajta lv kdot.
Az tjrst a felhasznli zemmd s a kernelzemmd kztt a rend-
szerhvsok nyjtjk. A rendszerhvsok meghvsval tudnak a folyamatok
olyan mveleteket vgrehajtani, amelyek a sajt virtulis birodalmukon kvl
tallhat rszekre hatssal vannak. Ilyenkor a rendszer ellenrzi a jogosult-
sgaikat, s vgrehajtja a mveletet.
Azok a mveletek, amelyek kernelmdban futnak, pldul a rendszerh-
vsok implementcija vagy a ks'bb trgyaland kernelszlak, hozzfrhet-
nek a kernel cmtartomnynak az egszhez. Ez azt jelenti, hogy semmilyen
korltozs nem vonatkozik rjuk, brmilyen mveletet vgrehajthatnak.
Vagyis elmondhatjuk, hogy a hibs vagy a rosszindulat kdot tartalmaz
modulokkal szemben a kernel vdtelen, ezrt a rendszer adminisztrtorra,
illetve a rendszerfejlesztkre hrul az a feladat, hogy ezektl a veszlyektl a
rendszert megvdjk.
7.3. Kernelmodulok
A Linux-kernel eredetileg monolitikus, vagyis egyetlen nagy program, amely
tartalmaz minden olyan funkcit s bels adatstruktrt, amely az opercis
rendszerhez tartozik (lsd a 2.1. A Linux-kernel felptse alfejezetben). Az al-
ternatva a mikrokernel lenne, amely minden funkcionlis elemet kln egys-
gekben tartalmaz, s az egyes rszek kztt jl meghatrozott kommunikci
zajlik. gy minden j komponens vagy funkci hozzadsa a kernelhez na-
gyon idignyes feladat lenne. A korai kernelverziknl, ha egy j eszkzt tet-
tnk a gpbe, a kernelt tnylegesen jra kellett konfigurlni s fordtani.
A Linux gy orvosolta a monolitikus kernel rugalmatlansgt, hogy az
1.2 -es verzi ta mr teljes tmogatst nyjt a futs kzben betlthet ker-
nelmodulok hasznlathoz. A kernelmodulok olyan trgykd binrisok,
amelyeket a rendszer indtsa utn brmikor betlthetnk, s dinamikusan
hozzlinkelhetnk a kernelhez. Majd amikor mr nincs r szksgnk, le-
kapcsoljuk (unlink), s eltvolthatjuk a modult memribl. Ez lehetv te-
szi, hogy az opercis rendszer egyes komponenseit dinamikusan betltsk s
eltvoltsuk, attl fggen, hogy szksgnk van-e rjuk, vagy sem. A legtbb
eszkzvezrlt modulknt valstottk meg, s ez a megolds javasolhat a
sajt eszkzvezrlink elksztsnl is. Ez a megkzelts magt a fejlesztst
is nagyban knnyti s gyorstja.
343
7. fejezet: Fejleszts a Linux-kernelben
Feladat A plda-eszkzvezrl feladata az lesz, hogy olvasskor kirja a Hello!" szveget,
rskor pedig a konzolra kirja a specilis llomnyba foglaltakat.
7.3.1. Hello modul vilg
Kezdsknt nzzk meg, hogyan alkothatjuk meg a legegyszerbb kernelmo-
dult. Ezt tekinthetjk majd vzknt is a ksbbi munknkhoz. Ez a kd a
kernel 2 .6.x-es verzija alatt fordul s mkdik:
/* hellomodule.c -Egyszeru kernel modul. */
#include <linux/module.h>
#include <linux/kernel.h>
int ni t_module(void)
{
printk("Hello modul vilag! \n");
return 0;
void cl eanup_module(void)
printk("viszlat modul vilag! \n");
MODULE_LICENSE("GPL");
A modul a lehet legegyszerbb. Minden modul minimum kt fggvnnyel
rendelkezik. Az egyik a modul betltsekor (init_module()), a msik az eltvo-
ltskor (cleanup_module()) hajtdik vgre. Ezek formja a 2 .6-os kernel ese-
tn a pldban lthat. A gyakorlatban azonban nem a fggvnyek beptett
neveit hasznljuk, hanem a sajt nevekkel ltrehozott fggvnyeket regiszt-
rljuk be, ez ugyanis flexibilisebb megolds. Ezzel a kibvtssel a kvetkez
kdig jutunk:
/* hellomodule.c - Egyszeru kernel modul. */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int ini t hello_init(void)
{
printk("Hello modul vi lag! \n");
return 0;
}
344
7.3. Kernelmodulok
static void exit hello_exit(void)
{
printk("viszlat modul vilag!\n");
module_init(hello_init);
module_exit(hello_exit);
mODuLE_DEsCRIPTIoN("Hello module");
MODULE_LICENSE("GPL");
A modul betltsekor s eltvoltsakor meghvand fggvnyeket a modu-
le_init() s a module_exit() makrkkal jelljk ki. Megfigyelhetnk mg egy kis
eltrst a fggvnyek alakjban. Nevezetesen az _init s az _exit makrkat.
Ezeket a makrkat arra hasznljuk, hogy megjelljk a kernel szmra az
inicializcis s az eltvolt fggvnyeket. A kernel a makrk ltal nyjtott
informcit felhasznlhatja a memriafelhasznls optimalizlsra. Jelen-
leg ezek az optimalizcis algoritmusok csak akkor lpnek mkdsbe, ha a
kernelmodult belefordtjuk a kernelbe.
Ha teht a kernelbe ptettk a modult, az _init makr hatsra az ini-
cializcis folyamat utn az init fggvny megsznik, s a hozztartoz me-
mria felszabadul. Az _exit makr hatsra a tisztogatfggvnyt figyelmen
kvl hagyja a rendszer a fordts sorn, hiszen a kernel kitltdsekor nincs
szksg felszabadtsra. Ha a modult nem ptjk a kernelbe, ezek a fggv-
nyek norml inicializl s tisztogatfggvnyekk vlnak, s a makrknak
nincs klnsebb hatsuk. Vagyis az _init s az _exit makrk hasznlata
azrt clszer, hogy egy kdban mindkt esetet kezelhessk.
A pldaprogramban a regisztrlt fggvnyeink kirsokat vgeznek.
Az zenetek kirsra a printk() fggvnyt hasznljuk, amely hasonlt a printf()
fggvnyhez, de a Linux-kernelben van definilva. A modul betltsekor a Li-
nux-kernelhez linkeldik, gy a printk() fggvny is hasznlhatv vlik.
(A printf() pldul nem hasznlhat, hiszen a felhasznli knyvtrban van
definilva.)
A modul vgn makrkkal megadhatjuk a modul ksztjt, lerst s a
licencinformciit. Jllehet ezeket az adatokat nem ktelez megadni, lega-
lbb a licencet clszer belltanunk Ha nem GPL licencet lltunk be, akkor
a modul betltsekor figyelmeztetst kapunk, illetve egyes, a kernelben lv
fggvnyek elrhetetlenek lesznek a modulunk szmra.
345
7. fejezet: Fejleszts a Linux-kernelben
7.3.2. Fordts
Miutn elkszltnk a kernelmodulunk forrskdjval, a kvetkez lps a
fordts. A fordtshoz mindenkppen szksg van a hasznlt kernel forrs-
ra. Ez nemcsak azt jelenti, hogy le kell tltennk egy kernelforrst, amely
ugyanolyan verzij, mint amit ppen hasznlunk, hanem hogy ha vannak
mdostsok (patch) a kernelnkben, akkor azoknak a forrsban is meg kell
lennik, tovbb a konfigurcinak is egyeznie kell.
Szerencsre ez tbbnyire nem jelent komoly problmt, hiszen a disztri-
bcik tbbsge minden kernelverzihoz tartalmazza a forrscsomagot is (ti-
pikusan: linux-source, linux-kernel-source) vagy pedig egy kernelfejleszti
csomagot (tipikusan: linux-devel, linux-kernel-devel, linux-headers). Utbbi
ltalban nem teljes forrscsomag, hanem csak azok a rszei vannak benne,
amelyek a modulok fordtshoz szksgesek. Ez termszetesen lnyegesen
kisebb, m szmunkra teljes rtk.
A modulunk fordtshoz felhasznljuk a kernelforrs Makefile-jait. Ezrt
a telepts utn pontosan tudnunk kell, hogy melyik knyvtrban helyezke-
dik el a f Makefile. Ezt a korbban emltett s felteleptett forrscsomagok
llomnylistjnak a megtekintsvel lehet kiderteni. A forrs gykrknyv-
trra van szksgnk (tipikusan: /usr/src/ alatt egy knyvtr, amely a ne-
vben a kernelverzit is tartalmazza).
A fordtsi metdus a kvetkez:
1. A modul knyvtrban ltre kell hoznunk egy Makefile nev llomnyt.
Ebben az llomnyban a kvetkez sor bersval jelezhetjk, hogy
a hellomodulel.c llomnyt szeretnnk felvenni a fordtsi listba (a
trgykd llomny nevt kell megadni, vagyis a .0" kiterjesztst:
olaj -rt1 bel
-
1 ~91 e .9
2 . Ezt kveten meg kell hvnunk a make parancsot gy, hogy a kernel-
forrs f'knyvtrban lv Makefile llomnyt hasznlja. Ugyanak-
kor t kell adnunk a SUBDIRS paramterrel a modulforrsunk
knyvtrt. Ezt kveten a modules" clt is meg kell adni a fordts-
hoz, amellyel jelezzk, hogy kernelmodulokat szeretnnk fordtani.
Ezzel a parancssor a kvetkez lesz:
mak e-C<k erne'k ny v t r>suBDIRs=<modulforr sk ny v t r>modules
A fordts sorn ltrejn egy trgykd llomny .0" kiterjesztssel. Ezt ki-
egsztve adminisztratv informcikkal ltrejn a .ko" kiterjeszts llo-
mny is, amely mr a ksz kernelmodul.
346
7.3. Kernelmodulok
7.3.3. A modulok betltse s eltvoltsa
Miutn elkszlt a kernelmodulunk, a kvetkez problma: hogyan tltsk
be? ltalnosan elmondhat, hogy kernelmodult csak rendszergazdai jogo-
sultggal tlthetnk be. Mivel a modul a kernel teljes rtk rsze lesz, ezrt
szinte teljhatalommal rendelkezik, korltozni csak nagyon kis mrtkben le-
het. Nyilvnval, hogy ha egy felhasznl a sajt moduljt ilyen mdon be-
tlthetn, akkor az egsz vdelmi rendszer teljesen hatstalan lenne.
A kvetkezkben ttekintjk a betlts folyamatt.
7.3.3.1. insmod/rmmod
A lefordtott modult a legegyszerbben az albbi paranccsal tlthetjk be:
1 nsinod hel 1 omodul e . ko
Az insmod program hozzlinkeli a modult a kernelhez, s vgrehajtdik az
inicializl metdusunk. A metdus kirja az dvzlszveget a konzolra.
92
A betlttt modulokat az lsmod paranccsal ki is listzhatjuk. Ez az aktu-
lisan betlttt modulokrl s a kztk fennll kapcsolatrl is mutat inform-
cikat.
A modul eltvoltsra a kvetkez parancs szolgl:
rniMod bel 1 omodk.il e
Ilyenkor meghvdik a modulunk tisztogatfggvnye, amely kirja a konzolra
a bcsszveget. Majd lekapcsoldik a modul, s eltvoltdik a memribl.
7.3.3.2. modprobe
A msik lehetsg a modulok betltsre a modprobe program hasznlata.
Ehhez azonban elszr el kell helyeznnk a modulllomnyt a modulok hiva-
talos trolknyvtrba:
Ill/modki~kempivert~
Pontosabban az ebben a knyvtrban lv kernel vagy update knyvtrak va-
lamelyikbe kell helyeznnk, egy, a modul fajtjtl fgg alknyvtrba. Ez
utbbi csak ajnls, a mkds szempontjbl nem rdekes.
92
Ha valamilyen terminlprogramot hasznlunk, amely tipikus grafikus fellet esetben,
akkor azon a konzolzenetek nem jelennek meg. Ilyenkor a dmesg paranccsal listzhat-
juk ki a konzolzeneteket.
34 7
7. fejezet: Fejleszts a Linux-kernelben
Ezt kveten le kell futtatni a depmod a parancsot. Ez a parancs rekur-
zvan felderti a knyvtrak tartalmt. sszegyjti a tallt modulok listjt,
tovbb feltrkpezi a modulok kztti fggsgeket.
93
Ezutn a modprobe
mr kpes betlteni s eltvoltani a modulokat.
Mivel a depmod parancs egy fggsgi listt llt el a modulokhoz, gy a
modprobe kpes r, hogy ne csak a megnevezett modult tltse be, hanem azo-
kat is, amelyektl fgg, illetve amelyeknek a szolgltatsaira pt.
A modprobe konfigurcis llomnya, illetve knyvtra a kvetkez:
/etc/modprobe.conf
/etc/modprobe.d/
A konfigurcis llomnyban az albbi parancsokat (7.1. tblzat) hasznl-
hatjuk:
7.1. tblzat. A modprobe belltsai
Parancs Jelents
Alias Bellthatunk egy msk nevet a modulnak, illetve leggyakrabban spe-
cifikus modulokat rendelnk az eszkznevekhez, hogy azok automati-
kusan betltdhessenek.
Options Paramterezst adhatunk meg a modul betltshez.
A modul betltse helyett a megadott komplex parancssort hajtja vgre.
Remove Lsd az installt, csak eltvoltsra hasznljuk.
Include
Egy llomnyt vagy egy egsz knyvtr tartalmt beilleszthetjk a kon-
figurcis llomnyba. Ezltal modulrisan pthetjk fel az llomnyt,
amely egyszersti az automatikus konfigurcimdostst.
Blatklist A megadott modulokba beptett alias belltsokat figyelmen kvl
hagyja a rendszer. (tkzsek, illetve egyes modulok automatikus be-
tltse ellen hasznljuk.)
7.3.4. Egymsra pl modulok
Tallkozhatunk olyan esettel, amikor a modulok egymsra plnek. Ilyenkor
az egyik modul valamilyen olyan szolgltatst valst meg, amelyet ms mo-
dulok hasznlnak. Ehhez a szolgltatst nyjt modulok szimblumokat,
fggvnyeket, esetleg vltozkat exportlnak, amelyek ms modulok ltal
meghvhatk.
93
A fggsgeket a ko" llomny adminisztratv meziben tallhat informcik alapjn
hatrozza meg.
3 48
7.3 .Kernelmodulok
Betltskor termszetesen gondoskodnunk kell a fggsgekrl, vagyis a
szolgltatst nyjt modult kell betltennk elszr, majd az azt felhasznlt.
m a modprobe ezt megoldja helyettnk.
Ha egy modulbl szimblumokat akarunk exportlni, akkor definilnunk
kell benne az EXPORT SYMTAB makrt. Ezt kveten az exportland
fggvnyeket az EXPORT SYMBOLO makr segtsgvel kell megadnunk.
A modul, amely elrhetv teszi a hello() fggvnyt a tbbiek szmra a
kvetkezkppen nz ki:
/*hellomodulea.c-aszolgaltatastny uj tomodul*/
#ifndefEXP ORT_SYMTAB
#defineEXP ORT_SYMTAB
#endif
#include<linux/module.h>
#includelinux/in t.h>
char*hello(v oid)
{
return"Hello!";
}
EXP ORT_SYMBOL(hel1 o) ;
staticint_ nithelloA_ n t(v oid)
printk ("ModuleAstart!\n");
return0;
1
staticv oid exithelloA_exit(v oid)
{
printk ("moduleAend!\n");
}
module_init(helloAj nit);
module_exit(helloA_ex t);
MODULE_OESCRIP TION("HellomoduleA");
MODULE_LICENSE("GP L");
Ahhoz, hogy a tbbi modulban hasznlhassuk a fggvnyt, ltre kell hoznunk
egy header llomnyt:
/*hellomodulea.h-azexportaltfuggv eny */
char*hello(v oid);
3 49
7. fejezet: Fejleszts a Linux-kernelben
A header llomny hasznlatval a fggvnyt felhasznlhatjuk egy msik
modulban:
/*hellomoduleb.c-aszolcialtatasthasznalomodul*/
#include<linux/module.h>
#include<linux/init.h>
#include"hellomodulea.h"
static nt_ i nithelloB_init(v oid)
{
printk("modul e S start! \n");
printk("%s\n", hello());
return 0;
1
1~
staticv oid ex thelloB_exit(v oid)
{
pr ntk ("Module e end!\n");
}
module_init(helloB_in t);
module_exit(helloB_exit);
"1~
MODULE_DESCRIP TION("Hellomodule8");
MODULE_LICENSE("GP I");
Fordtsuk le mindkt modult, ekkor elszr az A modult, utna a B modult
betltve lthatjuk, hogy a B modul tnylegesen hasznlja az A modul expor-
tlt fggvnyt.
A fggvnyek exportlsakor gondolnunk kell arra, hogy mkds kzben
a modulunk a kernel teljes rtk rsze lesz, az exportlt fggvnynk/vlto-
znk pedig egy globlis szimblum. Azt pedig az alkalmazsok fejlesztsbl
tudjuk, hogy nem lehet kt azonos nev globlis fggvnynk vagy vltoznk.
Ezrt neknk is gy kell megvlasztanunk a neveket, hogy ne lehessen tk-
zs a kernellel vagy ms modulokkal.
Az EXPORT SYMBOLO makrnak ltezik mg egy tovbbi varinsa,
amelynek neve EXPORT SYMBOL_GPLO. A mkdse megegyezik az elz-
vel, m csak GPL licenccel rendelkez modulok szmra elrhet a szimblum.
Ezltal a GPL licences munknkat elfedhetjk a zrt lincenccel rendelkez
modulok ell.
350
7.4. Paramtertads a modulok szmra
7.4. Paramtertads a modulok szmra
A modulok leggyakrabban egy-egy eszkzvezrlt implementlnak. Az esz-
kzvezrlk sokszor rendelkeznek klnfle belltsokkal (pldul az eszkz
I/O cmtartomnya). Ezeket a belltsokat kontansknt bele is drtozhat-
juk" a modulba, eszerint ha valamelyik belltson mdostani szeretnnk,
akkor jra kell fordtanunk a modult. Ez termszetesen nagyon krlmnyes.
A megfelel megolds az lenne, ha a modul betltsekor is megadhatnnk be-
lltsokat. Erre szolgl a Linux-kernel paramtertadsi mechanizmusa.
A belltsokat paramterekben adhatjuk t a modulnak. Ennek mdja
nem egyezik meg a felhasznli alkalmazsoknl megszokott parancssori ar-
gumentumokkal. Definilhatunk olyan globlis vltozkat, amelyeket az
insmod parancs az indtskor kitlt. A vltoz ltrehozsakor megadhatjuk
az inicializcis rtkt, amely egyben a paramter alaprtelmezett rtke is
lesz. Ezt kveten a moduleparamO makr valamelyik vltozatval meg kell
adnunk azt, hogy az adott vltoz modulparamternek szmt, illetve tpustl
fggen egyb belltsokra is szksg van:
module_param(n v ,t pus,sy sfs-j ogok );
module_param_names(n v ,v ltozn v ,t pus,sy sfs-j ogok );
module_param_array (n v ,tipus,m retmutat,sy sfsj ogok );
module_param_array _named(n v ,v ltozn v ,t pus,m retmutat,
sysfs-jogok);
module_param_string(n v ,v ltozn v ,m ret,sy sfs-j ogok );
A nv a vltoz neve, a tpus a vltoz tpusa, a sysfs jogok a paramter-
jogosultsg belltsai a sysfs llomnyrendszeren bell. A mret mutat
a tmb esetben opcionlis paramter. Ha megadunk egy vltozt, illetve an-
nak mutatjt, akkor a rendszer a vltozban eltrolja a tmb elemeinek
szmt a paramter tadskor. A mretparamter a string tpus esetn a
szveg maximlis hosszt adja meg belertve a zr karaktert is. (A string t-
pus paramternl a nv ismtldse nem nyomdahiba, hanem implement-
cis furcsasg.) A stringparamter msik megads mdja, ha tpusnak charp
rtket adunk meg, amely karaktermutatt jelent. Ekkor azonban nem kell
megadnunk a mretet:
module_param(n v ,charp,sy sfs-j ogok );1.1.111~1~L
A paramterek lerst is clszer megadnunk a modulban a MODULE_
PARM DESCO makr hasznlatval. Erre azrt van szksg, hogy a felhasz-
nlk a modulbl megtudhassk a paramterek jelentst. A makr formja a
kvetkez:
MODULE_P ARM_DESC(n V,le r s);
351
7.fej ezet:Fej leszt saLinux-k ernelben
Nzznk egy egyszer pldt a paramterek hasznlatra:
/*helloparam.c-Egy szerupeldaabetoltesiparameterek
k ezelesere.*/
#include<linux/module.h>
#include<linux/moduleparam.h>
#include<linux/k ernel.h>
#include<linux/ nit.h>
/"Letrehozzuk aparameterek nek megfeleloglobalisv altozok at.*/
staticcharparaml[16]="hello";
staticintparam2 =5;
staticintparam3 [2 ]={ 1,2 } ;
/*Mak rok k almegadj uk ,hogy parameterk entv arj uk ,eshogy mily en
tipussal.*/
module_param_string(paraml,paraml,16,0644);
MODULE_P ARM_DESC(paraml,"Szov egesparameter");
module_param(param2 ,int,0644);
MODULE_P ARM_DESC(param2 ,"Szamparameter");
module_param_array (param3 ,int,NULL,0644);
moDuLE_P ARm_0EsC(param3 ,"Szamtombparameter");
staticint inithello_init(v oid)
printk ("paraml:%s\n",paraml);
printk ("param2 :%d\n",param2 );
printk ("param3 ;%d,%d\n",param3 [0],param3 [1]);
return0;
}
staticv oid_exithello_exit(v oid)
printk ("paraml:%s\n",paraml);
printk ("param2 :%d\n",param2 );
printk ("param3 :%d,%d\n",param3 [0],param3 [1]);
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIP TION("Helloprof");
MODULE_LICENSE("GP L");
A lefordtott modul paramtereit s a lersokat a modinfo parancs segtsg-
vel nzhetjk meg:
m o d i n f a h o l l o p a r a m , 3 5 0
3 52
7.5. Karakteres eszkzvezrl
A paramtereket az nsmod parancs hasznlatakor llthatjuk be. Nem szk-
sges minden paramtert megadnunk. Amelyiket nem adjuk meg, annak az
rtke az lesz, amellyel a C kdban inicializltuk az adott statikus vltozt:
Ha a modprobe parancsot hasznljuk a modul betltsre, akkor a mod-
probe.conf llomnyban kell megadnunk a paramtereket.
Ha a sysfs jogosultsgok belltsnl adtunk olvassi vagy rsi jogosult-
sgot a paramterekre, akkor utlag is kiolvashatjuk vagy mdosthatjuk az
rtkket. Ehhez a /sys/module/<modul nv>/parameters knyvtrban kell
krlnznnk. Itt minden egyes paramterhez tallhatunk egy virtulis l-
lomnyt. Ezeket olvashatjuk s rhatjuk.
Termszetesen utlagos mdostsok esetn szmolnunk kell az esetleges
konkurenciaproblmkkal Erre pldaknt nzzk meg a kvetkez esetet. Egy
tbbprocesszoros gpen kt alkalmazst futtatunk prhuzamosan. Az egyik al-
kalmazs hasznlja a kernel modulszolgltatst, mg a msik mdostja
a kernel modulparamtert a sysfs llomnyrendszeren keresztl. Ha a para-
mter sszetett (szveg, tmb), akkor tbb gpi mvelettel trtnik az rsa,
illetve az olvassa. Vagyis a kt alkalmazs ltal kivltott paramterkezelsi
folyamatok tlapoldhatnak, gy kritikus versenyhelyzetet eredmnyezhetnek.
7.5. Karakteres eszkzvezrl
Ebben a fejezetben egy karaktertpus eszkzvezrl moduljt ksztjk el.
Azrt ezt a tpust, mert ltalban ez illeszkedik az egyszerbb hardvereszk-
zkhz, illetve ez a legegyszerbben rthet eszkzvezrl-fajta.
A Unix rendszerek az eszkzket a idei) knyvtrban tallhat specilis
llomnyokknt teszik elrhetv a felhasznlk szmra, illetve a felhaszn-
li mdban fut programok is lllomnyokknt hasznljk ket. Ezrt esz-
kzvezrl ltrehozsakor az az els feladatunk, hogy hardvereszkzeink
funkciit llomnykezelsre kpezzk le: megnyits, rs, olvass, bezrs.
Az eszkzvezrl modulnak az llomnykezelssel kapcsolatos funkcik te-
szik ki az egyik rszt. A msik rszk a modulkezelshez tartoz inicializl s
tisztogatfggvnyek, amelyeket az elz fejezetben lttunk. Egy eszkzvezrl
esetben ezekben a fggvnyekben regisztrljuk be a kernel nyilvntartsba
az eszkznket, illetve tvoltjuk el a bejegyzst.
353
7. fejezet: Fejleszts a Linux-kernelben
7.5.1. F- s mellkazonost (major s minor number)
Mint mr sz volt rla, az eszkznk elrshez szksg van specilis llom-
nyokra, amelyeket az mknod paranccsal vagy rendszerhvssal hozhatunk lt-
re. A korbbi fejezetekben lthattuk, hogy a ltrehozsukhoz szksges a tpus,
valamint egy f- s egy mellkazonost (major s minor number) megadsa.
A fazonost azonostja a specilis llomnyhoz tartoz modult. A kernel
ennek alapjn vlasztja ki, hogy melyik eszkzvezrl modulhoz forduljon, ha
egy program ezt az llomnyt nyitja meg.
A mellkazonostt az eszkzvezrl program hasznlhatja, amennyiben
tbb llomnyinterfszt is kezel. Ezt neknk kell kezelnnk a modulon bell, a
kernel nem foglalkozik vele." A soros interfsz fazonostja pldul 4 , azon be-
ll a mellkazonostk hatrozzk meg a konkrt eszkzk interfszeit. Az els
soros port (/dev/ttySO) fazonostja pldul 4 , mellkazonostja 64 .
95
Egy j eszkzvezrl beregisztrlsa lnyegben azt jelenti, hogy hozzren-
deljk egy fazonosthoz a virtulis llomnykezelst megvalst fggvnyeit.
A karakteres eszkzvezrl regisztrlfggvnynek alakja a kvetkez:
ntregister_chrdev (unsignedintmaj or,constchar*name,
structfile_operations*fops);
A visszatrsi rtk negatv szm esetn hibt mutat. A major argumentum
a fazonostt jelenti, a name argumentum annak az eszkznek a neve, amely
a /proc/devices listban jelenik meg. A fops paramter egy olyan struktrra
mutat, amely az egyes llomnykezelsi funkcikat megvalst fggvnyek
mutatit tartalmazza, pldul azt, hogy a specilis llomnyba val rskor
melyik fggvny hvdjon meg.
Lehetsgnk van arra, hogy a regisztrls sorn ne mi vlasszuk meg a
fazonostt kockztatva ezzel az tkzst egy msik meghajtval , hanem
a rendszerre bzzuk ezt a feladatot Ekkor a kernel automatikusan kivlaszt
egy azonostt, s a fggvny visszatrsi rtkben adja vissza.
Miutn az eszkzvezrlnket regisztrltuk a kernel knyvelsbe, minden
olyan mvelet esetn, amelyet az ltalunk regisztrlttal megegyez fazonos-
tj specilis llomnyokkal vgznk, a kernel meghvja a mvelethez meg-
adott fggvnyt.
A modulunk eltvoltsakor termszetesen el kell tvoltanunk ezt a bejegy-
zst, s el kell eresztennk a fazonostt. Erre szolgl a kvetkez fggvny:
~iit~idgrtia~d, int itialr, ~t 4 ~01
94
Hangslyoznunk kell, hogy a kernel kizrlag a fazonostt hasznlja a modul azonost-
sra. A modul neve, megjelense az llomnyrendszerben kizrlag a knnyebb kezelhet-
sget segti el a felhasznlk szmra. A blokkos s karakteres eszkzket teljesen kln
kezeli a kernel, ezrt egy blokkos s egy karakteres eszkz azonostja ugyanaz is lehet.
" Az eddig kiosztott azonostk a The Linux Assigned Names And Numbers Authority
(http: / / www.lanana.org) oldaln tallhatk.
3 54
7.5. Karakteres eszkzvezrl
Az els paramter a fazonost, a msodik az eszkzvezrl neve. Utbbi
csak biztonsgi okokbl szerepel. A kernel sszehasonltja a korbban regiszt-
rlttal, s eltrs esetn nem hajtja vgre a regisztrci eltvoltst.
Ha netn a modult a regisztrls trlse nlkl tvoltannk el, az ksbb
komoly kellemetlensgeket okozhat. Minden olyan mvelet, amely erre az esz-
kzvezrlre hivatkozik a mr emltett Oops hibazenet vltja ki a kernelbl.
7.5.2. Az eszkzllomnyok dinamikus ltrehozsa
Tradicionlisan a /dev knyvtr tele volt statikusan ltrehozott eszkzllo-
mnyokkal. Minden a Linux ltal tmogatott eszkzllomnynak szerepelnie
kellett benne, htha az adott meghajtt hasznlni szeretnnk. Ez jelents s
felesleges helyfoglalst jelentett. Ezrt clszernek ltszott az eszkzllom-
nyok dinamikus ltrehozsa.
Az els prblkozs a devfs llomnyrendszer tmogatsa volt. A kernel
ezen az llomnyrendszeren keresztl virtulis llomnyokkal reprezentlta
az eszkzllomnyokat, amikor erre szksg volt. A modern kernelvltozatok
ezt a mechanizmust manapsg mr nem tmogatjk.
A jelenleg is hasznlatos megolds az udev felhasznli mdban fut al-
kalmazsra pt. A folyamatosan fut udev daemon fogadja a kernel hotplug
zeneteit, s ezek alapjn dinamikusan hoz ltre s trl le eszkzllomnyo-
kat egy virtulis, memriban trolt llomnyrendszeren.
A hotplug zenetek generlshoz az eszkznknek implementlnia kell
a 2 .6-os kernelekkel bemutatkoz eszkzmodellt (device model). A Linux-esz-
kzmodell lnyegben egy olyan komplex adatstruktra, amely tartalmazza
azt, hogy az eszkz milyen tpusosztlyba tartozik, melyik buszra csatlakozik,
s milyen specilis attribtumokkal rendelkezik. Ha az eszkzkezelkben el-
vgezzk ezeket a regisztrcikat, akkor az eszkzvezrlnk, illetve az eszk-
znk megjelenik a sysfs llomnyrendszerben is a hierarchinak megfelel
helyen. Emellett lehetv vlik az udev rendszer hasznlata.
Ha clunk mindssze az eszkzllomnyok automatikus ltrehozsa, ak-
kor elegend a device_create() fggvnyt hasznlnunk, amely az udev szm-
ra kiadja a megfelel jelzst. A fggvny alakja a kvetkez:
structdev ice*dev ice_create(structclass*oszt ly ,
structdev ice*szl,dev _teszk z,constchar*n v ,...);
Az osztly egy mutat arra az osztlyra, amelyhez az eszkzt rendeljk. Lt-
rehozsa a class_create() fggvnnyel lehetsges. A szl egy mutat a szl-
eszkzre, ha ltezik ilyen. Az eszkz a f- s mellkazonostkat tartalmaz
argumentum. Ellltsa az MKDEVQ makrval lehetsges. A nv s az ezt
kvet argumentumok az eszkz llomnynevnek sszelltst teszik lehe-
tv a printf() fggvnyhez hasonl mdon.
355
7. fejezet: Fejleszts a Linux-kernelben
A ltrehozott eszkzt a device_destroy0 fggvnnyel kell megsemmisteni
a modul eltvoltsa eltt. A fggvny alakja a kvetkez:
Void_dev ce_de.stroY(struc.tclass*oszt ly ,dev _teszk z);
A fggvny paramtereinek rtelmezse megegyezik a ltrehozsnl hasznl-
takkal.
Az eszkz ltrehozshoz szksges egy olyan osztly, amelyhez hozzren-
delhetjk. Ezt a class_create0 fggvnnyel hozhatjuk ltre, amelynek alakja a
kvetkez:
struct class* cl ass_create(struct module*modul,constchar*n v );
A modul paramter annak a modulnak a mutatja, amely az eszkzosztlyt
birtokolja. A THIS MODULE makrval adhatjuk meg a modulunkat. A nv
az osztly szveges megnevezse.
Az osztly megszntetst a class_destroy0 fggvnnyel kell elvgeznnk
a tisztogatsnl. A fggvny szintaxisa a kvetkez:
void cl ass_destroy(struct class* osztly);
Nzznk egy pldt az eszkzllomny ltrehozsra:
staticstructclass*hello_class;
hello_class=class_create(THis_MODULE,"hello");
dev ice_create(hello_class,NULL,MKDEV(12 0,0),NULL,"hello");
Az eltvolts:
dev ice_destroy (hello_class,MKDEV(12 0,0));
class_destroy (hello_class);
A kdrszleteket elhelyezve az nit s az exit fggvnyekben az udev automa-
tikusan ltrehozza, illetve letrli a hello" eszkzllomnyt. Ha szeretnnk az
llomny jogosultsgait megadni, akkor ez az udev konfigurcis llomny-
ban lehetsges.
7.5.3. llomnymveletek
Az eszkzvezrlnek az eszkzk elrhetv ttelre, kezelsre az llomnyke-
zelseknl hasznlatos fggvnyeket kell implementlnia. Ezeknek a fggv-
nyeknek a mutatit tartalmazza a file_operations struktra. Olyan mveletekrl
van sz, mint a megnyits, az olvass, az rs, a bezrs stb. A lista tartalmaz-
hat NULL pointereket is, ennek jelentse az, hogy az adott mveletet az eszkz-
vezrl nem tmogatja.
356
7.5. Karakteres eszkzvezrl
A struktra a kernelverzik vltozsakor folyamatosan ntt, s talakult
az jabb elemek felvtelvel. Az ppen aktulis lerst a linux/ fs.h llomny
tartalmazza.
A struktra egyes elemeibl lthat, hogy az adott metdust milyen fgg-
vnnyel lehet lekezelni. Az implementlni kvnt llomnykezel metdusokat a
struktrban megadott paramterekkel s visszatrsi rtkkel kell definilni.
Mivel a struktra az egyes verzikban vltozhat, ezrt az albbi mdon
javasolhat a hasznlata:
96
staticstruct fi 1 e_operations hel 1 o_fops
{
owner
read:
wri te :
open :
rel ease :
1;
THIS_MODULE,
hello_read,
hello_write,
hello_open,
hello_release
Az owner mez megadsval jelezzk, hogy melyik modulhoz ktdik a ler
struktra. A THIS_MODULE makr az aktulis kernel moduller struktr-
jnak mutatjt adja vissza.
7.5.4. Hasznlatszmll
Ha egy alkalmazs hasznlja az eszkzvezrlt, a kernelnek nem szabad addig
eltvoltania a modult, amg az utols alkalmazs is le nem zrja az eszkzvezr-
lhz tartoz llomnyt. Ezt a vdelmet a kernel klasszikus referenciaszmlls-
sal implementlja. Neknk csak annyit kell tennnk, hogy amikor megnyitjk az
eszkznket, akkor nvelnk egy szmllt, amikor pedig lezrjk, akkor csk-
kentjk a szmllt. A kernel nem tvoltja el a modult a memribl, amg en-
nek a szmllnak az rtke nagyobb, mint nulla y'
Ennek a mechanizmusnak a hasznlathoz ksz fggvnyeket nyjt a
rendszer. A szmllt nvelni az albbi fggvnnyel tudjuk:
try _module_get(THIs_mpoutE):
96
Ez a definci egy gcc kiterjesztsre pl, amely lehetv teszi a struktra tagjainak nv
szerinti inicializlst (a nem inicializlt tagokat a gcc nullra inicializlja). A szabv-
nyos megolds a C99-es szabvny gynevezett nv szerinti inicializlsi (designated
initializer) mechanizmust hasznlja. Ilyenkor a pont utn megadjuk az egyes mezk ne-
veit, s expliciten adunk rtket nekik egyenlsgjellel. Azokat a vltozkat, amelyeket
nem sorolunk fel, a fordt nullval inicializlja. Ezt a C-ben is viszonylagosan j szinta-
xist a C++ nem tmogatja. Vagyis ha a tagok nevei el pontot, a kettspont helyett pedig
egyenlsget hasznlunk, akkor hordozhat megoldshoz jutunk.
97
A kernel termszetesen szmon tartja azt is, hogy ha ms modulok is hasznlnak egy
adott modult. Ilyenkor szintn nveli a referenciaszmllt.
357
/*hellodriv er.c- Egy szerudriv eroffsetk ezelessel.
#include<1nux/moduleh>
#include <1 i nux/kernel .h>
#include <linux/fs.h>
#include <asm/uaccess . h>
#include <1 i nux/devi ce .h>
#defineDEVICE_NAME "hello"
staticintmaj or_num=12 0;
#defineCLASS_NAME"helloclass"
staticstructclass*hello_class;
#defineMSG_LEN 7
staticchar*msg="Hello!\n";
7. fejezet: Fejleszts a Linux-kernelben
Ha mr nem hasznljk a modult, akkor cskkentennk kell a szmll rtkt:
module_put(THIS_MODULE);
A rendszer figyeli, s ha a hasznlatszmll rtke nagyobb, mint 0, akkor
nem engedi a modult eltvoltani. Ez ugyanakkor a fejleszts sorn gondot is
jelenthet, mert ha elrontjuk a knyvelst, akkor nem lehet a modult a rend-
szer jraindtsa nlkl eltvoltani. Ezrt a kernelbe belefordthat a kny-
szertett eltvolts lehetsge.
98
7.5.5. Hello vilg" driver
Hogy knnyebben megrtsk, nzzk meg egy pldn az alapmveleteket s
az implementlsuk sorn felmerl problmkat.
A plda-eszkzvezrl feladata az lesz, hogy olvasskor kirja a Hello!"
szveget, rskor pedig a konzolra kirja a specilis llomnyba rtakat:
/*Azirasmuv eletetk ezelorutin.*/
staticssize_thello_write(structfile*pfile,constchar*buf,
size_tcount,loff_t*ppos)
{
/*Akernel memoriabol lefoglaljuk a szukseges teruletet. * /
char*str=k malloc(count+1, GFP _KERNEL);
98
A kernelfordts eltti konfigurls sorn a modulokra vonatkoz belltsoknl kiv-
laszthatjuk a knyszertett modul eltvoltsi lehetsgt. Ksbb a lefordtott kernelt
hasznlva lehetsgnk lesz a modul knyszertett eltvoltsra. Br a rendszer engedi
az eltvoltst, csak szksg esetn hasznljuk.
358
7.5.Karak tereseszk zv ez rl
/*Atmasolj uk afelhasznaloicimteruletrolazadatok atak ernel
cimteruletre.*/
f(!copy _from_user(str,buf,count))
{
/*Lezarj uk egy 0k arak terrel.*/
str[count]=0;
/* Aprintk ()fuggv eny hiv assalk iirj uk .*/
printk (DEVICE_NAME"write:%s\n",str);
/*Felszabaditj uk alefoglaltteruletet.*/
k free(str);
/*v isszaterunk azolv asottbaj tok szamav al.*/
returncount;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
staticssize_thello_read(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
{
//haapoz zicioaszov egv egeremutatak k orv isszaterunk
i f(*ppos>=MSG_LEN)return0;
//Maximumanny ibaj totszolgalunk k i,amily enhosszuaszov eg.
if((*ppos+count)>MSG_LEN)count=MSG_LEN - *ppos;
/*Atmasolj uk azadatotak ernelcimteruletrol,azolv aso
fuggv eny altalk apottbufferbe.*/
if(copy _to_user(buf,msg+*ppos,count))
{
return -EFAULT;
*ppos+=count;
/*V sszaterunk av isszaadottadatmenny iseghosszav al.*/
returncount;
/*Amegny itasmuv eletetlek ezelofuggv eny .*/
staticinthello_open(structinode*inode,structfile*pfile)
t
/*Nov elj uk ahasznalatiszamlalot.*/
try _module_get(THIs_mODULE);
printk (DEVICE_NAME"open.\n");
return0;
359
7. fejezet: Fejleszts a Linux-kernelben
/* Alezarasmuv eletetlek ezelofuggv eny .*/
stat cinthello_close(structinode*inode,structfile*pfile)
{
printk (DEv ICE_NAME"close.\n");
/*Csok k entj uk ahasznalatiszamlalot.*/
module_put(THIS_M0DuLE):
return0;
staticstructfile_operationshello_fops=
owner: THIS_MODULE,
read: hello_read,
write: hello_write,
open: hello_open,
release:hello_close
} :
/*Ak ernelmodulinic al zalasatv egzofuggv eny .
staticint inithello_init(v oid)
intres;
structdev icecerr;
/*Regisztralj uk ak arak tertipusueszk ozt.'/
res=register_chrdev (maj or_num,DEVICE_NAME,&hello_fops);
i f(res<O)
{
printk (DEv ICE_NAME"afoazonosito:%dnemelerheto\n",
maj or_num):
returnres;
}
if(maj or_num==0)maj or_num=res;
/*Azudev sz m raj elz s,hogy hozzal treaz
eszk z llom ny t.*/
helloclass=class_create(TNIs_m0DuLE,CLASS_NAME);
err=dev ice_create(hello_class,NULL,MKDEV(maj or_num,0),
NULL,DEVICE_NAME);
printk (DEv ICE_NAmE"betoltv e.Fazonosito:%d\n",maj or_num);
return0;
}
/*Ak ernelmoduleltav olitasaelottafelszabad tasok atv egzi.
staticvoid _exithello_ext(void)
/*Azudev sz m raj elz s,azeszk zelt v olit s rl.*/
dev ice_destroy (hello_class,MKDEV(maj or_num,0));
class_unregister(hello_class);
class_destroy (hello_class);
360
7.5. Karakteres eszkzvezrl
/*Eltav olitj uk az eszkoz regisztrac ot.*/
unreg ster_chrdev (maj or_num,DEv ICE_NAmE);
printk (oEv icE_NAmE"felszabaditv a.\n");
}
module_init(hello_init);
module_exit(hello_exit);
moDuLE_DEscRIP TIoN("Hello driv er");
mODULE_LICENSE("GP L");
A modul inicializl- s tisztogatfggvnye mr ismers. Ennl a modulnl
ezekben a fggvnyekben regisztrljuk, illetve tvoltjuk el a 12 0-as fazono-
sthoz az eszkzvezrl fggvnyeinket.
A file_operations struktrrl szintn esett mr korbban sz. A pldban
lthatjuk, hogyan adhatjuk meg az egyes llomnymveletekhez tartoz
fggvnyeket.
A hello_openo s a hello_elose0 fggvnyeinkben nveljk, illetve csk-
kentjk a hasznlatszmllt. Ezltal megakadlyozhatjuk a modul eltvolt-
st, amg egy vagy tbb processz nyitva tartja az eszkzvezrlnkhz tartoz
llomnyt.
Az eszkzllomny olvasst megvalst fggvnynk a korbban meg-
adott Hello!" szveget, vagy ha az olvas kevesebb byte-ot vr, akkor annak
egy rszt bemsolja a paramterknt kapott bufferbe (bal). A msolsra a
copy_to_user0 fggvnyt hasznljuk. Ennek az a feladata, hogy a kernel me-
mriatartomnyban lv adathalmazunkat a felhasznli memriatarto-
mnyba msolja. gy valsthatjuk meg a tartomnyok kzti adatmozgatst
ebben az irnyban.
Az olvasst megvalst fggvny visszatrsi rtkeknt a visszaadott
byte-ok szmt, az llomny vge" esetn 0-t vagy hiba esetn negatv rt-
ket kell visszaadnunk, annak megfelelen, amit a readO fggvny meghv-
sakor az alkalmazsban vrunk. Eltrs csak a hibajelzsnl mutatkozik,
ahol a hiba kdjt kell visszaadnunk, amelyet az alkalmazs az errno vlto-
zban kap meg. Az rst megvalst fggvny implementcijnl hasonlan
kell eljrnunk, csak ebben az esetben a szmrtk a feldolgozott byte-ok sz-
mt jelenti.
99
A hello_readO fggvny implementcija az adatok visszaadsa mellett
knyveli az aktulis pozcit is. Ennek akkor van szerepe, ha a fogad buffer
mrete kisebb a visszaadand szvegnl. Ilyenkor a ppos vltozban (term-
szetesen msknt is elnevezhetjk a paramtert) trolhatjuk, hol tartunk az
adatokban, s a kvetkez olvassi mveletnl visszaadhatjuk a maradkot.
A ppos vltoz egy llomnykezelsi viszonylatban egyedi. Vagyis ha megnyi-
tunk egy llomnyt, akkor kap egy egyedi pozcit trol vltozt, amely
99
Mindkt esetben a visszatrsi rtk tpusa ssize t, amely eljeles size _t (signed size_t")
tpust jelent. Ez a negatv rtkek visszaadsa miatt szksges.
361
7. fejezet: Fejleszts a Lnux-kernelben
megrzi az rtket. Ha egy msik folyamatban szintn megnyitjuk ugyanazt
az llomnyt, akkor ez a viszonylat egy msik vltozt kap. gy az egyes vi-
szonylatok nem zavarjk egymst.
A read s a write fggvnyek olyan buffereket kapnak paramternek a
felhasznli programoktl, amelyek a felhasznli cmtartomnyban vannak
lefoglalva. Ugyanakkor a kernelmodulok ltal lefoglalt terletek ltalban
a kernel cmtartomnyban vannak, ezrt meg kell oldanunk az adatok moz-
gatst a kt terlet kztt. Erre a linux/ uaccess.h tartalmaz az elz pld-
bl ismers fggvnyeket:
unsigned long copy_from_user(void *to, const void _user *from,
unsigned long n);
unsigned long copy_to_user(void _user *to, const void *from,
unsigned long n);
Az eszkzllomny rst implementl metdusban lthatjuk, hogy a kernel
memriatartomnyban a kmalloc0 fggvnnyel alloklhatunk terletet, s a
kfree0 fggvnnyel szabadthatjuk fel.
Valjban itt nem szksges az allokls s a msols, mert a konzolra
trtn kirs ezek nlkl is mkdne. A vals alkalmazsoknl azonban l-
talban szksg van ezekre a lpsekre, ezrt kerltek bele a pldba.
A fenti pldaprogram fordtsa a korbbi modulnl ismertetett Makefile
segtsgvel trtnhet.
Ezt kveten, ha az insmod utastssal betltttk a modult, akkor mr
hasznlhat is.
7.5.6. Az open s a release fggvnyek
Az open fggvny tipikus feladatai a kvetkezk:
A hasznlatszmll nvelse.
Eszkzspecifikus inicializci az els megnyitsnl.
Ha egyszerre az eszkzt csak egy program vagy egy felhasznl hasz-
nlhatja, akkor a klcsns kizrs megvalstsa.
A mellkazonost alapjn a pfile->f op paramter mdostsa, egy
msik file_operations struktra belltsa.
A pfile->private_data pointerhez alloklhatunk egy trterletet, s
bellthatunk valami eszkzspecifikus informcit.
362
7.5. Karakteres eszkzvezrl
A release fggvny feladatai a kvetkezk:
A hasznlatszmll cskkentse.
Eszkzspecifikus lezrsok az utols bezrsnl.
Ha a pfile->private_data pointerhez allokltunk valamit, akkor ennek
felszabadtsa.
A hasznlatszmllk kezelst mr korbban lthattuk. Az egyszeres meg-
nyitst a mellkletben tallhat pldakdokkal mutatjuk be, a mellkazonos-
t kezelsvel kapcsolatos megoldsokat pedig a kvetkez fejezet trgyalja.
7.5.7. A mellkazonost (minor number) hasznlata
A mellkazonost lehetsget biztost arra, hogy az eszkzmeghajt tbb
azonos tpus eszkzt tegyen lthatv az opercis rendszer szmra. Br a
meghajt szabadon hasznlhat eltr implementcit a klnbz mellkazo-
nostkhoz, az egysges viselkeds ersen javallott.
Vegyk pldnak a soros portokat kezel eszkzvezrlt. Termszetesen
az eszkzvezrl az egyes portokra megegyezik, hiszen pazarls lenne minden
porthoz kln eszkzvezrlt betlteni s regisztrlni. Vagyis az eszkzvezr-
lnk egy pldnyban van jelen, s egy fazonostra regisztrlta az llomny
interfszt. Az sszes soros porton foly kommunikcit azonban egyetlen l-
lomnyon keresztl elrhetv tenni nehz s clszertlen lenne. Jobban j-
runk, ha minden porthoz rendelnk egy llomnyt. Ekkor ezek az llomnyok
egy fazonostval rendelkeznek, s a mellkazonost klnbzteti meg ket.
A mellkazonost kezelse, ahogy korbban mr sz volt rla, a mi fela-
datunk. Kt utat vlaszthatunk. Az egyik megolds szerint az olvasst s
rst kezel fggvnyeinkbe helyeznk elgazsokat, amelyek a mellkazono-
st alapjn ms-ms kdrszletet futtatnak.
Feladat Mdostsuk az elbbi plda eszkzvezrljt gy, hogy ha 0-s mellkazonostj eszkz-
llomnyon keresztl olvassuk, akkor a Szia!", ha az 1-es, akkor a Mizu?" szveget adja vissza.
Nzznk egy rszletet, amely illeszkedik a korbbi pldba:
#defineMSG_LENb
staticchar*msgs[]={ "szia!","mizu?"} ;
staticssize_thello_read(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
i ntlen;
l en=count;
if(count>mSG_LEN)len=MSG_LEN;
363
7. fejezet: Fejleszts a Linux-kernelben
switch(MINOR (pfile- >f_dentry - >d_inode - >i_rd ev))
{
case0:
i f(copy _to_user(buf,msgs[0],len))return-EFAULT;
break ;
case 1:
if(copy _to_user(buf,msgs[1],len)) return -EFAULT;
break ;
default:
return - EINVAL
return len;
Az llomnyt ler struktra segtsgvel elrjk annak az eszkzllomny-
nak az inode-informciit, amelyen keresztl a fggvny meghvdott. Azon
bell is a f- s a mellkazonostt tartalmaz i_rdev tagjt vizsgljuk. Ebbl
a M/NORO makr hasznlatval kinyerhetjk a mellkazonostt. Ezt kve-
ten a switch-case szerkezet segtsgvel eltr kdot hajtunk vgre az egyes
esetekben.
A msik megolds az, ha az elz fejezetben ltottak szerint az llomny
megnyitsnl lltunk be eltr lekezel fggvnyeket az egyes minor sz-
mok esetben. Nzznk egy pldakdrszletet erre az esetre is:
#defineMSG_LEN 6
stat cchar*msgs[]={ "Szia!","mizu?"} ;
staticssize_thello_write(structfile*pfile,constchar*buf,
size_tcount,loff_t*ppos);
staticssize_thello_readl(structfile char*buf,
size_tcount,loff_t*ppos);
staticssize_thello_read2 (structfile*pfile,char*buf,
size_tcount,loff_t*ppos);
staticinthello_open(structinode*inode,structfile*pf le);
staticinthello_close(structinode*inode,structfile*pfile);
staticstructfile_operationshello_fops=
owner: THIS_MODULE,
read: hello_readl,
write: hello_write,
open: hello_open,
release:hello_close
} ;
staticstructfile_operationshellol_fops=
owner:
THIS_MODULE,
read:
hello_readl,
write:
hello_write,
364
7.5. Karakteres eszkzvezrl
open: hello_open,
release:hello_close
} ;
staticstructfile_operationshello2 _fops=
{
owner: THIS_MODULE,
read: hello_read2 ,
write: hello_write,
open: hello_open,
release:hello_close
} :
structfile_operations*hello_fops_array []=
&hellol_fops,
&hello2 _fops,
} ;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
staticssize_thello_readl(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
{ ntlen;
len=count;
if(count>MSG_LEN)len=MSG_LEN;
if(copy _to_user(buf,msgs[0],len))return -EFAULT;
returnlen;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
staticssize_thello_read2 (structf le*pfile,char*buf,
size_tcount,loff_t*ppos)
{
intlen;
len-count;
if(count>MSG_LEN)len=MSG_LEN;
if(copy _to_user(buf,msgs[1],len))return-EFAulT;
returnlen;
/*Amegny itasmuv eletetlek ezelofuggv eny .*/
staticinthello_open(structinode*inode,structfile*pfile)
{
intnum;
num=MINOR(inode->i_rdev );
if(num>=2 )return-ENODEV;
pfile->f_op=hello_fops_array [num];
7. fejezet: Fejleszts a Linux-kernelben
/*Nov elj uk ahasznalatiszamlalot.*/
try _module_get(THIS_mODuLE);
printk (DEVICE_NAME"open.\n");
return0;
_Y..-. --
A pldban kt eltr fggvnynk van a kt eszkzllomny olvassra. Azt
azonban mr tudjuk, hogy csak egy kezelfggvnyt llthatunk be egy fazo-
nostra, vagyis ez mindegyik mellkazonostnl ugyanaz lesz. Ezt a probl-
mt gy oldhatjuk meg, ha az open fggvnyben az adott helyzetre mdostjuk
a belltott kezelfggvnyeket.
A pldban a mellkazonost kinyerse utn eltr lekezelfggvny-
halmazt lltunk be az egyes viszonylatokra. A mellkazonostt indexknt hasz-
nlva a korbban belltott tmbbl ms-ms fggvnyhalmazt vlasztunk.
7.5.8. Az ioctl() i mplementcija
A Unix fjlabsztrakcis interfsznek elnye az egyszersg. Ugyanakkor az
egyes eszkzk ltal lehetv tett specilis belltsokhoz nem lehet a meg-
nyits, lezrs, rs s olvass mveletein keresztl hozzfrni. Ezt az lta-
lnos ioctl fggvny segtsgvel oldhatjuk meg.
Az ioctl fggvnnyel kzvetlenl parancsokat hajthatunk vgre az eszkz-
kezeln bell. Ezzel feloldhatjuk az ltalnos llomnymveletek korltait.
Ugyanakkor mrskelten ellenrztt, kzvetlen hozzfrst ad az eszkzve-
zrl bels funkciihoz, ezrt a kernelfejleszt'k biztonsgi kockzatot ltnak
benne, s nem igazn kedvelik. Ennek ellenre sok funkcit mg mindig gy
lehet a legjobban megoldani. Ugyanakkor kialakulban vannak jabb mecha-
nizmusok, amelyek rszben kivlthatjk az ioctl fggvnyt. Ilyenek pldul a
sysfs llomnyrendszeren keresztl elrhet eszkzattribtumok.
Az ioctl rendszerhvs kezelfggvnyt hasonlan tudjuk megvalstani,
mint a karakteres eszkzvezrl tbbi llomnykezel fggvnyt. Ltre kell
hoznunk egy fggvnyt, majd a mutatjt be kell lltanunk a file_operations
struktra adott mezjben. A fggvny alakja, amely egybknt a file_operations
struktra defincijbl derl ki, a kvetkez:
lengioctl(structfile*pfile,unsignedintcmd,unsignedlongarg)
m ha alaposabban megnzzk a file_operations struktrt, tbb olyan mezt
is tallhatunk benne, ahol az ioctl fggvny mutatjt bellthatjuk. Vegyk
ezeket sorra.
Az ioctl mez a 2 .6.37-es kernelig volt jelen. Az itt megadott fggvnyt
gy futtatja le a rendszer, hogy eltte lefoglalja a nagy kernelzrolst" (Big
Kernel Lock, lsd a 7.9.5. Olvas/r ciklikus zrols (spinlock) s szemafor
(semaphore) alfejezetban), majd a vgn felszabadtja. Ezzel a rendszer leke-
3 66
7.5. Karakteres eszkzvezrl
zeli a szinkronizcis problmk egy rszt, gy ezzel a fggvny ksztjnek
mr nem kell foglalkoznia. A nagy kernelzrols" megsznsvel azonban az
ioctl fggvny ilyen jelleg implementcija sem maradhatott meg, ezrt a
2 .6.37-es kernel ta nem hasznlhat.
Az unlocked_ioctl a jelenleg leggyakrabban hasznlt mez ioctl fggv-
nyek regisztrlsra. Ahogy a neve is tartalmazza, a rendszer nem vgez
szinkronizcit, gy az esetleges konkurenciaproblmkat neknk kell megol-
dani a fggvny megvalstsban.
A compat_ioctl a harmadik mez, amely mg elfordul. Jelentsge ak-
kor van, ha egy 64 bites rendszerben a 32 bites folyamatoknak szeretnnk
ioctl szolgltatst nyjtani. Ilyenkor a fggvnynk megvalstsakor fel kell
kszlnnk az eltr adatbrzols okozta problmkra.
A szinkronizcis s az adatkezelsi problmkat leszmtva a hromfle
ioctl i mplementci felptse hasonl. A fggvny gyakran egy switch-case
szerkezetet tartalmaz, amely a parancskd alapjn gazik el. Az gak az
egyes parancsok megvalstst kpezik.
Az ioct/O parancskdok sszelltsa az els feladatunk. Egyedi azonostt
kell megadnunk minden parancshoz, de nem clszer, hogy egyesvel elkezdjk
szmozni ket 1-tt kezdden. Ezzel ugyanis az a problma, hogy a felhasznl
tvedsbl az egyik eszkz parancskdjait felhasznlhatja egy msik tpus
eszkznl, amely rtelmezi a parancskdot, s teljesen mst csinl, mint amit
a felhasznli program ksztje szeretne. Mivel itt a kernel cmtartomnyban
garzdlkodunk", ezrt ez akr vgzetes is lehet a rendszer szempontjbl.
Az ilyen jelleg problmk elkerlshez clszer abban gondolkodni, hogy
a parancskdok egyediek legyenek, s az adott eszkzhz tartozzanak, ms
eszkzk pedig lehetleg ne rtelmezzk, s hibt adjanak vissza.
Kzenfekv megoldsnak tnik, amelyet a korai Linux-verzik hasznltak
is, hogy a 16 bites parancskdbl a fels byte legyen egy mgikus szm".loo gy
ez a szm az eszkz szma, az als byte pedig az eszkzn belli egyedi azo-
nost. Termszetesen ez nem garantlja a parancskd tnyleges egyedisgt,
m jelentsen lecskkenti a vletlen balesetek eslyt. A mgikus szmokrl
a Documentation lioca-number.txt llomnyban tallhatunk egy listt.
Egy potencilis hibaforrs azonban tovbbra is fennll. A rendszer nem
tudja ellenrizni, hogy az adott parancskdhoz megfelel argumentumot ad-
tunk-e meg utols paramterknt. Ugyanis a fordt ezt nem teheti meg, hi-
szen ltalnos pointereket hasznlunk, ezrt a feladat a kernelre pontosab-
ban a kernelmodul ksztjre hrul. A megolds az, ha minden argumen-
tumspecifikus informcit is belekdolunk a parancskdba, gy mr olyan l-
talnos ellenrz mechanizmus hasznlatra is lehetsg nylik, amelyet a
kernel is kpes tmogatni.
Nzzk meg vgl, melyek azok a paramterek, amelyeket manapsg a
parancskdok ellltsra hasznlnak (7.2. tblzat).
100
A mgikus szm" egy olyan szm, amelyet a felhasznl igyekszik egyedinek megvlasz-
tani.
367
7. fejezet: Fejleszts a Linux-kernelben
7.2. tblzat. Az IOCTL parancskdok ellltshoz hasznlt paramterek
Informci Jelents
type Egy mgikus szm, amelyet az adott eszkzhz vlasztottunk Mre-
te 1 byte.
number Egy 1 byte-os szm, a parancsnak az eszkzn belli egyedi azonostja.
Dir Az adatramls irnya: nincs adatramls, rs, olvass, mindkett.
Size Az argumentum mrete.
Az adatokbl a parancskdok ellltsban a kvetkez makrk segtenek:
#nclude <asm/ioctl .h>
_IO(ty pe,number)
_IOR(ty pe,number,dataitem)
_IOW(ty pe,number,dataitem)
_IOWR(ty pe,number,dataitem)
A makr nevnek az JO utni rsze adja meg az adatramls irnyt a fel-
hasznli oldal fell:
nincs
R: olvass
W: rs
WR: rs s olvass
A dataitem az argumentum tpusa vagy egy ugyanolyan tpus vltoz. Ebbl
a rendszer meghatrozza az architektra fgg mretet.
A 7.2. tblzatban szerepl egyes informcikat a parancskdbl a kvet-
kez makrkkal lehet visszafejteni:
_IOC_TYP E(cmd)
_IOC_NR(cmd)
_IOC_DIR(cmd)
_IOC_SIZE(cmd)
-9
~1~11111a
Ezek alapjn nzznk meg egy pldaheaderfjlt:
#define HELLO_IOC_MAGIC ' h '
#defineHELLO_IOC_INCREASE_IO(HELLO_IOC_MAGIC,0)
#defineHELIO_IOC_OECREASE_10(HELI0_IOC_MAGIC,1)
#defineHELLO_IOC_GET_IOR(HEILO_IOC_MAGIC,2 ,int)
#defineHELLO_IOC_SET_10W(HELLO_IOC_MAGIC,3 ,int)
368
7.5. Karakteres eszkzvezrl
A kvetkez feladatunk az ioca() fggvny implementcija. Nzznk erre is
egy pldt:
longhello_ioctl(struct file *pfile,unsignedintcmd,
unsignedlongarg)
f
intres=0;
i f(_IOC_TYP E(cmd)!=HELLO_IOC_MAGIC)return-ENoTTY;
if(_IOC_DIR(cmd)&_IOC_READ)
if(!access_ok (VERIFY_READ,(v oid*)arg,
_IOC_SIZE(cmd)))return-EFAULT;
elseif(_IOC_DIR(cmd)&_IOC_WRITE)
i f(!access_ok (v ERIFY_WRITE,(v oid*)arg,
_10C_SIZE(cmd)))return-EFAULT;
}
switch(cmd)
{
caseHELLO_IOC_INCREASE:
/*Muv elet1*/
break ;
caseHELLO_IOC_DECREASE:
/*Muv elet2 */
break ;
caseHELLO_IOC_GET:
/*Muv elet3 */
break ;
caseHELLO_IOC_GET:
/*Muv elet4*/
break ;
default:
return-ENOIOCTLCMD;
returnres;
}
A fggvny elejn megvizsgljuk a parancskdba kdolt informcikat: a m-
gikus szmot, az adatramls irnyt, az argumentum mrett. Majd ellen-
rizzk, hogy a kapott argumentum megfelel-e ezeknek a kritriumoknak.
Az argumentumok ellenrzst az access_ok() fggvnnyel vgeztk. En-
nek alakja a kvetkez:
#include <asm/uaccess.h
intaccess_ok (intty pe,constv oid*addr,unsignedlongsize)
369
7. fejezet: Fejleszts a Linux-kernelben
Az els argumentum (type) lehet VERIFY READ, VERIFY WRITE vagy a
kett bites vagy kombincija is a mvelet tpustl fggen. A msodik pa-
ramter (addr) a vizsglt argumentum cme. Az utols (size) az ltalunk vrt
adatterletmret. A visszatrsi rtk valjban egy logikai rtk. Ha sikeres
az ellenrzs, akkor 1, ha az ellenrzs problmt tallt, akkor O.
Ha az ellenrzs sorn minden rendben van, akkor egy elgazssal ms-
ms mveletet hajtunk vgre az egyes parancsokra. Ha az argumentum hi-
bs, vagy ismeretlen parancskdot kaptunk, akkor hibval trnk vissza.
A kezelfggvny implementcija utn mr csak regisztrlnunk kell a
fggvnyt az eszkzvezrlhz hasonlan, mint korbban a read vagy a write
fggvnyeket, ezttal a file_operations struktra unlockedioctl nev mezjn
keresztl.
7.6. A /proc llomnyrendszer
A Linux rendelkezik egy tovbbi mechanizmussal is, amellyel a kernel vagy a
kernelmodulok informcikat tudnak tadni a felhasznli zemmdban fut
folyamatoknak. Br a karakteres eszkzvezrlknl megismert mdszerrel is
megoldhatjuk a kommunikcit egy folyamat s egy kernelmodul kztt, m a
/proc llomnyrendszer hasznlata ezt leegyszersti. Eredeti feladata az,
hogy knnyen hozzfrhet informcit szolgltasson a processzekhez kapcso-
ld adatokrl (lsd a 2.3.1. A Linux processzekhez kapcsold informcik
alfejezetben). Manapsg a kernel minden olyan rsze hasznlja, amelyik va-
lamilyen hasznos jelentssel vagy statisztikval szolglhat. Tovbb mr
nemcsak olvashatjuk, hanem rhatjuk is egyes rszeit, gy szablyozva a ker-
nel s a modulok mkdst.
A metdus hasonlt az elzekben, az eszkzvezrlben hasznltakhoz. Itt
is egy struktrt kell ltrehoznunk, amely tartalmaz minden informcit,
amely szksges a /proc llomnyunkhoz, belertve a mutatt a kezelfgg-
vnyekre. Ha egy csak olvashat llomnyt szeretnnk ltrehozni, akkor csak
egy fggvnyt kell implementlnunk s belltanunk, amely az llomny ol-
vassakor meghvdik. A modul inicializlsakor regisztrljuk a ler struk-
trnkat, s a tisztogatfggvnyben eltvoltjuk.
A kvetkez pldamodul ltrehoz a /proc llomnyrendszerben egy hello"
llomnyt, amely egy dvzl szveget ad vissza, ha kiolvassuk a tartalmt:
/* helloproc.c -Egy szerukernel modul a /proc allomanyrendszer
hasznalatara. */
#include <1 i nux/modul e .
#include <1 nux/kernel . h>
#include <1 i nux/proc_fs h>
370
7.6. A /proc llomnyrendszer
/*Azallomany olv asasatlek ezelofuggv eny .*1
intprocfile_read(char*buffer,char**buffer_location,
off_toffset,intbuffer_length,int*eof,
v oid*procdata)
{
intlen;
/* Az egy szerusegk edv eertnemengedunk reszlegesolv asast.
Csak azallomany elej erol.*/
i f(offset)
{
*eof=1;
return0;
}
/*Feltoltj uk abuffertesv isszaterunk azadathosszav al.
len=sprintf(buffer,"Helloprocv ilag!\n");
returnlen;
}
/*Ak ernelmodulinicializalasatv egzofuggv eny .
staticint_inithello_in t(v oid)
structproc_dir_entry *hello_proc_ent;
/*Dinamik usanhozzuk letreaprocallomany bej egy zest.*/
hello_proc_ent=create_proc_entry ("hello", S_IFREGIS_IRUGO,
0);
/*Beallitj uk alink szamlalotesak ezelofuggv eny t.*/
if(!hello_proc_ent)
{
remov e_proc_entry ("hello",0);
printk ("Error: A /proc/hellonemletrehozhato.\n");
return -ENOMEM;
}
hello_proc_ent->nlink =1;
hello_proc_ent->read_proc=procfile_read;
printk ("A/proc/helloletrehozv a.\n");
return0;
/*Ak ernelmoduleltav olitasaelottafelszabaditasok atv egzi.*/
staticv oid_exithello_exit(v oid)
/*Megsemmisitj uk aprocallomany bej egy zest.*/
remov e_proc_entry ("hello",0);
printk ("A/proc/helloeltav olitv a.\n");
371
7. fejezet: Fejleszts a Linux-kernelben
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIP TION("Helloproc");
moDuLE_LicEN5E("GP L");
Lthat, hogy itt dinamikusan hoztunk ltre a proc llomnyler struktr-
bl egy elemet, amelynek belltottuk a linkszmlljt s az olvasst kiszol-
gl fggvnyt. A megsemmistst a neve alapjn vgezzk el.
Az olvasfggvny implementlsnl az egyszersg kedvrt csak a 0
eltolst fogadjuk el. Ilyenkor a paramterknt kapott bufferbe berjuk a sz-
veget, s a hosszval visszatrnk. Ha megnzzk a kdot, lthatjuk, hogy
ebben az esetben nem foglalkoztunk a kernel s s a felhasznli cmtarto-
mny kztti mozgatssal. Ennek az a magyarzata, hogy a fggvny megh-
vsakor bufferknt egy memrialapot kapunk. Miutn rrtuk az informcit,
a tartalma tmsoldik a felhasznli cmtartomnyba, gy a folyamatok el-
rik. Ezzel a megoldssal az implementci leegyszersdik, s a hibalehet-
sgek szma is cskken.
rhatv is tehetjk a virtulis llomnyunkat Ehhez szksg van az rs-
kor meghvott fggvny implementcijra. Ez hasonlt a karakteres eszkzve-
zrlknl megismertekre, belertve a kernel- s a felhasznli cmtartomny
kztti adatmozgatst is. A kvetkez pldaprogram megmutatja, hogyan hoz-
hatunk ltre rhat proc llomnyt:
/*helloproc2 .c-Egy szeruk ernelmodula/procallomany rendszer
hasznalatara.*/
#include<linux/module.h>
#include<linux/k ernel.h>
# nclude<linux/proc_fs.h>
#include<asm/uaccess.h>
Whill~~M~
1
~~1
#defineGBUFFERSIZE2 56
staticchargbuffer[GBuFFERsizE];
staticunsignedlonggbufferlen=0;
staticP EFINE_MUTEx(lock );
/*Azallomany olv asasatk ezelofuggv eny .*/
ntprocfile_read(char*buffer,char"buffer_location,
off_toffset, ntbuffer_length,int*eof,
v oid*procdata)
{
intlen;
/*Azegy szerusegk edv eertnemengedunk reszlegesolv asast.
Csak azallomany elej erol.*/
if(offset)
{
*eof=1;
return0;
372
7.6. A /proc llomnyrendszer
/*Feltoltj uk abuffertesv isszaterunk azadathosszav al.*/
if(down_interruptible(&lock ))return -ERESTARTSYS;
memcpy (buffer,gbuffer,gbufferlen);
l en=gbufferlen;
up(&lock );
returnlen;
}
intprocfile_write(structf le*pfile,constIhar*buffer,
unsignedlongcount,v oid*procdata)
{
if(count>GBUFFERSIZE)
count=GBUFFERSIZE;
}
if(down_ nterruptible(&lock ))return -ERESTARTSYS;
if(copy _from_user(gbuffer,buffer,count))
{
gbufferlen=0;
up(&lock );
return -EFAULT;
gbufferlen=count;
up(&lock );
returncount;
}
/* A k ernelmodulinicializalasatv egzofuggv eny .*/
staticint_inithello_init(v oid)
structproc_dir_entry *hello_proc_ent;
/*Dinamik usanhozzuk letreaprocallomany bej egy zest.*/
hello_proc_ent=create_proc_entry ("hello",
S_IFREGIS_IRUGOI S_IWUGO, 0);
/*Beallitj uk alink szamlalotesalek ezelofuggv eny t.
if(!hello_proc_ent)
{
remov e_proc_entry ("hello",0);
printk ("Error: A /proc/hellonemletrehozhato.\n");
return-ENOMEM;
}
hello_proc_ent->nlink =1;
hello_proc_ent->read_proc=procfile_read;
hello_proc_ent->write_proc=procfile_write;
hello_proc_ent - >mode=S_IFREGIS_IRUGOIS_IWUGO;
hello_proc_ent - >uid=0;
373
7. fejezet: Fejleszts a Linux-kernelben
hello_proc_ent->gid=0;
hello_proc_ent->size=2 56;
printk ("A/proc/helloletrehozv a.\n");
return0;
/*Ak ernelmoduleltav ol tasaelottafelszabaditasok atv egzi.
A /
staticv oid exithello_exit(v oid)
/*megsemmisitj uk aprocallomany bej egy zest.*/
remov e_proc_entry ("hello",0);
printk ("A/proc/helloeltav olitv a.\n");
module_init(hello_init);
module_exit(hello_ex t);
MODULE_DESCRIP TION("Hell0proc");
MODULE_LICENSE("GP L");
A pldban egy olyan proc llomnyt hozunk ltre, amely hasonlt a vals l-
lomnyokra. Vagyis amit belerunk, azt utna kiolvashatjuk belle. Ugyan-
akkor tartalmaz egyszerstseket is, gy nem teljes rtk implementci.
A virtulis llomny prhuzamos olvassa s rsa versenyhelyzetet ered-
mnyezhet, ezrt a pldban a globlis troltmbhz val hozzfrst szinkro-
nizcis eszkzzel kell szablyoznunk. A korbbi pldkban nem volt szksg
erre, mert a globlis vltoznkat csak olvastuk, ezzel szemben ebben a pld-
ban olvassuk s rjuk is prhuzamosan. A pldban ezt egy szemaforral tettk.
(A szinkronizcis eszkzket s hasznlati terletket egy ksbbi fejezetben
trgyaljuk, m a helyes implementcihoz szksg volt a hasznlatra.)
Ahhoz, hogy a folyamatok tnylegesen tudjk rni az llomnyt, az rst
kezel fggvny regisztrcija mellett arra is szksg van, hogy az rsjogot
megadjuk a felhasznlknak Az llomny ltrehozsnl lthatjuk, hogy a
pldban mindenkinek joga van rni a virtulis llomnyunkat.
Felmerlhet a krds: hogyan lehetsges az, hogy rhat az llomnyunk,
pedig nem is a /proc/sys knyvtr alatt tallhat. Az igaz, hogy ltalban az r-
hat proc llomnyok az emltett knyvtr alatt tallhatk, de ez csak konvenci.
Valjban a /proc knyvtr alatt tetszleges llomnyt tehetnk rhatv.
374
7.7. A hibakeress mdszerei
7.7. A hiba keress mdszerei
A hibakeressre kernelfejleszts esetben korltozottabbak a lehetsgeink,
mint egy alkalmazsnl. Mivel a kernelmodul a betlts utn a kernel szer-
ves rszt alkotja, ezrt ilyenkor lnyegben abban a programban kell hibt
keresnnk, amely a mkd rendszer kzponti eleme, s ugyanezen program
alatt futnak a hibakeressre hasznlt eszkzeink is. Ezrt a feladat jval bo-
nyolultabb, mint felhasznli cmtartomnyban.
A legegyszerbb s ugyanakkor leggyakrabban hasznlt mdszereket mr
megmutattuk. Mind a printk() fggvny, mind a /proc llomnyrendszer al-
kalmas arra, hogy informcit kzljnk a kernelmodul llapotrl, gy hasz-
nlhatk a hibakeresshez. Ezeken kvl lteznek kifinomultabb mdszerek
is, amelyekre ugyancsak mutatunk pldt ebben a fejezetben.
7.7.1. A prntk() hasznlata
A legegyszerbb s ezrt az egyik leggyakrabban hasznlt mdszer a hibake-
ressre, ha a lnyeges pontokon kirjuk az llapotokat. A kernel esetn ezt a
printkQ fggvnnyel tehetjk meg, majd a kernelnaplbl nzhetjk vissza.'"
A kernelnaplba rt zenetek klnbz fontossgak lehetnek. A hibake-
resshez ltalban minden szba jhet informcit kiratunk, ez pedig nagy
mennyisg naplbejegyzst eredmnyez. Viszont valsznleg kisebb a sz-
ma a fontos, konkrt hibt jelz zeneteinknek. Azrt, hogy ezeket a naplz-
sokat kzben tarthassuk, a Linux szintekbe szervezi a klnbz fontossg
zeneteket, ezt clszer neknk is alkalmaznunk a kirsaink sorn. Az albbi
szinteket klnbztetjk meg (7.3. tblzat):
7.3, tblzat. Kernel zenetek szintjei
Cmke rtk Ler s
KERN_DEBUG <7> A legkevsb fontos zenetek, amelyeket csak teszte-
lsnl hasznlunk.
KERN_INFO <6> Informcik a driver mkdsrl.
KERN_NOTICE
<5>
Nincsen gond, de azrt jelznk valamilyen emltsre
mlt szitucit.
KERN_WARNING <4 > Problms helyzet jelzse.
KERN_ERR <3> Hiba jelzse.
101
A kernelnaplt a dmesg paranccsal vagy a log llomnyokbl nzhetjk vissza. Tipikus
helye a /var/logimessages vagy /var/logisyslog llomny a syslog rendszer belltstl
fggen.
375
7. fejezet: Fejleszts a Linux-kernelben
Cmke rtk Lers
KERN_CRIT <2 > Kritikus hiba jelzse.
KERN_ALERT <1> Vszhelyzet, amely esetleg srgs beavatkozst ignyel.
KERN_EMERG <0> A legfontosabb zenetek. Tbbnyire a rendszer meg-
halsa eltt kapjuk.
A naplzrendszer lehetv teszi, hogy a ksbbiekben a fontossgi szint
alapjn szrjnk. Vagyis nem szksges a szoftveren mdostani, ha pldul
az egyszerbb hibakeressi zeneteket ki akarjuk kapcsolni.
A fontossgi szintek hasznlata a kvetkez:
printk(KERN_DEBUG "uzenet \ n") ;
A szrs belltsa az albbi:
echo 8 > /proc/sys/kernel/printk
A pldban a 8"-as rtk adja meg, hogy a KERN_DEBUG zeneteket is lt-
ni szeretnnk. Ahogy ezt a szmot cskkentjk, gy csak az egyre fontosabb
zeneteket lthatjuk. A 0" rtk azt jelenti, hogy csak a KERN_EMERG
zeneteket kapjuk meg.
Elfordul, hogy szeretnnk egy zenetben kirni, hogy ppen merre j-
runk a kdban. Termszetesen ezt megtehetjk gy, hogy a szvegbe beler-
juk a pozcit, m ltezik ennek automatizlt mdja is.
Pldul a forrskdllomny nevnek s sorszmnak kirsa a kvetkez:
printk(KERN_DERuG "Kod: %s:%
-
i \n", FILE , LINE )
Ha az ppen aktulis programkd pointerre vagyunk kvncsiak, vagyis ar-
ra, hogy a kirst vgz gpi instrukci hol tallhat a virtulis memriban,
a kvetkezt kell tennnk:
printk(KERN_DEBuG "Cim: Yop\n", ptr);
7.7.2. A /proc hasznlata
Az elz fejezetben lthattuk, hogyan valsthatunk meg olyan llapotelle-
nrzst, amikor is a kernelmodul adja a futsa sorn a jelzseket. Nha azon-
ban egy ilyen jelleg megolds olyan mennyisg llapotinformcival raszt
el bennnket, amelynek a kezelse knyelmetlen. Emellett a rendszer futst
is ersen lelassthatja egy ilyen jelleg kirsradat.
376
7.7. A hibakeress mdszerei
Ilyenkor a megolds az lenne, ha bizonyos idpontokban, amikor ppen
szksg van rjuk, megvizsglhatnnk az llapotvltozk aktulis rtkt,
vagyis igny szerinti lekrdezst alkalmaznnk. Ezt teszi lehetv a /proc l-
lomnyrendszer a virtulis llomnyain keresztl. Ennek implementcijt
korbban lthattuk. Az jdonsgot csak az jelenti, hogy a korbban megis-
mert mechanizmust hibakeressre is hasznlhatjuk.
A /proc llomnyrendszer mellett hasonl hatst rhetnk el az ioca0
rendszerhvs implementcijval is, amelyre most nem trnk ki. Az
ioca0
rendszerhvst azonban csak eszkzvezrl'knl alkalmazhatjuk, gy ltalnos
modulok esetben nem jrhat t.
7.7.3. Kernelopcik
A kernel fordtsa eltt, a konfigurlskor szmos hibarzkelsi mechaniz-
must bekapcsolhatunk. Ezeknek az opciknak a hatsra a fordts sorn
plusz hibarzkelsi s kezelsi algoritmusok fordulnak bele a kernelbe. gy
az ltalunk rt kd hibira knnyebben fny derlhet. A kernel hibarzkelsi
algoritmusainak egy j rsze azonban a plusz ellenrzsek miatt lasstja a
kernel mkdst, gy norml rendszerben nem hasznlhatk, ezrt alap-
esetben ki vannak kapcsolva.
A hibarzkelsi/kezelsi opcikat a kernelkonfigurci sorn a Kernel
Hacking" gban tallhatjuk meg. Minden opcihoz kapunk segtsget, amely
lerja az adott bellts ltal nyjtott szolgltatst. A lehetsges hibakeressi
opcik listja hossz, s kernelverzinknt vltozik, bvl, gy nem vllalko-
zunk a lista rszletes lersra s elemzsre. Az albbiakban sszegyjtt-
tnk nhny fontosabb opcit.
CONFIG_DEBUG_KERNEL: Bekapcsolja a hibakeressi opcikat.
9
ese-
tn a kvetkez:
struct platform_driver {
struct device_driver driver;
struct pl atform_devi ce_i d "id_tabl e;
;
Ugyanakkor ezeket a kibvtett eszkzvezrl lerstruktrkat a korbbi
regisztrlfggvnynek nem adhatjuk t. Ezrt tipikusan minden busztpus
eszkzvezrl tartalmaz egy sajt eszkzvezrlt regisztrl s egy regisztr-
lst megszntet fggvnyt, amely a kibvtett struktrkkal dolgozik. Ez a
specilis regisztrlfggvny vgzi el a bus mez belltst is az eszkzve-
zrl lerstruktrjban. Nzzk meg pldaknt a platformbusz esett:
int pl atform_dri ver_regi ster (struct platform_driver * drv)
{
drv->driver.bus = &platform_bus_type;
return dri ver_regi ster(&dry->dri ver) ;
Az eltvolts a kvetkez:
void pl atform_d ri ver_un regi ster(struct platform_driver * drv)
{
driver_unregi ster(&drv->driver) ;
}
sszegezve: ha egy olyan buszhoz szeretnnk regisztrlni egy eszkzvezrlt,
amely nem az ltalnos lerstruktrt hasznlja ilyen a buszok tbbsge ,
akkor a buszspecifikus lerstruktrbl hozunk ltre egy pldnyt, s azt
tltjk ki, tovbb a buszspecifikus regisztrl- s eltvoltfggvnyeket
hasznljuk.
109
A platformbusz nem valdi busz. Ide soroldnak azok a specilis hagyomnyos hardve-
rek, amelyek nem buszra csatlakoznak, ilyen pldul a billentyzetvezrl.
4 32
7.19. Eszkzvezrl modell
7.19.6. Eszkzvezrl attribtumok exportlsa
Hasonlan a busz attribtumaihoz az eszkzvezrlnek is hozhatunk ltre s
exportlhatunk attribtumokat. Az eljrs megegyezik a korbbival, csak az
adattpusok s a fggvnyek neve ms, ezrt a rszletes magyarzatot nem
ismteljk el, az a buszattribtumoknl olvashat (lsd a 7.19.4. Buszattrib-
tumok exportlsa alfejezetben).
Az eszkzvezrl attribtumtpusa a kvetkez:
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *driver, char *buf);
ssize_t (*store)(struct device_driver *driver, const char *buf,
size_t count);
};
A mezk megegyeznek a bus_attribute tpus mezivel a fggvnyek param-
terezst leszmtva. rtelmezsk ugyanaz.
A ltrehozst s inicializlst vgz makr az albbi:
. DRiVER_ATTR,(h4 j09
0
SUltS g,
ShoWfv,
storefv)
A makrval ltrehozott vltoz neve driver_attr_nv lesz.
Az attribtum virtulis llomnyt ltrehoz, illetve eltvolt fggv-
nyek a kvetkezk:
int driver_create_file(struct device_driver *driver,
const struct driver_attribute *attr);
void driver_remove_file(struct device_driver *driver,
const struct driver_attribute *attr);
7.19.7. Az eszkz
Az eszkzk ltalnos ler struktrja az albbi:
struct device {
struct device *parent;
struct device_private
const char
const struct device_type
struct mutex
struct bus_type
struct device_driver
void
*
P;
*init_name;
*type;
mutex;
*bus;
*driver;
*platform_data;
dev_t devt;
433
7. fejezet: Fejleszts a Linux-kernelben
struct cl ass * cl ass ;
const struct attri bute_group * * groups ;
void (* rel ease) (struct device * dev) ;
};
A mezk rtelmezse a kvetkez (7.9. tblzat):
7.9. tblzat. Az eszkz regisztrcisstruktra -mezi
Nv
parent
init_name
type
mutex
rtelmezs
Az eszkz szlje, vagyis az az eszkz, amelyre r van csatlakoz-
tatva. Ez tbbnyire egy busz vagy egy vezrl.
Az eszkz privt adatai.
Az eszkz neve.
Az eszkz tpusa.
Az eszkzhz rendelt mutex az eszkzvezrl mveleteinek szink-
ronizlshoz.
bus A buszeszkz, amelyre csatlakoztatva van.
driver A driver, amelyik alloklta ezt a struktrt.
platform_data Trolhely, ahova az eszkzvezrl az eszkzhz kapcsold in-
formcikat helyezheti. Ilyenkor ltrehoz egy egyni adatstrukt-
rt, s ide helyezi a mutatjt.
devt
class
groups
release
A sysfs-en bell, illetve udev-vel eszkzllomny gyrtshoz.
Az eszkz osztlya.
Opcionlis csoportattribtumok.
Akkor hvdik meg, amikor az eszkzler struktrt megsemmis-
ti a busz eszkzvezrlje.
A busz eszkzvezrlje rzkeli az eszkz csatlakoztatst. Ennek hatsra
ltrehoz egy pldnyt a device struktrbl, s regisztrlja a kvetkez fgg-
vnnyel:
intdev ice_register(structdev ice*dev );
Az eszkz akkor sznik meg, ha a referencia szmllja elri a 0-t. A referen-
ciaszmllt nvelni s cskkenteni az albbi fggvnyekkel tudjuk:
struct device *get_device(struct device *dev);
void put_device(struct device *dev);
A get_device0 fggvny visszaadja a struktra mutatjt abban az esetben,
ha az mg ltezik. Ha a referenciaszmll mr elrte a 0 rtket, akkor mr
megsznt az eszkz.
434
7.19.Eszk zv ez rlmodell
Emellett az eszkzn vgzett mveletek szinkronizlshoz hasznlhat-
juk az eszkz struktrjban szerepl mutexmezt. Ezt az albbi mveletek-
kel foglalhatjuk le:
v oiddev ice_lock (structdev ice*dev );
intdev ice_try lock (structdev ice*dev );
Felszabadtani pedig a kvetkez fggvnnyel tudjuk:
v oiddev ice_unlock (structdev ice*dev );
7.19.8. Az eszkz attribtumainak exportlsa
Hasonlan a buszhoz s az eszkzvezrlkhz az eszkzknek is megadha-
tunk attribtumokat, s kiexportlhatjuk. Ebben az esetben is hasonl tpu-
saink s fggvnyeink vannak, mint a busz esetben. (Bvebb informcit a
7.19.4. Buszattribtumok exportlsa alfejezet tartalmaz.)
Az eszkz egy attribtumt ler struktra az albbi:
structdev ice_attribute{
structattributeattr;
ssize_t(*show)(structdev ice*dev ,
structdev ice_attribute*attr,char*buf);
ssize_t(*store)(structdev ice*dev ,
structdev ice_attribute*attr,
constchar*buf,size_tcount);
1 ;
A mezk rtelmezse megegyezik a busz attribtumainl trgyalttal, csak a
fggvnyek paramterezse tr el tle.
Az attribtum ltrehozst s inicializlst vgz makr a kvetkez:
DEVICE_ATTR(n V,md, showfv ,storefv )
A makrval ltrehozott vltoz neve dev_attr_nv lesz.
Az attribtum virtulis llomnyt ltrehoz, illetve eltvolt fggv-
nyek az albbiak:
intdev ice_create_fi1e(structdev ice*dev ice,
conststructdev ice_attribute*entry );
v oiddev ice_remov e_fi1e(structdev ice*dev ,
conststructdev ice_attribute*attr);
435
7. fej ezet:Fej leszt saLinux-k ernelben
7.19.9. Plda
Az eszkzvezrlmodell hasznlatra nzznk egy nagyon egyszer pldt.
A pldban egy meglv buszhoz, a platformbuszhoz adunk hozz egy eszkz-
vezrlt. Majd mivel ez a busz rtelem szerint nem tudja rzkelni, hogy a
kpzeletbeli eszkznket csatlakoztattuk hozz, ltrehozunk egy eszkzt is:
/*dev attr.c-Egy szerudev iceextrasy sfsattributumok k al.*/
#include<linux/module.h>
#include<linux/k ernel.h>
#include<linux/platform_dev ice.h>
#defineDRV_NAME"dev attr"
staticinti=0;
/*Azattribtumlek rdezfggv ny e*/
staticssize_tshow_num(structdev ice*dev ,
structdev ice_attribute*attr,char*buf)
{
returnsprintf(buf,"%d\n",i);
/*Azattribtumbe ll tfggv ny e*/
staticssize_tstore_num(structdev ice*dev ,
structdev ice_attribute*attr,
constchar*buf,size_tcount)
sscanf(buf,"%d",&i);
returncount;
}
/*Azattribtum ssze ll t sa*/
DEv ICEATTR(num,S_IRUGO1S_IWUSR,show_num,store_num);
staticint_dev initdev attr_probe(structplatform_dev ice*pdev )
{
dev _info(&pdev ->dev ,"probe");
dev ice_create_file(&pdev ->dev ,&dev _attr_num);
return0;
staticint_dev exitdev attr_remov e(structplatform_dev ice*pdev )
{
dev _info(&pdev ->dev ,"remov e");
dev ice_remov e_file(&pdev ->dev ,&dev _attr_num);
return0;
43 6
7.19.Eszk zv ez rlmodell
staticstructplatform_driv ermy _driv er={
.probe=dev attr_probe,
.remov e= dev exit_p(dev attr_remov e),
.driv er={
.name=DRV_NAME,
.owner=THIS_MODULE,
}
};
staticstructplatform_dev ice*my _dev ;
staticint initmy _init(v oid)
{
interr;
err=platform_driv er_register(&my _driv er);
if(err)
returnerr;
my _dev =platform_dev ice_register_simple(DRv _NAmE,-1,NULL,0);
if(IS_ERR(my _dev ))
{
platform_driv er_unregister(&my _driv er);
returnP TR_ERR(my _dev );
return0;
staticv oid exitmy _exit(v oid)
{
platform_dev ice_unregister(my _dev );
platform_driv er_unregister(&my _driv er);
module_init(my _init);
module_exit(my _exit);
MODULE_DESCRIP TION("Dev iceattr");
MODULE_LICENSE("GP L");
Az eddig trgyalt fggvnyeken kvl a pldakd hasznlja a platformbusz
egy specilis eszkzt ltrehoz s regisztrl fggvnyt:
staticstructplatform_dev ice*platform_dev ice_register_simple(
constchar*name,intid,conststructresource*res,
unsignedintnum);
Erre a fggvnyre azrt van szksg, mert a virtulis platformbusz szmos
olyan eszkzt foglal magba, amelynek az rzkelse specilis, gy a rendszer
nem tudja rzkelni ezek csatlakoztatst. Ezrt a tbbi busztl eltren itt
manulisan is ltrehozhatjuk az eszkzket.
43 7
7. fejezet: Fejleszts a Linux-kernelben
A name paramterekben meg kell adnunk az eszkz nevt. Azonostk hi-
nyban fontos, hogy az eszkzt az eszkzmeghajtval azonos nven hozzuk
ltre, mert ez jelzi a kztk lv kapcsolatot.
Az id paramter tbb eszkz esetben az adott eszkz sorszmt tartal-
mazza. Ha csak egy eszkz szerepelhet a rendszerben, akkor az rtke 1.
A res paramter tartalmazza az eszkzhz allokland erforrsokat, mg
a num ezek szmt.
Ha manulisan hoztuk ltre az eszkzt, akkor az eltvoltsrl is gon-
doskodnunk kell. Ezt a kvetkez fggvnnyel tehetjk meg:
voi d pl atform_devi ce_unregi ster(struct pl atform_devi ce *pdev) ;
7.20. Tovbbi informcik
A clunk ezzel a fejezettel az, hogy az eszkzvezrl kernelmodulok fejleszt-
snl leggyakrabban hasznlt eszkzket, illetve leggyakrabban tapasztalt
problmkat bemutassuk. m szmos olyan tovbbi terlet maradt a kernel-
programozs tmakrben, amelyre nem trtnk ki. Az albbiakban nhny
forrst javasolunk, ahol az rdekld olvas tovbbi informcit tallhat a
munkjhoz. Viszont mg ezek a dokumentumok sem tartalmazzk a kernel
teljes lerst, hiszen a tma kiterjedtsge miatt ez majdnem lehetetlen fela-
dat. Vagyis biztosan maradnak olyan rszek, amelyet csak a kernel forrsbl
fejthetnk vissza.
A legels javasolt forrs nagyon hinyos s egyltaln nem rendszerezett,
m nhny informci csak itt lelhet fel. Ez pedig a kernelforrs Documenta-
tion knyvtra, amelyet korbban is emltettnk.
Olvasmnyosabb, de nmikppen elavult a http: //www.tldp.org/guides.html
cmen tallhat The Linux Kernel Module Programming Guide.
Tapasztalatunk szerint az egyik legjobb knyv a Linux Device Drivers,
Jonathan Corbet, Al essandro Rubini s Greg Kroah-Hartman tollbl.
Emellett kifejezetten rszletes tmutatt a kernel mkdsrl a Profes-
sional Linux Kernel Architecture cm knyvben tallhatunk.
Szmos online webes intormciforrst is tallhatunk. Kezd s kevsb
kezd kernelfejleszt'k szmra is kihagyhatatlan a http: / /kernelnewbies.org/
oldal.
Amikor a kernelforrst bngsszk, gyakran nehzkes tud lenni a hivatkoz-
sok kikeresse, lekvetse. Ebben nyjt nagy segtsget a http: / /lxr.linux.no/ ol-
dal, amely feldolgozza s linkek formjban egyszeren kezelhetv teszi a ke-
reszthivatkozsokat.
438
NYOLCADIKFEJEZET
A Qt keretrendszer
programozsa
8.1. Az X Window rendszer
Manapsg, ha egy opercis rendszer versenykpes szeretne lenni a piacon,
akkor ktsgkvl szksge van grafikus felhasznli felletre (Graphical
User Interface, GUI). A GUI egyrtelmen bartsgosabb s knnyebben kezel-
het, mint a szveges terminl. A Unix rendszerek s a Linux grafikus fellete
az X Window rendszer (vagy egyszeren X), amely hasonlan sok ms unixos
fejlesztshez egy akadmiai projekt eredmnye: az MIT-n fejlesztettk ki.
A Unix kezdetek ta rendelkezik a tbbfelhasznls (multiuser), a
tbbfeladatos (multitask) kpessgekkel, illetve a hlzatok elterjedse ta
tmogatja a tvoli bejelentkezst is. Az X architektrjt is gy alaktottk
ki, hogy illeszkedjen ebbe az elkpzelsbe.
Az X az Athena projekt keretben, 1984 -ben jtt ltre. 1988-tl az X kon-
zorcium felgyeli a fejlesztst s a terjesztst. Az X specifikcija szabadon
hozzfrhet, ezzel utat nyitottak az olyan ingyenes implementcik ltrejt-
tnek, amilyen pldul az XFree86 vagy az X.Org. Linux alatt is az utbbi
felletet hasznljuk, elterjedtsge azonban nem korltozdik kizrlag a Li-
nuxra, ms opercis rendszereken is (BSD, OS/2 ) hasznljk, st nevvel el-
lenttben ms CPU-architektrkon is.
8.1.1. Az X Window rendszer felptse
Az X-et kliens-szerver architektrjra alaktottk ki. Az alkalmazsok a kli-
ensek, amelyek kommuniklnak a szerverrel. Krseket kldenek, s infor-
mcikat kapnak. Az X szerver kezeli a kpernyt s a bemeneti eszkzket
(billentyzet, egr), a programok ezekhez nem frnek hozz, csak az X szer-
vert krik meg az egyes mveletek vgrehajtsra.
8. fejezet: A Qt keretrendszer programozsa
Ennek a megoldsnak az elnye egyrtelm: a kliensnek nem kell az
adott eszkz jellemzivel foglalkoznia, csak a szerverkommunikcit kell imp-
lementlnia. Ez pedig nem klnbzik attl, mintha csak egy grafikus knyv-
trat hasznlnnk.
m az X architektra ennl tovbb is megy. Nincs szksg arra, hogy a
kliens- s a szerveralkalmazs egy gpen fusson. A kliens-szerver kommuni-
kci hlzaton keresztl is megvalsthat brmilyen IPC-mechanizmussal,
amely megbzhat, adatfolyam-jelleg kommunikcit biztost.
Az X csomag tartalmaz egy fejleszti knyvtrat, az Xlib-et, amely az ala-
csony szint kliens-szerver kommunikcit implementlja. A programjaink-
ban csak ezeket a fggvnyeket kell hasznlnunk, hogy alkalmasak legyenek
arra, hogy X krnyezetben fussanak.
Amikor ablakos, grafikus felletet hasznlunk, akkor termszetes ig-
nynk, hogy a kliensablakokat kezelhessk: mozgathassuk, tmretezhessk,
minimalizlhassuk, maximalizlhassuk stb. Az X nem kezeli ezeket a mvele-
teket, ez a feladat az ablakkezelkre (Window Manager) vr. Az ablakkezel
dszti az ablakokat, illetve felletet biztost a felhasznlknak az ablakmve-
letekhez, de magukat az ablakmveleteket mr az X szerver implementlja.
Mivel az ablakkezel is csak egy kliensprogram, nem rsze az X szervernek,
gy kvnsg szerint cserlgethetjk, s szles vlasztkbl vlaszthatunk az
zlsnknek megfelelt.
Br az ablakkezel f feladata nevbl eredenden a kliensek ablakainak
a kezelse, emellett klnbz egyb funkcikkal is rendelkezhet. Az egyik
ilyen ltalnos funkci pldul a kliensprogramok indtsa.
8.1.2. X Windows kliensalkalmazsok
Ha az eddigi informciink alapjn vgunk neki az X-es alkalmazsunk fej-
lesztsnek az Xlib segtsgvel, hamar kiderl, hogy ez nem egyszer fela-
dat. Az Xlib csak a szksges alapokkal szolgl, s egy nyomgomb kiraksa,
szveg vagy egyb vezrlelem elhelyezse elg sszetett mvelet lehet.
110
Szerencsre a vezrlelemek nehzkes kezelse miatt ltrehoztak olyan
Xlib-re pl programozi knyvtrakat, amelyek egyszerbb teszik a fe-
ladatunkat. Ezeket a knyvtrakat widgetknyvtrnak (Widget Library)
nevezzk. Termszetesen hasznlatukkor nem ajnlatos az Xlib knyvtr
fggvnyeit kzvetlenl hvni, mert konfliktusba kerlhetnek egymssal.
Mivel ettl kezdve a widgetknyvtr felels minden elem megrajzolsrt
s kezelsrt, ezrt programunk kezeli felletnek jellemzi s viselkedse
nagyban fgg attl a knyvtrtl, amelyet vlasztottunk.
110
Az MS Windows alatti programozsban jratosakat leginkbb a Windows API absztrak-
cis szintjre emlkeztetheti.
4 4 0
8.1. Az X Window rendszer
Az els widgetknyvtr az Athena projekt keretben kifejlesztett Athena
knyvtr volt. Csak a legalapvetbb elemeket tartalmazza, s a vezrlele-
mek kezelse eltr a manapsg hasznlatosaktl. Az ezt kvet legismertebb
knyvtr az Open Software Foundation (OSF) Motif csomagja, amely 1980-tl
a korai 1990-es vekig volt elterjedt. A legkomolyabb hibja az, hogy slyos
sszegekbe kerl a fejleszti licenc. Manapsg mr vannak jobb alternatvk
rban, sebessgben, illetve szolgltatsokban. Ilyen pldul a Gtk, amely a
GIMP projekthez kszlt. Arnylag kicsi, sok szolgltatssal, bvthet, s
teljesen ingyenes. Vagy egy msik npszer eszkzkszlet, a Qt, amely a KDE
projekt ta ismert igazn, hiszen a KDE alapjt szolgltatja. A Qt keretrend-
szer s egy hozztartoz fejlesztkrnyezet ingyenesen hasznlhat, de lte-
zik fizets vltozata is, amely tovbbi szolgltatsokat s tmogatst biztost.
Tovbbi alternatva a LessTif, amely egy ingyenes API-kompatibilis helyette-
stje a Motifnak.
8.1.3. Asztali krnyezet
Kiderl teht, hogy felhasznlknt vlaszthatunk ablakkezelt kedvnk sze-
rint, s a programok ri is vlaszthatnak widgetknyvtrakat. Ennek a nagy
szabadsgnak azonban megvannak a htrnyai. A kliensprogram rja hat-
rozza meg, hogy milyen widgetknyvtrat hasznl. m mivel e knyvtrak
vezrlelemei nagyban klnbzhetnek, elfordulhat, hogy ahny programot
hasznlunk, annyiflekppen kell kezelni ket.
Ezek a widgetknyvtrak ltalban dinamikus programknyvtrakban
helyezkednek el, m ha a kliensprogramjaink klnbzket hasznlnak, ak-
kor ez tovbbi memrit ignyel.
Az ablakkezelk is sokflk, klnbz kezelsi koncepcikkal. Az egsz
fellet ennek kvetkeztben nem ll ssze egysges egssz. Nem lehet egy-
ben konfigurlni a kinzett, a kezelst.
Azrt trtnt ez gy, mert az X kialaktsa sorn a flexibilitsra s a fel-
hasznlk szabadsgra helyeztk a hangslyt, ellenttben egyb opercis
rendszerek (pldul a Windows s a MacOS) megktttsgeivel, zrtsgval.
m ez a fenti helyzethez vezetett, ezrt a szabadsggal szemben eltrbe ke-
rlt a komplex fellet ltrehozsa, s ez magval hozta az asztali krnyeze-
tek (Desktop Environment) kialakulst.
Az asztali krnyezet tartalmaz szolgltatsokat s mdszertanokat is,
amelyekkel a fellet egysgesthet, s a problmk lekzdhetk. Ugyanakkor
tbb fajtja is ltezik, s a vlaszts szabadsga gy megmarad. Az ismertebbek
a Motifra pl CDE (Common Desktop Environment), a Qt-alap KDE
(K Desktop Environment) s a Gtk-t hasznl GNOME. A tovbbiakban ezek
kzl a Qt programozst mutatjuk be, amely szles kr hordozhatsga s
hatkony felhasznlhatsga miatt az egyik legelterjedtebb krnyezet.
441
8. fejezet: A Qt keretrendszer programozsa
8.2. Fejleszts Qt alatt
A Qt (hivatalos kiejtse megegyezik az angol cute sz ejtsvel) egy C++ nyelv
keretrendszer platformfggetlen alkalmazsok programozsra. A keretrend-
szer rszt egy osztlyknyvtr s egy fejlesztkrnyezet kpezi. Az osztly-
knyvtr tmogatst nyjt tbbek kztt grafikus felhasznli felletek, a
tbbszl fejleszts, az I/O kezels, az erforrs-llomnyok, a hlzati kom-
munikci, az adatbzis-elrs programozsra. A Qt az opercis rendszerek
szles skljt tmogatja, tbbek kztt a Windows s Linux rendszereket, a
Mac OS platformot, a Symbian- s a Meego-alap mobileszkzket. Br a Qt
C++ nyelven kszlt, tbb nyelvhez ltezik mr programozsi fellete, gy a
Qt szolgltatsai elrhetk tbbek kztt Python, Java s PHP nyelveken is.
A 8.1. brn lthat, hogy a Linux-alap fejleszts esetn hogyan nz ki a
Qt keretrendszer segtsgvel fejlesztett alkalmazsok architektrja.
8.1. bra. Qt -architektra Linux platformon
Az opercis rendszerre pl a korbban bemutatott X Window (X11) ablakoz
rendszer, amely a grafikus megjelentst biztostja. Ezutn kvetkeznek a Qt
egyes komponensei, amelyeket moduloknak neveznk. A QtCore tartalmazza
a tbbi ltal is hasznlt alaposztlyokat, a QtGui pedig a grafikus felhaszn-
li fellethez szksges osztlyknyvtrat jelenti. A kt nagy alapkomponen-
sen kvl a tovbbi modulok kzl az adatbzis-elrst biztost QtSql s a
hlzatkezelst tmogat QtNetwork modulokat ebben a knyvben rszlete-
sebben is bemutatjuk.
442
8.2. Fejleszts Qt alatt
A Qt keretrendszer segtsggvel teht platformfggetlenl tudunk alkal-
mazsokat kszteni, a keretrendszer elfedi a klnbz opercis rendszereken
klnbsgeit. A Linux opercis rendszeren elrhet a KDE ablakoz rendszer,
amely maga is a Qt keretrendszeren alapul, s egy egysges krnyezet biztost-
sra az eszkzkszlett bvti. Ebben a knyvben a Qt alapszolgltatsait s fel-
ptst trgyaljuk, m ha valaki kifejezetten KDE-krnyezetben hasznlhat
alkalmazst fejleszt, akkor rdemes ennek a knyvtrnak a funkciit hasznlnia.
Ebben az esetben a Qt ltal biztostott hordozhatsgot valamilyen szinten elve-
sztjk, mert az alkalmazsok csak KDE knyvtraival egytt futnak.
8.2.1. Hello Vilg!
Bevezetsknt a kvetkez programban egy pldn keresztl bemutatjuk a
Qt kertrendszer hasznlatt s alapvet mkdst. Egy egyszer grafikus
felhasznli fellettel rendelkez alkalmazst hozunk ltre, amelynek a fel-
letn elhelyeznk egy Szveg:" feliratot, alatta egy szveg bevitelre alkal-
mas dobozt, illetve legalul egy Kilp" gombot. A felletrl egy kpernykpet
a 8.2. brn lthatunk.
8.2. bra. Hell Vilg" alkalmazsfellete
/* main.cpp */
#include <QAppl i cati on>
#include <Qmai nwi ndow>
#include <QVBoxLayout>
#include <Qt.abel >
#include <QTextEdi t>
#include <QPushButton>
443
8. fejezet: A Qt keretrendszer programozsa
int main(int argc, char * argv[])
f
QApplication app(argc, argv);
QWi dget*window=new QWi dget();
wi ndow->setWi ndowTitle("HellVil g");
QLabel*label=newQLabel("Sz v eg:");
QTextEdit*txtEdit=newQTextEdit();
QP ushButton*btn=newQP ushButton("Kil p");
QVBoxLay out*lay out=newQVBoxLay out();
window->setLay out(1 ay out);
1ay out->addWidget(1abel);
1ay out->addWidget(txtEdit);
lay out->addwidget(btn);
QObj ect::connect(btn,SIGNAL(click ed()),&app, sLoT(guit()));
window->show();
returnapp.exec();
}
A programunk egyetlen forrsllomnybl ll (main.cpp), ezen bell pedig a
main, fggvnyben hozzuk ltre a felletet. Az els ngy sorban az include
utastsok segtsgvel beptjk a Qt keretrendszerbl hasznlt osztlyok
definciit. Minden Qt-osztlyhoz egy kln headerfjl tartozik, amelynek neve
megegyezik az osztly nevvel. A keretrendszer sszes osztlynak neve ha-
gyomnyosan Q" betvel kezddik.
A main fggvnyben elszr egy QApplication objektumot hozunk ltre.
Ez az osztly felels az alkalmazs esemnykezel ciklusnak az elindts-
rt. Az esemnykezel ciklus fogadja tbbek kztt az ablakoz rendszertl
rkez esemnyeket, gy a felhasznli interakcikat is, amelyeket a megfelel
vezrl'khz tovbbt. Az esemnykezel ciklus addig fut, amg az alkalmazs
utols ablakt be nem zrjuk. (Az esemnykezelsre a ksbbiekben mg visz-
szatrnk.)
A Qt keretrendszerben az X Window rendszerhez hasonlan a grafi-
kus vezrlket widgeteknek nevezik. Minden grafikus elem a QWidget s-
osztlybl szrmazik. Egy alkalmazsban hasznlt vezrlket a keretrend-
szer automatikusan fastruktrba rendezi, vagyis minden elemnek pontosan
egy szlje s tetszleges szm gyereke lehet. Ezt a fastruktrt futs kz-
ben programozottan is be lehet jrni, benne a vezrlket tpus s nv alapjn
meg tudjuk keresni. A gyermekvezrlk mindig a szl terletn bell jelennek
meg. Az a vezrl, amelynek nincsen szlje, mindig egy nll alkalmazs-
ablakknt (top-level window) jelenik meg, ltalban ez azt jelenti, hogy sajt
fejlce (cmsora) s kerete van. A fenti kdban ltrehozott QWidget pldny
lesz az alkalmazs fablaka, mivel ennek nem adtunk meg szlt. A vezrl
setWindowTitle fggvnyvel adjuk meg az ablak cmt.
444
8.2. Fejleszts Qt alatt
A felleten a kvetkez tpus vezrlket helyezzk el:
QLabel (egyszer szveg kirsra),
QTextEdit (tbbsoros szvegbeviteli doboz) s
QPushButton (nyomgomb).
A vezrlk kialaktsa utn egy elrendezskezel (layout manager) objek-
tumot hozunk ltre, amelynek segtsgvel automatikusan elrendezzk a fe-
lletre elhelyezett elemeket. Az elrendezskezel felels a benne elhelyezett
vezrlk mretnek s pozcijnak automatikus lltsrt. Ez biztostja,
hogy pldul az ablak tmretezse utn is megfelelen legyenek elhelyezve
az elemek. A pldban hasznlt QVBoxLayout osztly fgglegesen egyms
al helyezi el azokat a vezrlket, amelyeknek az elrendezsrt felels. Egy
elrendezskezel objektumhoz az addWidget metdussal adhatjuk hozz az
elrendezend elemeket. A hozzads sorrendje termszetesen szmt, pldul
a QVBoxLayout ilyen sorrendben helyezi el a widgeteket egyms al.
A keretrendszerben az objektumok kztti kommunikcit az gynevezett
szignl-szlot mechanizmuson alapul esemnykezels teszi lehetv. Ennek
lnyege, hogy tetszleges, a QObject sosztlybl szrmaz osztly specilis
esemnytpusokat publiklhat, amelyeket szignloknak (signal) neveznk.
Egy adott esemnytpusbeli esemny bekvetkezst a szignl kibocstsval
(emit) jelezzk. Az esemnyekre specilis deklarcij fggvnyekkel, gyne-
vezett szlotokkal (s/ot) reaglhatunk. A szlotokat szintn a QObject sosz-
tlybl leszrmaz osztlyokban definilhatjuk. Ha egy szignlt sszektnk
egy szlottal, akkor valahnyszor kibocstjk a szignlt (jelzik a szignl ltal
reprezentlt esemnytpus egy konkrt elfordulst), a szlotfggvny meg-
hvdik. A fejleszts sorn a szignlfggvnyekhez nem ksztnk fggvny-
trzset, mert azt a Qt generlja helyettnk. A generlt fggvny biztostja,
hogy a szignllal sszekttt szlotfggvnyek meghvdjanak. A szlotfgg-
vny trzst termszetesen neknk kell definilni. Egy szignllal akr tbb
szlotfggvny is sszekthet, s egy szlotfggvnyt akr tbb szignllal is
sszekthetnk, az egyetlen megkts, hogy a szignlfggvny s a szlot pa-
ramterlistja megegyezzen. Amikor egy szignlt kibocstunk, a keretrend-
szer biztostja, hogy az sszes olyan szlotfggvny meghvdjon, amellyel a
szignlt sszektttk, s paramterknt megkapja a szignl kibocstsakor
megadott rtkeket. (A szignlok s a szlotok mkdst, valamint a keret-
rendszer esemnykezelsi modelljt lsd ksbb.)
Egy szignl s egy szlot sszektse a QObject osztly connect metdus-
val trtnik. A connect meghvsakor a SIGNALO s a SLOT() makrkat kell
hasznlni, hogy megadjuk a szignl- s a szlotfggvnyeket. A fenti pldban
a btn objektum clicked szignljt ktjk ssze a QApplication objektum quit
szlotjval az albbi fggvnyhvs segtsgvel:
QObj ect::connect(btn,SIGNAL(click ed()),&app,SLOT(quit()));
445
8. fejezet: A Qt keretrendszer programozsa
A QPushButton osztly ltal publiklt clicked szignl akkor kvetkezik be,
amikor a nyomgombot a felhasznl megnyomja. A Qt keretrendszer bizto-
stja, hogy ha a felhasznl az egrrel egy nyomgomb hatrain bell kattint,
akkor a nyomgomb megkapja ezt az zenetet. Ha a nyomgomb engedlyez-
ve van, kibocst egy clicked szignlt. Ezzel a szignllal kell sszektnnk
azokat a fggvnyeket, amelyek meghvst ki szeretnnk vltani a kattin-
tst jelz esemnnyel. Vagyis a kattintsesemny kezelshez a programoz-
nak csak egy szlotfggvnyt kell ltrehoznia s azt sszektnie a szignllal.
Brmilyen felhasznli beavatkozs esetn a Qt keretrendszer feldolgozza az
opercis rendszertl jv rtestst, ezek bekvetkezst pedig a vezrlk
szignlokkal jelzik.
A quit fggvny kilp az alkalmazsbl. Ezt a fggvnyt a QApplication
osztly szlotknt publiklja A szignl s a szlot sszektse biztostja, hogy
amint rkattintunk a gombra, az alkalmazs azonnal bezruljon.
Minden vezrl lthatatlan a ltrehozs pillanatban, amg meg nem hv-
juk rajta a show metdust. A pldban a fablakot jelentjk meg, amely gon-
doskodik arrl, hogy az sszes tartalmazott vezrl ugyancsak megjelenjen.
A main fggvny utols sorban elindtjuk az alkalmazsobjektum esemny-
kezel ciklust az exec fggvny segtsgvel. Ez akkor r vget, amikor meg-
hvdik az alkalmazs quit fggvnye, a ciklus mindaddig fogadja s tovbbtja
a felhasznli esemnyeket
Az egyetlen main.cpp forrsllomny megrsa utn a kvetkez lps a
program lefordtsa. A Qt keretrendszerben minden programhoz egy platform-
fggetlen projektllomny tartozik, amelynek kiterjesztse .pro. Ez az llo-
mny tartalmazza tbbek kztt a programhoz kapcsold forrsfjlok listjt.
A projektllomnyt a qmake programmal hozhatjuk ltre:
Az llomny neve a forrskdot tartalmaz knyvtr neve lesz.
A projektllomnyokbl szintn a qmake segtsvel tudunk platformspe-
cifikus make llomnyokat generlni:
A generlt make llomnyok segtsgvel az adott platformon elrhet ford-
tval mr a hagyomnyos mdon generlhatjuk a vgrehajthat programot:
make
446
8.2 .Fej leszt sQtalatt
8.2.2. Projektllomnyok
Az elz pldban elksztettnk egy egyszer Qt-alap grafikus alkalma-
zst, az albbiakban a program fordtst vizsgljuk meg rszletesebben.
A lert fordtsi folyamatnak kt Qt keretrendszer specifikus pontja van:
a .pro kiterjeszts projektllomny megrsa s
a platformspecifikus make llomnyok generlsa a qmake programmal.
Ezeket a feladatokat az integrlt fejleszti krnyezetek automatikusan el tudjk
vgezni, de azrt rdemes megismerkedni a projektllomnyok szerkezetvel.
A projektllomnyt megrhatjuk mi magunk is, de a qmake segtsgvel
generlhatjuk is a project kapcsol hasznlatval (lsd az elz pldban).
A korbbi, egyetlen main.cpp llomnyt tartalmaz programhoz a qmake
a kvetkez projektfjlt generlja:
##################################################################
# Automatically generatedby qmak e(2 .01a)P j l.113 :07:412 011
##################################################################
TEMP LATE=app
TARGET=
DEP ENDP ATH+=
INCLUDEP ATH+=.
# Input
SOURCES+=main.cpp
A projektllomnyok legfontosabb rszei a kvetkezk:
A # jellel kezdd sorok megjegyzsek, ezeket a feldolgozsnl a
qmake nem veszi figyelembe.
A megjegyzsek utni els sorban a TEMPLATE vltoznak adunk
rtket, ez ltalban app vagy lib lehet. Az app jelzi, hogy egy nll
futtathat alkalmazst akarunk generlni a projektbl, a lib pedig,
hogy egy programknyvtrat.
A TARGET vltozban megadhatjuk a generland file nevt (kiter-
jeszts s verziszm nlkl), res rtk esetn az alaprtelmezett
nv a projektllomnyt tartalmaz knyvtr neve.
A DEPENDPATH s az INCLUDEPATH vltozk rtkei troljk
azoknak a knyvtraknak a neveit, ahol a nem a projekthez tartoz,
de hivatkozott headerfjlokat s programknyvtrakat kell keresnie a
fordtnak.
447
8. fejezet: A Qt keretrendszer programozsa
A SOURCES vltoznl soroljuk fel a fordtand forrsllomnyokat.
Amennyiben klnll headerfjljaink is lennnek, azokat a HEADERS
utn kellene felsorolni.
A fenti vltozk esetben gyakran nemcsak egy, hanem tbb nevet is fel kell
sorolni, ilyenkor ezeket szkzzel elvlasztva rjuk le. Ha egy sor tl hossz,
akkor a \ jellel trhetjk, s j sorban folytathatjuk. Egy tovbbi lehetsg
az, hogy a += opertor segtsgvel lehet egy vltozhoz hozzfzni jabb r-
tket, ezt tbbszr is meg lehet tenni egyms utn. Az albbi pldban mind-
hrom lehetsget megmutatjuk:
SOURCES =sourcel.cppsource2 .cpp\
source3 .cpp
SOURCES +=source4.cpp
SOURCES +=source5.cpp
Egy projektllomny teht egy Qt-projektet r le, ahol a projekt tartalmazza a
generland alkalmazs vagy programknyvtr nevt, az sszes fordtand
forrsllomnyt s azokat a knyvtrakat, ahol a fordtshoz szksges hi-
vatkozott programknyvtrak megtallhatk. A projektllomny mindezeket
az informcikat platformfggetlen formban trolja.
A projektllomny megrsa utn, a qmake parancs kiadsval (a pro-
jektllomnyt tartalmaz knyvtrban) a projektllomnybl generlunk egy
platformspecifikus make llomnyt, amelyet mr hagyomnyosan tudunk
fordtani.
8.2.3. A QObject szolgltatsai
A Qt keretrendszer olyan specilis konstrukcikat biztost, amelyek lehetv
teszik az objektumok kztti hatkony kommunikcit (szignl-szlot mecha-
nizmus) s a metaadatokhoz val hozzfrst. A keretrendszer alaposztlya a
QObject. Ennek pldnyait a keretrendszer fastruktrba rendezve trolja,
amely programozottan bejrhat futs kzben, gy az objektumok kereshetv
vlnak. A Qt lehetv teszi olyan tulajdonsgok (property) definilst, ame-
lyek futsi idben lekrdezhetk.
A fenti szolgltatsok egy rszt hagyomnyos C++-technikkkal vals-
tottk meg, de bizonyos kiterjesztsek (pldul a szignl-szlot mechanizmus)
szksgess teszik egy specilis elfordt, a moc (Meta-Object Compiler)
hasznlatt. (A moc mkdsre a Qt esemnykezels-modelljnek trgyal-
snl visszatrnk.)
448
8.2. Fejleszts Qt alatt
8.2.4. A QtCore modul
A Qt keretrendszer nem csak grafikus felletek fejlesztshez szksges ve-
zrlket tartalmaz osztlyknyvtrat knl. Sok olyan osztly tallhat ben-
ne, amely a felhasznli fellettl fggetlen programozi interfszt biztost,
tbbek kztt pldul adatbzisok elrsre, hlzati kommunikci rsra
vagy tbbszl programozsra.
Amikor egy forrsfjlban a keretrendszer egyik osztlyra hivatkozunk,
akkor ehhez az include utastssal be kell pteni a megfelel osztlyt. A be-
ptend llomny neve megegyezik az osztly nevvel. A kvetkez sor szk-
sges ahhoz pldul, hogy a QApplication osztlyt tudjuk hasznlni a k-
dunkban:
<t Lica
A Qt keretrendszer knyvtra modulokra van osztva, ezek kzl az egyik a
grafikus komponenseket tartalmaz modul, a neve QtGui. Ha nem szeretnnk
egyenknt az sszes osztlyra gy hivatkozni, lehetsg van modulonknt be-
pteni a keretrendszer osztlyait, ekkor ltalban az adott modul nevt kell
kirni, pldul a grafikus modul esetben a kvetkezkppen:
#inclucte QtGui
Az gynevezett alapmodul a QtCore nevet viseli, ebben azokat az osztlyokat
definiltk, amelyeket az sszes tbbi modul hasznl. Ebben tbbek kztt ta-
llunk:
bonyolultabb adattpusok lersra szolgl osztlyokat (szveg
QString, dtum, idpont QDate, QDateTime, QTime, tglalap
QRectangle),
sablonalap gyjtemnyeket (lista QList, halmaz QSet, asszociatv
tmbk QHash, QMap),
szinkronizcis objektumokat (szemafor QSemaphore, mutex
QMutex),
tbbszl programozshoz szksges osztlyokat (QThread, QThread-
Pool, QTimer),
I/O kezelshez szksges osztlyokat (knyvtr QDir, fjl QFile,
QFilelnfo).
Az egyik fontos osztly, amelyet ebben a fejezetben nagyon gyakran haszn-
lunk, a QString, amellyel 16 bites unicode karaktersorozatokat trolunk.
Egy-egy karaktert a QChar osztllyal runk le, ezek gyjtemnye alkot egy
QStringet. Egy QString inicializlshoz tbb mdszert is vlaszthatunk.
449
8. fejezet: A Qt keretrendszer programozsa
Ltrehozhatjuk valamilyen szvegkonstans- (const char * tpus) kezdetir-
tkkel, de a karaktereket megadhatjuk egyenknt is. A szoksos indexelssel
lekrdezhetjk s mdosthatjuk az egyes karaktereket, illetve tovbbi fggv-
nyek is rendelkezsre llnak a szvegek mdostsra (append hozzfzs,
prepend elfzs, replace helyettests). Lehetsg van tovbb ms ka-
rakterkdols (Latin-1, ASCII, UTF8) szvegekkel val egyttmkdsre is:
A QString osztly hasznlatban fontos megemlteni a QStringBuilder osz-
tlyt, amellyel hatkonyan lehet szvegkonstansokat sszefzni. Ezt az osztlyt
explicit mdon nem kell pldnyostani, elg, ha beptjk a programunkba a
kvetkez utastssal:
r;01,00,
Ezutn a szvegek sszefzsre a % opertort hasznlhatjuk a szoksos +
opertor helyett. Ez a mdszer optimalizlja a szvegek msolsval jr
tbbszrs memriafoglalst:
#include <Q5tri ngsuilder>
QStringmessage = "hello " %"v il g"; //hatkony sszefzs
8.3. A Qt esemnykezels-modellje
A grafikus felhasznli fellet programozshoz egy j szemlletet kell k-
vetnnk, ennek a neve esemnyvezrelt programozs (event driven prog-
ramming). Mr az elz fejezetekben is tallkoztunk azzal a problmval,
amikor a program bemenetre vrva blokkoldik egy adott ponton. Pldul a
socketek esetben a recv fggvny addig blokkolt llapotban marad, amg
adat nem rkezik. Ez utbbi azrt okoz problmt, mert a programunk nem
tud ms feladatot elltni, amg a recv fggvny vissza nem tr. Ennek kezel-
sre tbb technikt is bemutattunk. Az sszes hatkony megolds abbl llt,
hogy megadtuk, milyen esemnyekre szeretnnk reaglni, majd a program
vrakoz llapotba kerlt, ahonnan valamelyik esemny bekvetkezse bil-
lentette ki. Erre a logikra ptve az egsz alkalmazst eljutunk az esemny-
vezrelt programozshoz.
450
8.3. A Qt esemnykezels-modellje
A recv blokkoldsnak egyik megoldsa volt pldul a select fggvny
hasznlata. A select fggvnynek meg kellett adni olyan lerkat, amelyekkel
megmondtuk, hogy milyen eszkzk (hlzat, szabvnyos beviteli eszkz stb.)
milyen jelleg esemnyeirl (pldul rs, olvass) szeretnnk rteslst kap-
ni Amikor a select visszatrt, megvizsgltuk, hogy milyen esemny trtnt,
majd ennek megfelelen reagltunk. Ez a megolds az esemnyvezrelt prog-
ramozsnak egyfajta megvalstsa:
megadjuk, hogy milyen esemnyekrl szeretnnk tudomst szerezni,
ha valamilyen esemny rkezik, arra reaglunk.
A modern GUI-krnyezetek ltalban nyjtanak valamilyen tmogatst az
esemnyvezrelt szemllet programozsra (ilyen pldul a Qt szignl-szlot
modellje), gy a select utni esetsztvlasztst maga a krnyezet biztostja.
Neknk csak azt kell megmondani, hogy milyen esemnyt szeretnnk leke-
zelni, s melyik kdrszlettel.
Az esemnyvezrelt programozssal teht egyszerre tbb beviteli eszkzt
is kezelhetnk, ugyanakkor az zenetkezelkben sztszrt kdokkal a prog-
ram megszokott szekvencilis futst elvesztettk, s ez egyttal bonyolul-
tabb is teszi az esemnyvezrelt programot a hagyomnyos, eljrsvez-
relt (procedure driven) szemllettel szemben.
Az esemnyvezrelt programozs megvalstsakor egy esemnykezel
ciklus indul el, amelyben a keretrendszer fogadja a klnbz tpus zene-
teket. Ezek az zenetek lehetnek az opercis rendszertl jv rtestsek
pldul valamilyen hardveresemnyrl, de lehetnek a sajt programunkban
definilt esemnyek (szignlok), amelyeket mi magunk kldnk. Az gy rke-
zett esemnyek egy vrakozsi sorba kerlnek. Az esemnykezel ciklus
folyamatosan fut, s sorban olvassa be az rkezett zeneteket, majd azok tar-
talmtl fggen hvja meg pldul az ltalunk megadott fggvnyeket.
A program befejezshez a ciklust kell lelltani, erre a keretrendszerek lta-
lban biztostanak valamilyen fggvnyt.
A Qt keretrendszer biztostja az esemnykezel ciklust, tovbb egy ese-
mnyvezrelt programozsi modellt, a szignl-szlot mechanizmust (lsd az els
pldnl). A QPushButton osztlynl lttuk, hogy a szignl-szlot mechanizmu-
son alapul a felhasznli fellet programozsa is. Az egyes vezrlelemeket
megvalst osztlyok szignlokat definilnak, ezekre rkapcsoldva tetszle-
ges felhasznli esemnyrl rteslhetnk. A rkapcsolds azt jelenti, hogy
megadunk egy fggvnyt (szlot), amely az esemny bekvetkeztekor megh-
vdik. A ksbbiekben bemutatjuk, hogyan lehet olyan osztlyt definilni,
amely maga is publikl szignlokat, illetve szlotokat.
Az esemnyeket a szignlok reprezentljk, az esemnyek kezelse pedig
a szlotokkal trtnik. Neknk kell kivlasztani, hogy mely szlotokkal mely
szignlokra akarunk feliratkozni, ezt nevezzk egy szignl s egy szlot ssze-
kapcsolsnak: erre a QObject osztly connect fggvnyt hasznljuk.
451
8. fejezet: A Qt keretrendszer programozsa
A szignlt publikl objektum felels a szignl kibocstsrt Amikor a
jelzs megtrtnik, az sszes olyan szlot meghvdik, amelyet korbban sz-
szekapcsoltunk a szignllal. A szignl kibocstsa utn ltalban azonnal
vgrehajtdik a szlotfggvny, s a vezrls a fggvny vgeztvel tr csak
vissza a kibocsts utni kdra. Ha tbb szlotfggvnyt ktttnk be, akkor
azok szekvencilisan egyms utn futnak le. Ez a mkds teht teljesen
fggetlen az esemnyfeldolgoz ciklustl, nem zenetek segtsgvel jelezzk,
hogy a szlotfggvnyeknek meg kell hvdniuk, hanem a szignl kibocstsa-
kor kzvetlenl hvdnak meg.
Lehetsg van azonban gynevezett vrakozsisor-alap sszektte-
tst definilni (queued connection), ilyenkor a szignl kibocstst egy esemny
jelzi, amely bekerl az esemnyfeldolgoz ciklusba. A szignl kibocstsa utn
azonnal visszatr a vezrls a kibocsts utni sorra, a szlotfggvnyeket pe-
dig az esemnykezel ciklus hvja meg az adott esemny feldolgozsakor.
A ktfle megolds kzl a connect fggvny paramtereivel lehet vlasztani
(ezeket lsd ks'bb rszletesen). Fontos azonban, hogy tbbszl alkalmaz-
soknl, amikor a kibocst szl klnbzik attl a szltl, amelyben a szlotot
publikl objektumot hoztuk ltre, automatikusan vrakozsisor-alap sz-
szekttetst hasznl a rendszer. A Qt ugyanis lehetv teszi, hogy minden
szl sajt esemnykezel ciklussal rendelkezzen.
A szignl-szlot mechanizmus bizonyos rtelemben fggetlen a szignlt, il-
letve a szlotot tartalmaz objektumtl. A szlotfggvny, amely egy bizonyos
szignlt kezel, a program brmelyik objektumban elhelyezkedhet. A szignlt
kld objektumnak semmit nem kell tudnia a szlotfggvnyrl vagy arrl, hogy
melyik objektumban van, st a kt objektum klnbz szlakban is futhat.
Tovbb a jelzs kibocstsakor azzal sem kell foglalkozni, hogy egyltaln
iratkozott-e fel egyetlen szlotfggvny is.
Br a szignl-szlot modell elsdleges funkcija az esemnykezels, hasznl-
hat objektumok kztti kommunikcira is, pldul, amikor egy alkalmazson
bell kt ablaknak kell kommuniklnia egymssal. Ez a mdszer egyszerbb,
mint pointerekkel elrni a msik objektumot s gy hvni publikus tagfggv-
nyeket. A httrben hosszabb mveleteket vgz szlak tipikusan szignlokon
keresztl kommuniklnak a felhasznli fellettel.
8.3.1. Szignlok ltrehozsa
Ha egy osztlyban szignlokat vagy szlotokat szeretnnk definilni, akkor
ennek a QObject osztlybl kell kzvetve vagy kzvetetten leszrmaznia.
Ezen kvl az osztly defincijban el kell helyeznnk a Q_OBJECT makrt.
452
8.3. AQt esemnykezels-modellje
/*textcontent.h*/
#ifndefTEXTCONTENT_H
#defineTEXTCONTENT_H
#include<Q0bj ect>
#include<QString>
classTextContent:publicQObj ect
{
Q_OBJECT7/ k telezQ_OBJECTmak r
public:
v oidsetText(constchar*newText);
signals:
v oidtextChanged(constchar*newText);
priv ate:
QString*text;
};
#endif//TEXTCONTENT_H
A fenti headerfjlban deklarlt TextContent nev osztly egy tetszleges sz-
veg trolsra szolgl. A szveget egy QString tpus tagvltozban (text) t-
roljuk. Egy szignlt is definiltunk, ennek a neve textChanged, ezzel jelezzk,
ha a tartalmazott szveg megvltozott. Az adott fggvny attl lesz szignl,
hogy a signals:" kulcssz utn szerepel a deklarciban. A szignlok mindig
publikusak, a lthatsgukat nem befolysolhatjuk.
A szignl kibocstsakor azt is tudatni szeretnnk, hogy mi az j szveg,
ezrt a textChanged fggvny egy char * tpus paramterrel rendelkezik.
A szignl-szlot mechanizmus ersen tpusos, azaz egy szignlra csak azzal
azonos paramterlistj szlotfggvnyekkel lehet feliratkozni Amikor a szig-
nl kibocstsval jelezzk, hogy a szveg megvltozott, akkor az sszes hoz-
zkapcsolt szlotfggvny meghvdik, mindegyik megkapja paramterknt a
kibocstskor megadott rtket. A szlotfgvnyek, azon kvl, hogy sszekt-
hetk szignlokkal, hagyomnyos fggvnyekknt is felhasznlhatk, ezrt
a szlotoknak lehet visszatrsi rtke is. m a szlotok visszatrsi rtkhez
a szignl kibocstsa utn nem frnk hozz, csak akkor, ha hagyomnyos
fggvnyknt hvtuk meg ket. Mivel a szlotok egyszer fggvnyek, gy vir-
tuliss tehet'k, s a leszrmazott osztlyokban felldefinilhatk.
A TextContent osztlynak csak a setText metdust kell implementl-
nunk. A szignlokhoz nem tartozik kln implementci pontosabban ezt
nem mi ksztjk el , hiszen a szignlok segtsgvel csak jelezzk, hogy az
adott esemny bekvetkezett, a bekttt szlotok meghvsrl a keretrend-
szer automatikusan gondoskodik:
453
8.fej ezet:AQtk eretrendszerprogramoz sa
/*textcontent.cpp*/
#include"textcontent.h"
v oidTextContent::setText(constchar*newText){
text=newQString(newText);
emittextChanged(text->data());
A setText metdusban kell frissteni a trolt szveget s a textChanged jelzst
leadni, vagyis a textChanged szignlt kibocstani. Ennek a szintaktikja a
kvetkez:
emit<szign l_fggv ny >(argumentumok >);
vagyis az emit kulcssz utn a szignlfggvnyt hvjuk meg a megfelel pa-
ramterrtkek tadsval.
8.3.2. Szlotfggvnyek ltrehozsa
A programunkban szksg lesz egy msik osztlyra is, amelynek a szlotjt sz-
szekthetjk a textChanged szignllal. A ContentWatcher osztly segtsgvel
egy TextContent tpus objektumot figyelhetnk meg, gy, hogy feliratkozunk
arra a szignlra, amely az adott objektum szvegnek a megvltozst jelzi:
/*contentwatcher.h*/
#ifndefFILEWATCHER_H
#defineFILEWATCHER_H
#include<Q0bj ect>
#include<textcontent.h>
classContentWatcher:publicQObj ect
{
Q_OBJECT
publicslots:
v oidcontentChanged(constchar*newText);
1;
#endif//FILEWATCHER_H
454
8.3 .AOtesem ny k ezel s-modellj e
/*contentwatcher.cpp*/
#include"contentwatcher.h"
#include<iostream>
v oidContentwatcher::contentChanged(constchar"newText){
std::cout"Contenthaschanged:"newText;
}
A ContentWatcher osztly definil egy contentChanged szlotfggvnyt. A szlo-
tokat mindig a slots:" utn soroljuk fel. A szlotok mindig publikusak, akr-
csak a szignlok, ennek ellenre mgis adhatunk meg lthatsgot, ennek
azonban csak akkor van jelentsge, ha a szlotot mint hagyomnyos fggvnyt
hasznljuk. A contentChanged paramterlistja megegyezik a Text Content osz-
tlyban definilt textChanged szignl paramterezsvel. A szlotfggvny
i mplementcijban egyszeren kirjuk a konzolra a megvltozott szveget.
8.3.3. Szignlok s szlotok sszekapcsolsa
Egy szignlt s egy szlotot a mr korbban ltott connect fggvnnyel kap-
csolhatunk ssze:
#incl ude<Q0bj ect>
boolQObj ect::connect(
constQObj ect* sender,
constchar* signal,
constQObj ect* receiver,
constchar*method,
Qt::ConnectionTy pe type = Qt::AutoConnection)
Paramterei a kvetkezk:
sender: Arra az objektumra mutat pointer, amelytl a szignl szr-
mazik.
signal: A kezelend szignl. A sender objektumnak kell kldenie.
receiver: Arra az objektumra mutat pointer, amelynek fogadnia kell
a szignlt.
method: A receiver szlotfggvnye, amely lekezeli a szignlt.
type: Az utols paramterrel a kapcsolds tpust lehet belltani.
Lehetsges rtkeit a 8.1. tblzatban soroljuk fel.
455
8. fejezet: A Qt keretrendszer programozsa
8.1. tblzat. A szignlok s a szlotok sszekapcsolsnak tpusai
(a Qt::ConnectionType rtkei)
Tpus Lers
Qt:.AutoConnection Ez az alaprtelmezett tpus. Ilyenkor a rendszer au-
tomatikusan vlaszt aszerint, hogy a szignlt publi-
kl s a szlotot definil objektumok egy szlban
vannak-e Ha igen, akkor a DirectConnection tpus
szerint a szignl kibocstsakor a szlot kzvetlenl
hvdik meg, ha nem, akkor a QueuedConnection
tpus szerint a szignl bekerl a msik szl ese-
mnykezel ciklusnak vrakozsi sorba.
Qt::DirectConnection
A szlotot azonnal meghvjuk, amikor a szignlt ki-
bocstjuk.
Qt::QueuedConnection
A szignlt akkor hvja meg a keretrendszer, amikor
a szlotfggvnyt tartalmaz objektum szlnak az
esemnykezel ciklusa feldolgozza a szignl hat-
sra kldtt zenetet.
Qt::BlockingQueuedConnection Ugyangy mkdik, mint a QueuedConnection,
csak a szignl kibocstsakor a kld szl blokko-
ldik, amg a szlot fggvny le nem fut. (Csak k-
lnbz szlak esetn hasznlhat.)
Qt:: UniqueConnection Ugyangy mkdik, mint az AutoConnection, de
csak akkor trtnik meg az sszekapcsols, ha az
korbban mg nem ltezett. Teht a rendszer biz-
tostja, hogy egy objektum egy szignljt egy msik
objektum egy szlotjval csak egyszer lehessen sz-
szekapcsolni.
Amikor egy szignl hatsra meghvdik egy szlotfggvny, ezen bell fontos
lehet tudni, hogy melyik objektum kldte a jelzst. A megolds a QObject osz-
tly sender fggvnye:
;cn*,-,
Ez a fggvny egy szignl hatsra meghvott szlotfggvnyben a szignlt
kld objektummal tr vissza, egybknt pedig 0-val.
Ahhoz, hogy az elbbi kt osztlyban definilt szignlt s szlotot hasznl-
ni tudjuk, a QObject osztly connect fggvnynek segtsgvel a kt osztly
egy-egy pldnyn ssze kell ktni a fggvnyeket, ezt a pldnkban az al-
kalmazs main fggvnyben tesszk meg. Az alkalmazsunk harmadik for-
rsllomnya a main fggvnyt tartalmaz main.cpp. Ebben felhasznljuk a
TextContent s a ContentWatcher osztlyainkat, mindkettt pldnyostjuk,
majd sszektjk a megfelel szignlt s szlotot:
4 56
8.3 .AQtesem ny k ezel s-modellj e
/*main.cpp*/
#include<iostream>
#include<textcontent.h>
#include<contentwatcher.h>
intmain(intargc,char*argv [])
{
TextContent*content=newTextContent();
ContentWatcher*watcher=newContentWatcher();
QObj ect::connect(content,SIGNAL(textChanged(constchar*)),
watcher,SLOT(contentChanged(constchar*)));
content->setText("Hellszign l-szlot!");
return0;
}
A program lefordtshoz szksg van egy .pro kiterjeszts projektllo-
mnyra, amelyet ismt automatikusan generlhatunk a qmake-kel, vagy
megrhatjuk manulisan is:
#watchDog.pro
TEMP LATE=app
SOURCES+=main.cpp\
textcontent.cpp\
contentwatcher.cpp
HEADERS+=\
textcontent.h
contentwatcher.h
Ezutn mr csak a make llomny ellltsa s a make program meghvsa
hinyzik a projekt lefordtshoz:
qmak eWatchDog.pro
mak e
8.3.4. Szlot az tmeneti objektumokban
Ha egy szlotfggvny olyan objektumban helyezkedik el, amelyet csak tme-
netileg hasznlunk, akkor szksg lehet a ltrehozott szignl-szlot kapcsola-
tok megsemmistsre. A szignl-szlot sszekttetseket a QObject osztly
disconnect fggvnyvel kapcsolhatjuk szt:
boolQObj ect::di sconnect
constQObj ect* sender,
const char * signal,
const QObj ect receiver,
const char* method )
457
8.fej ezet:A Qt k eretrendszerprogramoz sa
A sender paramter ltal tartalmazott egyik szignlrl (signal) lecsatlakoztat-
juk a receiver egyik szlotjt (s/ot). Ha a signal vagy a slot paramternek 0 rt-
ket adunk meg, akkor ez az sszes szignl vagy sz/ot lecsatlakoztatst jelenti.
A szignlt kibocst objektum nem tud arrl, hogy a szignlhoz milyen
szlotfggvnyek csatlakoztak, illetve csatlakoztak-e egyltaln, ezzel teht nem
kell foglalkozni a szignl kibocstsakor. Elfordulhat, hogy egy korbban sz-
szekapcsolt szlotfggvnyt tartalmaz objektumot idkzben mr trltnk a
memribl. A Qt keretrendszer gondoskodik rla, hogy a trlt objektum
destruktorban sztkapcsolja az objektum szlotjaihoz tartoz kapcsolatokat,
gy ez nem okoz hibt a futs sorn.
8.3.5. A Meta Object Compiler
A szignl-szlot mechanizmus trgyalsakor szmos olyan j nyelvi elemmel
tallkoztunk a forrsllomnyokban (pldul slots, signals, emit), amelyek
nem felelnek meg a C++ nyelv szintaxisnak. Tovbb a szignlokat a fgg-
vnyekhez hasonl szintaktikval deklarltuk, implementcit mgsem r-
tunk hozzjuk.
A Qt keretrendszer egyrszt makrkat biztost a fenti kulcsszavak helyettes-
tsre, gy a C++-fordt szmra rtelmezhet lesz kd, msrszt egy elfordtt
hasznl, amellyel az osztlyhoz kiegszt kdot generl. Ez az elfordt a ko-
rbban mr bemutatott moc, amely feldolgoz minden olyan headerllomnyt,
amelyben a Q_OBJECT makr szerepel. A feldolgozs sorn ezekhez a header-
llomnyokhoz egy moc_<headerllomnynv>.cpp nev llomnyt kszt. Ez
tartalmazza az osztlyokhoz tartoz metainformcikat s a szignlok imple-
mentcijt. A linkelskor az ltalunk rt forrskdok mellett ezeket az llo-
mnyokat is fel kell hasznlni. A moc hasznlata a qmake programmal teljesen
ttekintheten trtnik, gy a fenti fordtsi lpsekkel kzvetlenl nem kell
foglalkoznunk
A fentiek illusztrlsra nzzk meg, hogy milyen lpsekbl ll az elz
WatchDog elnevezs programunk fordtsa. (Az itt bemutatott kimenet nem
teljes, a knnyebb olvashatsg kedvrt a fordt hvsakor megadott kap-
csolk kzl csak az llomnyok nevre vonatkozkat hagytuk benne, gy hi-
nyoznak pldul a belinkelt programknyvtrak.)
g++-c-omain.omain.cpp
g++-c-otextcontent.otextcontent.cpp
g++-c-ocontentwatcher.ocontentwatcher.cpp
/usr/bin/moc-qt4textcontent.h-omoc_textcontent.cpp
g++-c-omoc_textcontent.omoc_textcontent.cpp
/usr/bin/moc-qt4contentwatcher.h-omoc_contentwatcher.cpp
g++-c-omoc_contentwatcher.omoc_contentwatcher.cpp
g++-owatchDogmain.otextcontent.ocontentwatcher.o
moc_textcontent.omoc_contentwatcher.o
458
8.4. Ablakok s vezrlk
A cpp llomnyokat a fordt hagyomnyosan fordtja le. A moc segtsgvel
minden headerllomnybl ellltunk egy msik cpp forrsllomnyt, ezeket
ugyancsak lefordtjuk, majd a linkelskor felhasznljuk, s beptjk a vgle-
ges programba.
8.4. Ablakok s vezrlk
Az albbiakban a grafikus felhasznli fellet programozst vizsgljuk meg
rszletesebben. A Qt keretrendszerben a felhasznli felleten megjelen ve-
zrlk mindegyike a QWidget sosztlybl szrmazik. Ez az osztly kezeli az
ablakoz rendszert) rkez felhasznli esemnyeket, tovbb az ltalnos
ablakjellemzket, s nyilvntartja a szl-gyermek viszonyokat. Az ablak
esemnyei lehetnek mretvltozssal vagy thelyezssel kapcsolatosak, va-
lamint a felhasznl beavatkozsnak az eredmnyei. Az esemnykezels a
szignl-szlot mechanizmuson alapul. A vezrlket az els pldban ismerte-
tett elrendezskezel objektumok segtsgvel ltalban automatikusan
rendezzk el egy szln bell, gy a felletek knnyen tudnak alkalmazkodni
az ablak tmretezshez.
A vezrlket szigor fastruktrba rendezzk, az a vezrl, amelynek
nincsen szlje, nll ablakknt jelenik meg. A gyermek mindig a szl fel-
letn helyezkedik el, a szlwidget ltal behatrolva.
Az ablakoknak alapveten ktfle tpusa van: a dialgusablakok s a ha-
gyomnyos alkalmazsablakok. Egy grafikus fellettel rendelkez alkalma-
zsnak tipikusan van egy fablaka, ahol eszkzsorokat s menket helyeznk
el itt tudjuk szerkeszteni a megnyitott dokumentumokat , s tbb dial-
gusablaka, amelyek kiegsztik a fablak funkciit.
A dialgusablakok a QDialog osztlybl szrmaznak. A dialgusablakokat az
egyszerbb felletek megjelentsre hasznljuk, van gynevezett visszatrsi
rtkk. A visszatrsi rtket a dialgusablak bezrsakor llthatjuk be, ez
utlag lekrdezhet, illetve van olyan blokkol fggvny (exec), amellyel megjele-
nthetjk a dialgusablakot, s ennek valban ez lesz a visszatrsi rtke.
A fablakot reprezentl osztlyok a QMainWindow-bl szrmaznak. Ez az
osztly sajt alaprtelmezett elrendezssel rendelkezik, menket, sttuszsort,
eszkzsorokat lehet benne elhelyezni. Rendelkezik tovbb olyan terletekkel,
ahov lebeg ablakokat lehet dokkolni, s egy olyan kzponti terlettel, amely-
be tetszleges vezrlt lehet elhelyezni. Ha nincsen szksgnk a Qt ltal biz-
tostott ablakfunkcikra (pldul eszkzsvok, mensv), akkor brmelyik
vezrlt hasznlhatjuk fablaknak (lsd az els pldban is, ahol a QWidget
egy pldnyt jelentettnk meg).
459
8. fejezet: A Qt keretrendszer programozsa
8.4.1. Dialgusablakok ksztse
A dialgusablakokat ktflekppen hasznlhatjuk. Az egyik, amg lthat,
blokkol minden hozzfrst a szlablakhoz, a msik esetben nem korltozza
semmiben a felhasznlt, a szlablakot is hasznlhatjuk. Az els vltozat a
modlis dialgusablak (modal dialog), a msodik a nem modlis dial-
gusablak (modeless dialog). A vlaszts, hogy modlis vagy nem modlis dia-
lgusablakot hasznljunk-e, fknt a dialgusablak funkcijtl fgg. Ha a
programban semmi hasznosat nem tehetnk, amg valamilyen adatot meg
nem kapunk, vagy a felhasznl nem nyugtz valamilyen informcit, akkor
clszer modlis dialgusablakot hasznlni. Pldul egy llomnynv kiv-
lasztsra is modlis dialgusablakot szoktunk megjelenteni. Ezzel szemben
a keress funkcijt ltalban nem modlis dialgusablakknt valstjuk
meg, hiszen kzben szerkeszthetjk a dokumentumot.
Egy modlis dialgusablakot a QDialog osztly exec fggvnyvel jelen-
tnk meg. Ilyenkor az alkalmazs eredeti esemnykezel ciklusa blokkoldik,
s a dialgusablak j ciklust indt. Ez a ciklus blokkolja a ms ablakokhoz r-
kez felhasznli esemnyeket, de tovbbtja pldul az jrarajzolst kr
zenetet. Amikor a felhasznl bezrja a dialgusablakot, akkor lell az
jonnan indtott esemnykezel ciklus, visszatr az exec fggvny, s gy az
eredeti ciklus folytatja a mkdst.
A modlis dialgusablakokat tipikusan loklis vltozknt hozzuk ltre,
ltalban valamilyen esemny kezelsre rt szlotfggvnyben, gy amikor a
vezrls elhagyja az adott fggvnyt, a dialgusablak felszabadul.
A nem modlis dialgusablakok osztoznak az esemnykezel cikluson a
tbbi ablakkal, gy a ltrehozs utn nem blokkoldhat a ltrehoz szl egy
olyan esemnykezel szlotban, amelyben ltrehoztk, s nem is szabad trlni
az objektumot, mert a fggvnybl val visszatrs utn is elrhet kell, hogy
maradjon. Ezrt a nem modlis dialgusablakokat tipikusan az alkalmazs
fablaknak tagvltozjaknt definiljuk, a konstruktorban hozzuk ltre, s
valamilyen esemny hatsra szlotbl jelentjk meg vagy rejtjk el. A meg-
jelentshez az exec helyett a show fggvnyt hasznljuk. Ez az exec-kel
szemben a dialgusablak megjelentse utn azonnal visszatr, s nem vr
az ablak bezrsra. A show tovbb nem indt kln esemnykezel ciklust
az j ablak szmra, az ide rkez zeneteket az alkalmazs fablaknak az
esemnykezelje kapja, s tovbbtja a dialgusablakhoz. Ezrt, ha nem mo-
dlis dialgusablakot jelentnk meg a show fggvnnyel, akkor mindenkp-
pen kell mr futnia esemnykezel ciklusnak, ezt a QApplication osztly exec
fggvnyvel indthatjuk el.
Feladat rjunk egyetlen dialgusablakbl ll alkalmazst, amelyben egy nevet s egy e-mail
cmet tudunk megadni. A dialgusablakbl a Rendben" s a Mgsem" nyomgombokkal
te-
hessen kilpni, a bezrszenetben mutassuk meg a dialgusablakba begpelt adatokat, s r-
juk ki, hogy melyik gombbal lptnk ki.
460
Uj bejegyzes
8.4. Ablakok s vezrlk
A kvetkez plda dialgusablakban (8.3. plda) teht egy ismersnk nevt
s e-mail cmt adhatjuk meg. Ezen a pldn bemutatjuk, hogyan kell sajt
dialgusablak-osztlyt rni, s hogyan kell az elrendezskezel objektumok
segtsgvel elhelyezni a vezrlket.
8.3. bra. QDialog-alap fellet nv s e-mail cm bersra
Sajt dialgusablak ksztsekor leszrmaztatunk a QDialog sosztlybl,
azoknak a tovbbi ltrehozott vezrlknek, amelyeket meg akarunk jelente-
ni, mindig a this mutatval elrt aktulis pldnyt adjuk meg szl'knt, gy
ezek a dialgusablakon bell jelennek meg.
/*contactdialog.h*/
#ifndefCONTACTDIALOG_H
#defineCONTACTDIALOG_H
#include<QtGui>
classContactDialog:publicQDialog
{
Q_OBJECT
public:
ContactDialog(QWidget*parent= 0);
QStringgetName();
QStringgetEmail();
priv ate:
QGroupBox*group;
QLabel*lblName;
QLabel*lblEmail;
QLineEdit*txtName;
QLineEdit*txtEmail;
QP ushButton*btn0k ;
QP ushButton*btnCancel;
QGridLay out*grid;
QVBoxLay out*mainLay out;
QHBoxLay out*buttonLay out;
};
#endif//CONTACTDIALOG_H
461
QGridLayout
tmretezhet res
terletek
QHBoxLayout
8. fejezet: A Qt keretrendszer programozsa
A ContactDialog osztly deklarcijban tagvltozknt troljuk a dialguson
megjelen sszes vezrlt. A group nev tagvltoz egy QGroupBox tpus
mutat. Ez megjelent cmmel egy keretet, a kereten bellre pedig tetszleges
tovbbi tartalmazott vezrl'ket helyezhetnk. A QLabel osztly segtsgvel
egy szveget vagy egy kpet tudunk megjelenteni, a fenti pldban a Nv"
s E-mail" cmkk megjelentsre hasznljuk. A QLineEdit osztllyal egy
egysoros szvegdobozt jelenthetnk meg, amelybe a felhasznl tetszleges
szveget gpelhet. Az egyszer nyomgombok ltrehozsra a Qt keretrend-
szerben a QPushButton osztly hasznlhat: kt ilyen tpus tagvltozt de-
finilunk a kt nyomgomb szmra. A tovbbi hrom tagvltoz a vezrlk
elrendezst segt objektumokat reprezentljk. A QGridLayout ngyzetrcs
alakban helyezi el az elemeket, ezek hasznlatakor minden vezrlhz meg
kell adni, hogy a ngyzetrcs melyik celljba tartozik. A QVBoxLayout a
hozztartoz vezrl'ket fgglegesen egyms al helyezi, mg a QHBoxLayout
vzszintesen egyms mell. A fenti objektumok segtsgvel a kvetkezkp-
pen helyezzk el az elemeket:
a QGridBoxLayout ngyzetrcsba rendezi a QGroupBoxon belli ngy
darab vezrlt, nevezetesen a kt feliratot s a kt szvegdobozt;
a QHBoxLayout csak a kt gombot rendezi el vzszintesen egyms
mell;
vgl a QVBoxLayout objektum segtsgvel a QGroupBoxot, illetve a
gombokat tartalmaz vzszintes svot helyezzk el egyms alatt.
Az automatikus elrendezsek hasznlatakor definilhatunk res te-
rleteket is, amelyek tmretezdnek, amikor az ablak mrete meg-
vltozik. Az elrendezskezel objektumok szerept s mkdst a
8.4. bra mutatja.
8.4. bra. A dialgusablak vezrlinek elrendezse
462
8.4.Ablak ok sv ez rlk
A dialgusablaknak van kt tovbbi fggvnye is: lekrdezhet a bert nv s
az e-mail cm. Erre szolglnak a publikus getName s getEmail fggvnyek:
contactdialog.cpp*/
#include"contactdialog.h"
ContactDialog::ContactDialog(Qwidget*parent):
QDialog(parent)
{
this->setWindowTitle("j bej egy z s");
group=newOGroupBox("Adatok ");
lblName=newQLabel("N v :");
lblEmail=newQLabel("E-mait:");
txtName=newQLineEdit();
txtEmail=newQLineEdit();
grid=newQGridLay out;
grid->addWidget(lblName,
grid->addwidget(txtName,
grid->addWidget(lblEmail,
grid->addwidget(txtEmail,
group->setLay out(grid);
0,
0,
1,
1,
0);
1);
0);
1);
btnok =newOP ushButton("Rendben");
btnCancel=newQP ushButton("M gsem");
buttonLay out=newQHBoxLay out;
buttonLay out->addstretch();
buttonLay out->addwidget(btn0k );
buttonLay out->addWidget(btnCancel);
mainLay out=newQHBoxLay out;
this->setLay out(mainLay out);
mainLay out->addWidget(group);
mainLay out->addStretch();
mainLay out->addLay out(buttonLay out);
connect(btnOk ,SIGNAL(click ed()),this,SLOT(accept()));
connect(btnCancel,SIGNAL(click ed()),this,SLOT(rej ect()));
QStringContactDialog::getName(){
returntxtName->text();
QStringContactDialog::getEmail(){
returntxtEmail->text();
463
8. fejezet: A Qt keretrendszer programozsa
Az osztly konstruktorban elszr a QGroupBoxot, illetve az abban tallhat
ngy vezrlt hozzuk ltre.
Az elrendezskezel objektumokhoz az addWidget fggvnnyel adhatjuk
hozz azokat a vezrlket, amelyeknek az elrendezsrt felelsek. Ha nem
egy vezrlt akarunk hozzadni az elrendezshez, hanem egy msik elrende-
zskezel objektumot, akkor az addLayout fggvnyt kell hasznlni, mivel
ezek az objektumok nem a QWidget osztlybl szrmaznak. Az elemek term-
szetesen a hozzads sorrendjben helyezkednek el.
A QGridLayout hasznlatakor az addWidget fggvny meghvsakor meg
kell adni, hogy melyik sorba, illetve oszlopba kerljn a vezrl (a sorok s
oszlopok indexelse 0-val kezddik). Termszetesen arra is van lehetsg,
hogy egy vezrl tbb egyms melletti cellt foglaljon el, gy a cellkat ssze-
vonjuk, ezeket a tovbbi opcionlis paramterekben lehet specifiklni.
A QGroupBox gyermekvezrljbl lesz a ngyzetrcsban elhelyezett ngy
msik vezrl. Ezt a ngy vezrlt pedig a QGridLayout objektum segtsgvel
rendezzk el, ezrt a QGroupBox objektumnak meg kell hvnia a setLayout
fggvnyt, paramterknt pedig az QGridLayout pldnyt kell tadni. Elren-
dezskezel objektumok hasznlatakor a gyermekvezrlket nem kzvetlenl a
szlhz adjuk, hanem a szlnek a setLayout fggvnyvel megadjuk elszr
az elrendezskezelt, majd ahhoz tesszk hozz a gyermekvezrlket a fentiek
szerint. A fenti kdban nem adtuk meg expliciten azt, hogy a kt cmke s sz-
vegdoboz a group gyermekvezrlje legyen. Ezt megtehettk volna gy, hogy a
vezrlk konstruktorainak tadjuk paramterknt a group szlt. Erre azon-
ban nincsen szksg, mert az elrendezskezel objektumok hasznlatakor a
setLayout fggvny meghvsval a keretrendszer automatikusan inicializlja
a szl-gyermek viszonyokat ez nagyban egyszersti a kdrst.
A kvetkez lpsben a kt nyomgombot s az azokat vzszintesen elren-
dez objektumot hozzuk ltre. A Qt keretrendszerben a vezrlk elrendezs-
nek egyik fontos eleme az res terek kezelse. A fenti pldban azt szeretnnk,
hogy ha az ablakot vzszintesen tmretezzk, akkor a kt nyomgomb mrete
ne vltozzon, hanem mindig az adott sor jobb oldalt foglaljk el, a bal olda-
lon pedig az res terlet szlessge vltozzon. Az addStretch fggvny ppen
egy ilyen, automatikusan vltoz mret res terletet (spacer) helyez el,
mgpedig a kt nyomgomb el, ugyanis ezek hozzadsa eltt hvtuk meg
ezt a fggvnyt.
A kvetkez sorokban az elzkhz hasonlan inicializljuk a fggleges
elrendezst biztost objektumot, a fenti ngyzetrcs s az als gombsor kz
pedig ismt egy res terletet helyeznk el
A QDialog osztlynak van kt szlotja: accept s reject. Ha brmelyik fgg-
vnyt meghvjuk, az ablak automatikusan bezrdik, s a dialgusablak
eredmnye" vagy visszatrsi rtke" a megfelel konstans QDialog::Accepted
vagy QDialog::Rejected lesz. Ezt az rtket a result fggvnnyel tudjuk lekr-
dezni. A kt ltrehozott gombnak a clicked szignljt elg sszektni a megfe-
lel szlottal (accept s reject), gy ezek automatikusan meghvdnak a gomb
megnyomsakor. Termszetesen sajt esemnykezel szlotfggvnyt is rhat-
464
8.4. Ablakok s vezrlk
nnk a gombnyoms lekezelsre, s ezen bell mi is bezrhatnnk az abla,
kot, illetve bellthatnk a visszatrsi rtket. Elbbit a close, utbbit a set-
Result fggvnnyel tehetjk meg.
A Qt keretrendszer nagyban egyszersti a memriakezelssel kapcsola-
tos feladatokat. A szigor fastruktrba rendezett felhasznlifellet-elemek
felszabadtsrl nem kell kln gondoskodni. Ha egy ablakot bezrunk, ak-
kor automatikusan felszabadtja az sszes benne lv vezrl szmra lefog-
lalt memriaterletet. Ezrt, habr a ContactDialog konstruktorban a new
kulcsszval terletet foglaltunk a tartalmazott vezrlknek s az elrendezs-
kezel objektumoknak, ezeket a hivatkozsokat a destruktorban nem kell k-
ln felszabadtani:
/*main.cpp*/
#include<QtGui>
#include"contactdialog.h"
intmain(intargc,char*argv [])
QApplicationapp(argc,argv );
ContactDialog*dlg=newcontactpialog();
dlg->exec();
QMessageBoxmsg;
msg.setwindowTitle("Eredm ny ");
QStringmessage=
"N v :"%dlg->getName()%
email:"%dlg->getEmail()%
(dlg->result()==QDialog::Accepted
?"(j v hagy v a)"
"(nincsj v hagy v a)");
msg.setText(message);
msg.show();
returnapp.exec();
}
Ahhoz, hogy a dialgusablakot ki tudjuk prblni, szksg van egy main
fggvnyre. A fenti forrsllomny els sorban a QApplication pldnyt ini-
cializljuk, majd ltrehozunk egy pldnyt a korbban definilt dialgusab-
lakbl. A dialgusablakot az exec fggvnnyel jelentjk meg modlisan.
Az exec nem tr vissza, amg a dialgusablak esemnykezel ciklusa fut, va-
gyis amg az ablakot be nem zrjuk.
Ha az ablakot nem modlisan szeretnnk megjelenteni, akkor a show
fggvnyt kellene hasznlni. Erre a ksbbiekben mutatunk mg pldt.
A dialgusablak bezrsa utn ltrehozunk egy szvegdobozt (QMessageBox
osztly), amelybe a dialgusablak visszatrsi rtktl fgg zenetet jelen-
tnk meg. A QMessageBox szintn egy beptett dialgusablak-tpus.
465
8. fejezet: A Qt keretrendszer programozsa
A main fggvny utols sorban az app.exec() hvsra azrt van minden-
kppen szksg, mert nem modlis dialgusablakot is hasznlunk (msg),
amely nem rendelkezik sajt esemnykezel ciklussal.
Ebben a pldban teht bemutattuk, hogyan tudunk olyan alkalmazst
rni, amelynek a fablaka egy dialgusablak. Sokszor a clunknak ennyi is
megfelel. A sajt alkalmazsablakokat bemutat fejezetekben rszletesen
megvizsgljuk azt, hogyan rdemes egy fablakkal rendelkez alkalmazsban
a modlis s a nem modlis dialgusablakokat hasznlni.
8.4.2. A Qt vezrlkszlete
A Qt keretrendszer egyik erssge a nagyszm testre szabhat vezrlt tar-
talmaz osztlyknyvtr. A szoksos egyszerbb vezrlk mellett tallhatk
sszetettebb vezrlk, s rendelkezsre llnak a szoksos dialgusablakok is.
A 8.2. tblzatban csak nhnyat sorolunk fel a legfontosabb vezrlk kzl.
8.2 . tblzat. A Qt keretrendszer legfontosabb vezrli
Vezrlk neve Ler s
Egyszerbb vezrlk
QLineEdit,
QTextEdit,
QDateEdit,
QDateTimeEdit,
QTimeEdit
Beviteli mez'k szvegekhez, dtumokhoz s idpontokhoz
QCheckBox, Jellngyzet- s vlasztngyzet-osztlyok
QRadioButton
QComboBox Legrdl lista
QFontComboBox Bettpus- vlaszt lista
QLabel
QMenu
Egyszer szveg vagy kp megjelentse
Menk megjelentse
sszetettebb vezrlk
QCalendarWidget Naptrat megjelent vezrl
QListWidget Elemeket listanzetben megjelent vezrl
QTableWidget Elemeket tblzatnzetben megjelent vezrl
QTreeWidget Elemeket fastruktrban megjelent vezrl
QWebView Webes dokumentumok megjelentsre s szerkesztsre
hasznlhat vezrl
4 66
8.4 . Ablakok s vezrlk
Vez r lk neve Ler s
Dialgusablakok
QColorDialog Sznvlaszt dialgusablak
QFileDialog llomnyok s knyvtrak kivlasztsra hasznlhat
dialgusablak
QFontDialog Dialgusablak bettpus belltsainak szerkesztsre
QlnputDialog Egy darab egyszer tpus adat beolvassa a felhaszn-
ltl (a beolvasand tpus lehet szveg, szm vagy egy
elre megadott lista egyik eleme)
QMessageBox zenet megjelentse a felhasznl szmra
A fenti tblzatban felsorolt vezrlk mindegyike hasonlan hasznlhat.
Mindegyik a QWidgetbl szrmazik, gy pldnyosts utn brmilyen sz-
lwidgeten elhelyezhetk, vagy nll ablakknt is megjelenthetk. Minde-
gyik vezrl szignlokat publikl, amelyekkel jelzi, hogy valamilyen vltozs
trtnt az llapotban. A szignlok termszetesen az adott vezrl tpusnak
megfelel esemnyeket jelzik, a QCheckBox pldul a kijellsi llapot meg-
vltoztatsnak jelzsre tartalmaz szignlt, a QListWidet pedig arra, hogy
megvltozott az ppen kijellt elem a listban. Termszetesen minden vezrl
a tpusnak megfelel tulajdonsgokkal rendelkezik, amelyek a megjelent-
st befolysoljk. Ezeknek a tulajdonsgoknak a lekrdezsre s mdost-
sra a megfelel fggvnyek rendelkezsre llnak. Ha egy konkrt vezrlt
hasznlunk a programozs sorn, rdemes hasznlat eltt tnzni a doku-
mentciban azt, hogy milyen fggvnyekkel szabhatjuk testre a kinzett, s
milyen esemnyekrl kld szignlokat a vezrl.
8.4.3. Sajt alkalmazsablakok
A QMainWindow osztly segtsvel definilhatjuk egy alkalmazs szoksos
felhasznli fellett, amelyen menk, eszkztrak s sttuszinformci je-
lennek meg, tallhatk tovbb lebeg s dokkolhat ablakok.
A QMainWindow osztly fellete elre meghatrozott terletekre van fel-
osztva, mindegyik terletre meghatrozott tpus vezrlket tudunk elhe-
lyezni. A feloszts a 8.5. brn lthat:
mensor (menu bar) s sttuszsor (status bar) az ablak tetejn s
aljn,
eszkztrak (tool bar) helye krben az ablak szlein,
leb ega b la kok (floating window) dokkolsra hasznlhat terlet
az eszkztrak mellett, illetve
a kzponti vezrl terlete, amely az ablak kzept, a legnagyobb te-
rletet tlti ki.
4 67
lebeg ablakok dokkolsnak helye
kzponti vezrl
mensor
eszkztrak
sttuszsor
8. fejezet: A Qt keretrendszer programozsa
8.5. bra. A QMainWindow terletnek felosztsa
A lebegablakok ltalban az alkalmazs fablaka fltt klnll ablakok-
knt helyezkednek el, de lehetsg van ezeket statikusan is elhelyezni, dok-
kolni" az ablak valamelyik oldaln. Mind a mensorbl, mind a sttuszsorbl
csak eggyel rendelkezik az ablak. A QMainWindow hasznlatnak elnye,
hogy beptetten tmogatja a fenti vezrlk elhelyezst. Termszetesen ezek
kzl egyiket sem kell tnylegesen fel is hasznlnunk az alkalmazsunkban.
m ha egyikre sincsen szksgnk, akkor nem rdemes a QMainWindow-bl
leszrmaztatni a fablakot.
A QMainWindow hasznlatakor vlaszthatunk az SDI (single document
interface) s az MDI (multiple document interface) felletek kzl, a keret-
rendszer mindegyik tmogatsra klnbz vezrl'ket biztost. Az SDI fel-
leten a kzponti vezrl terletn egyszerre egy dokumentumablak jelenik
meg. Ha egy msik dokumentummal akarunk dolgozni, akkor az elst be kell
zrni, s ezutn tudunk csak jabb ablakot megnyitni. Az MDI esetben vi-
szont egyszerre tbb dokumentumablakon is dolgozhatunk, vagyis a kzponti
terleten egyszerre tbb sajt fejlccel, kerettel rendelkez, tmretezhet
ablak is lehet megnyitva. Ezeknek az tmretezhetsgt, mozgatst a
QMainWindow biztostja. Az SDI esetben a kzponti terletre brmilyen ve-
zrlt elhelyezhetnk, ez tlti ki a rendelkezsre ll teljes terletet. Az MDI
esetben a kzponti vezrl helyre egy QMdiArea tpust kell elhelyezni,
amelyhez az addSubWindow fggvnnyel mr tetszleges vezrlt hozzad-
hatunk. Minden egyes ilyen vezrl kln ablakknt jelenik meg.
Lthat, hogy az SDI fellet programozshoz semmilyen specilis vezr-
lt nem kell hasznlni, egy MDI fellet megvalstsa azonban bonyolultabb,
erre a dokumentum-nzet architektra trgyalsakor mutatunk pldt.
468
8.4.Ablak ok sv ez rlk
8.4.4. A fablak programozsa
A tovbbiakban megvizsgljuk, hogy milyen fggvnyekkel tudunk hozzfr-
ni a fablak men-, eszkz- s sttuszsoraihoz, s hogyan tudjuk ket az akci-
kkal sszekapcsolni.
Egy alkalmazsban ltalban vannak olyan funkcik, amelyek a fellet tbb
pontjrl is elrhetk, pldul a mensor vagy az eszkztr egyik elemrl, illet-
ve valamilyen billentykombinci segtsgvel. ltalban ilyen pldul az j
dokumentum" funkci. A felhasznl szemszgbl csak az adott funkcinak van
jelentsge, s rdektelen, hogy ppen melyik mdon hvta meg. Egy ilyen funk-
cit az gynevezett akciobjektummal runk le, ez a QAction osztly egyik pld-
nya. Az akci (action) fogja ssze az ugyanannak a funkcinak a meghvshoz
szksges klnbz esemnyeket s a funkcit kezel szlotfggvnyt, valamint
a funkci lerst szvegekkel s kpekkel. Egy mr ltrehozott akcit hozz-
adhatunk egy mensorhoz vagy egy eszkztrhoz, avagy egyszeren maghoz
az ablakhoz, ha csak billentykombincival szeretnnk elrni. Mindegyik
esetben az adott vezrl (mensor, eszkztr, QMainWindow) addAction fgg-
vnyt hasznljuk az akci megjelentshez. Egy QAction ltrehozsakor meg-
adhat ikon, menszveg, gyorsbillenty, sttuszszveg, sgszveg (tooltip).
A QAction publikl egy triggered szignlt, ezzel kapunk rtestst, ha a fel-
hasznl az adott funkcit meghvta fggetlenl attl, hogy a felhasznli fel-
let melyik elemn keresztl aktivldott.
Amikor szeretnnk egy ment ltrehozni, a menuBar fggvnnyel lekr-
dezzk az ablaktl a mensort. A mensor valjban a legels lekrdezskor
inicializldik, ksbbi hvsokkor ugyanazt az objektumot adja vissza, gy ha
nem akarunk ment ltrehozni, s nem prblunk meg hozzfrni, akkor
nem is jn ltre. Hasonlan mkdnek az eszkztrak s a sttuszsor is.
A QMainWindow osztly menuBar metdusnak visszatrsi rtke egy
QMenuBar objektum, amely az ablak mensort rja le. A mensorhoz az
addMenu fggvnnyel adhatunk hozz jabb menelemeket. Ezek a men-
pontok a QMenu osztly pldnyai. Az j pldnyt magval az addMenu
fggvnnyel is ltrehozhatjuk, ekkor csak egy szveget kell tadni a men-
pont ltrehozshoz:
#include<QtGui>
QMenu*QMenu::addMenu(constQString&title)
QMenu*QMenu::addMenu(constQlcon&icon,constQString&title)
A QMenu addAction fggvnyvel egy akcinak megfelel QAction objektumot
adhatunk hozz a menhz. Ennek a szvege pedig egy tovbbi menpontknt
jelenik meg az eredeti menn bell. Lehetsg van arra, hogy a QAction pl-
dnyt az addAction fggvnyhvssal egytt hozzuk ltre, ekkor csak a megje-
lentend menpont cmt kell tadni.
469
8. fejezet: A Qt keretrendszer programozsa
QAction * QMenu::addAction ( const QString & text )
QAction * QMenu::addAction ( const Qicon & icon,
const QString & text )
Az albbi kdrszlet elszr ltrehoz egy Fjl" ment a mensoron, majd ini-
cializl egy QAction pldnyt, ennek szvege a Kilp" lesz. Ezutn a men-
ben megjelenti az akcit:
QMenu * fi leMenu = thi s->menuBar()->addmenu ("Faji ") ;
exitAction = new QAction("Ki lp", thi s);
filemenu->addAction(exi tActi on);
A mensorhoz hasonlan mkdnek az eszkztrak is, de azokbl a men-
sorral ellenttben tbb is lehet. Az ablak addToolBar fggvnyvel hozha-
tunk ltre egy QToolBar tpus eszkztrat, amelyre szintn az addAction
fggvnnyel tudjuk az akciknak megfelel elemeket elhelyezni.
Sttuszsorbl is csak egy van az alkalmazson bell, ezt a statusBar fgg-
vnnyel rjk el. A sttuszsoron hromfle informcit tudunk megjelenteni:
ideiglenes szveget (temporary), ltalnos (normal) s lland (permanent) in-
formcit. Az ltalnos s az lland informci nem csak szveg lehet, ezek
megj elentshez sajt QLabel objektumokat kell ltrehozni, s ezeket az add-
Widget fggvnnyel kell a sttuszsorhoz adni. Lehetsg van tbb QLabel hoz-
zadsra is. Az lland szveg egszen addig lthat, amg a removeWidget
fggvnnyel a megfelel QLabel vezrlt el nem tvoltjuk. Az ideiglenes szve-
get tipikusan valamilyen zenet rvid idej megjelentsre alkalmazzuk, erre
a showMessage fggvnyt hasznljuk, amelynek a megjelentend szveg mel-
lett megadhatjuk, hogy mennyi ideig legyen lthat. Az ideiglenes szveg, elta-
karhatja a norml informcit, de az lland informci mindig lthat marad,
amg programozottan el nem tntetjk.
Feladat rjunk egy olyan alkalmazst, amelyben ismerseink cmlistjt (nv s e-mail cm)
trolhatjuk. A fablakban jelentsk meg a lista adatait tblzatos formban. Ksztsnk dial-
gusablakokat, amelyekkel j bejegyzst vehetnk fel, illetve kereshetnk nv szerint a list-
ban. Az elst modlisan, a msodikat nem modlisan jelentsk meg.
j bejegyzs ltrehozsra az elz pldban bemutatott ContactDialog dia-
lgusablakot hasznljuk. runk tovbb egy SearchDialog osztlyt is, amely
ugyancsak egy dialgusablak, s a keresst teszi lehetv. Az ablakban meg-
jelentnk egy Fjl" ment, amelyben hrom menpont lesz: keress", j
bejegyzs" s Kilp". Ezen kvl hasznljuk a sttuszsort is a felhasznlnak
sznt zenetek megjelentsre. Az alkalmazs fellete a 8.6. brn lthat.
470
8.4. Ablakok s vezrlk
8.6. bra. Cmlista-alkalmazs kpernykpe
/*contactswindow.h*/
#ifndefCONTACTSWINDOW_H
#defineCONTACTSWINDOW_H
#includeQtGui>
#include"contactdialog.h"
#include"searchdialog.h"
classContactswindow:publicQmainwindow
{
Q_OBJECT
public:
explicitContactsWindow(QWidget*parent = 0)
;
signals:
publicslots:
v oidaddNewContact();
v oidupdateStatusText();
v oidsearch(Qstringexpression);
v oidshowSearch();
protected:
v oidcloseEv ent(QCloseEv ent*ev ent);
priv ate:
QAction*exitAction;
QAction*newContactAction;
QAction*showSearchAction;
471
8. fejezet: A Qt keretrendszer programozsa
QMenu *fi 1 emenu ;
QTableWi dget * table;
SearchDialog * searchDi al og ; // Nemodl i s , ezrt tagvltoz
},
#endif // CONTACTSWINDOW_H
A ContactsWindow osztly a QMainWindow-bl szrmazik, s a Q_OBJECT
makrval kezddik, hiszen sajt szlotokat definilunk.
A closeEvent az sosztlyban definilt virtulis fggvny, amely azeltt
hvdik meg, mieltt az ablakot bezrjuk. Ezt a fggvnyt felldefiniljuk, gy
kapunk rtestst az ablak bezrsrl. A fggvnyen bell r tudunk kr-
dezni arra, hogy a felhasznl valban ki akar-e lpni. A felldefinilst biz-
tost fggvnyen bell lehetsgnk van a bezrs megszaktsra is.
Az osztly tagvltozi kzl az els hrom akcikat r le. Az exitAction segt-
sgvel az ablakot lehet bezrni. Ezt a funkcit a menbl is el lehet rni, illetve
egy billentykombincit is rendelnk hozz. A msodik akci a newContact-
Action. Ezzel jelzi a felhasznl, hogy egy j bejegyzst szeretne ltrehozni, ilyen-
kor modlisan megjelentnk egy ContactDialog tpus dialgusablakot. Ez az
akci szintn a mensorbl, illetve egy billentykombincival rhet el.
A harmadik a showSearchAction, amellyel a keres dialgusablakot jelentjk
meg. Ezt nem modlisan tesszk, mivel folyamatosan elrhet lesz, mikzben az
alkalmazs fablakban is dolgozunk.
Tbb szlotfggvnyt is definilunk. Az addNewContacttal a newContact-
Action akci bekvetkezstl kezdve kapunk rtestst, az updateStatusText-
tel pedig arrl, ha a tblzatban j elemet jellnk ki. A showSearch szlottal
a keres ablakot jelentjk majd meg (ezt a showSearchAction akcin keresz-
tl rjk el). Vgezetl a search szlotfggvnnyel kapunk rtestst arrl,
hogy egy bizonyos szvegre kell rkeresni a megjelentett adatok kztt.
A fileMenu vltozval rjk el a Fjl" ment ler objektumot. Arra a
mensorra, amelyben a sajt mennk is megjelenik, nem trolunk kln re-
ferencit, mert azt mindig le tudjuk krdezni a menuBar fggvnnyel.
A table vltoz egy QTableWidget tpusra mutat, amellyel egyszer ele-
mekbl ll tblzatot tudunk megjelenteni. A tblzat celliban QTable-
Widgetltem tpus elemek vannak, egy-egy elemben tbbfle informcit is
trolhatunk, de ebben a pldban mi egyszer szveget jelentnk meg.
Vgezetl a searchDialog tagvltoz egy SearchDialog tpus dialgusab-
lakra mutat. Ezt a dialgusablakot nem modlisan jelentjk meg, gy fontos,
hogy az alkalmazsablakban mindig elrhet legyen. ContactDialog objek-
tumra viszont nem trolunk referencit loklis vltozknt hozzuk majd ltre,
amikor meg akarjuk jelenteni. A modlis dialgusablakot mindig a megjele-
nts eltt hozzuk ltre, majd bezrsa s az bekrt adatok feldolgozsa utn
rgtn trljk, mert ksbb mr nem lesz r szksg.
472
8.4.Ablak ok sv ez rlk
/*contactswindow.cpp*/
#include"contactswindow.h"
#include"contactdialog.h"
#include<QtGui>
#include<QStringBuilder>
contactswindow::contactswindow(Qwidget*parent):
Qmainwindow(parent)
{
this->setwindowTitle(tr("C mlista"));
fileMenu=this->menuBar()->addmenu(tr("&F j l"));
exitAction=newQAction(tr("&Kil p"),this);
exitAction->setShortcut(tr("Ctrl+Q"));
exitAction->setStatusTip(tr("Alk almaz sbez r sa"));
connect(exitAction,SIGNAL(triggered()),this,SLOT(close()));
fileMenu->addAction(exitAction);
newContactAction= newQAction(tr("&j bej egy z s"),this);
newContactAction->setShortcut(OKey Sequence::New);
newContactAction->setStatusTip(tr("j bej egy z sfelv tele"));
connect(newContactAction,siGNAL(triggered()),this,
SLOT(addNewContact()));
filemenu->addAction(newContactAction);
showsearchAction=newQAction(tr("Keres &s"),this);
showSearchAction->setShortcut(OKey sequence::Find);
showSearchAction->setStatusTip(tr("Keres sn v alapj n"));
filemenu->addAction(showsearchAction);
connect(showsearchAction,SIGNAL(triggered()),this,
SLOT(showsearch()));
this->table=newQTablewidget;
table->setSelectionmode(QAbstractItemv iew::SingleSelection);
table->setColumnCount(2 );
this->setcentralwidget(table);
QStringListheaderLabels;
headerLabels"N v ""E-mail";
table->setHorizontalHeaderLabels(headerLabels);
connect(table,SIGNAL(itemSelectionChanged()),this,
SLOT(updateStatusText()));
searchDialog=newSearchoialog;
connect(searchDialog,SIGNAL(searchinv ok ed(QString)),this,
SLOT(search(Qstring)));
}
v oidContactsWindow::showSearch(){
if(!searchoialog->isVisible())
this->searchDialog->show();
473
8. fejezet: A Qt keretrendszer programozsa
v oidContactsWindow::search(QStringexpression){
intcurrently SelectedRowNbr=-1;
QList<QTablewidgetitem*>selecteditems=
table->selecteditems();
i f(selecteditems.length()>0)
currently SelectedRowNbr=selectedItems.first()->row();
inti;
boolfound=false;
for(i=currently SelectedRowNbr+1;
i<table->rowCount();i++){
if(table->item(i,0)->text().contains(expression)){
table->clearSelection();
table->item(i,0)->setSelected(true);
found=true;
break ;
}
}
if(!found){
table->clearSelection();
}
}
v oidContactswindow::closeEv ent(QCloseEv ent*ev ent)
{
QMessageBoxmsg(this);
msg.setwindowTitle(tr("Kil p s"));
msg.setText(tr("T ny legk il p?"));
msg.setStandardButtons(QMessageBox::Yes1QMessageBox::Cancel);
i f(msg.exec()==QmessageBox::Yes)
ev ent->accept();
else
ev ent->ignore();
}
v oidcontactswindow::addNewContact(){
ContactDialog*newContactDialog=newContactDialog(this);
i f(newContactDialog->exec()==Wialog::Accepted)
{
intcurrentRowsNbr=table->rowCount();
table->insertRow(currentRowsNbr);
QTablewidgetItem*newNameitem=
newQTablewidgetItem(newContactDialog->getName());
table->setitem(currentRowsNbr,0,newNameItem);
QTablewidgetItem*newEmailitem=
newQTableWidgetItem(newContactDialog->getEmail());
table->setItem(currentRowsNbr,1,newEmailitem);
}
deletenewContactDialog;
}
474
8.4. Ablakok s vezrlk
v oidcontactswindow::updatestatusText()
{
Qtist<QTablewidgetitem*>selecteditems=
table->selecteditems();
if(selecteditems.length()>0)
this->statusBar()->showmessage(
"Name:"%
table->item(selecteditems.first()->row(),0)->text()
) ;
}
Az osztly implementcis llomnyban elszr a konstruktort rtuk meg.
A setWindowTitle fggvnnyel lltjuk be az ablak fejlcben megjelen cmet.
Ezutn kvetkezik a Fjl" men inicializlsa A menuBar fggvnnyel krjk
el a referencit az alkalmazsablak mensorra, s mivel ez az els hvsa a
fggvnynek, itt jn ltre maga a mensorobjektum. Nem kell kln ltrehozni
QMenu objektumot s azt hozzadni a mensorhoz, ez megtehet egy lpsben
az addMenu fggvnnyel, ezrt csak a menpont cmt adjuk t. A pldban
a &Fjl" szvegkonstans egy tr fggvnyhvson bell tallhat. A tr fggvny
a QObject osztly egy metdusa, s a fellet lokalizlhatv ttelhez hasznl-
juk. Ha egy kln llomnyban lefordtottuk az adott szveget egy msik
nyelvre, akkor a tr fggvny a fellet nyelve alapjn ezt a fordtst adja
vissza az eredeti szvegkonstans helyett. Arra, hogy miknt lehet egy adott
nyelv fordtst megadni, a kvetkez fejezetben trnk vissza, itt csak az a
fontos, hogy a tr fggvnybe gyazva jelezni kell, hogy az adott szveget lokali-
zlhatv akarjuk tenni. Termszetesen, ha biztosan tudjuk, hogy ksbb nem
akarjuk lokalizlhatv tenni az alkalmazsunkat, akkor a tr fggvnyhvs
elhagyhat, s a szveg nmagban is llhat Az addMenu fggvny visszatr-
si rtke az j menpontra mutat referencia. A menpont cmben az F' bet
eltti &" jel az adott menponthoz tartoz gyorsbillentyt jelzi, ebben az eset-
ben teht a Fjl" mennek az F' bet lesz a gyorsbillentyje.
Az els akci, amelyet ltrehozunk, az exitAction. A konstruktornak t-
adott szveg lesz a menpont cme, amikor hozzadjuk egy menhz. Ezenk-
vl egy gyorsbillentyt is megadunk a setShortcut fggvnnyel. A setStatusTip
fggvnynek tadunk egy szveget, amely ideiglenes szvegknt megjelenik a
sttuszsoron, amikor az adott menpont fl visszk az egeret. Az akcihoz
lehetne mg ikonkpet is megadni (seticon), amelyet az eszkztron helyez-
hetnnk el. Az akci hasznlathoz mg kt lps szksges. Elszr egy
megfelel szlotot ssze kell ktni az akci triggered szignljval, gy rtestst
kapunk arrl, ha az adott funkcit a felhasznl el akarta rni. Itt az alkal-
mazsablak close szlotjt hasznljuk, amelynek a meghvsakor bezrul az
ablak. Mivel a close szlotot az sosztly tartalmazza, itt ennek a megrsval
nem kell foglalkozni. Msodszor, az akcit el kell helyezni a mensoron, mert
amg nincsen egy vezrlhz sem hozzrendelve, nem lehet elrni. A QMenu
osztly addAction fggvnyvel a paramterknt tadott akciobjektum me-
npontknt jelenik meg az eredeti menpontot bell. Ilyenkor a billenty-
kombinci is automatikusan mkdik.
475
8. fejezet: A Qt keretrendszer programozsa
A newContactAction funkcival jelentnk meg egy ContactDialog dial-
gusablakot. Az exitAction inicializlsnak lpseihez kpest ennek a ltre-
hozsnl kt klnbsget lthatunk. Az els az, hogy a gyorsbillentyt nem
szvegknt adjuk t, hanem a QKeySequence osztly StandardKey felsorols-
tpusnak egy rtkeknt: QKeySequence::New. A QKeySequence osztlyban
vannak definilva azok az ltalnos billentykombincik, amelyeket gyak-
ran hasznlunk az alkalmazsokban, ilyen pldul az j dokumentum", a
Nyomtats", a Megnyits" vagy a Bezrs". Az adott funkcihoz tartoz
alaprtelmezett billentykombincik az opercis rendszertl fggen vl-
tozhatnak. Ha nem szvegknt definiljuk az akcihoz tartoz gyorsbillen-
tyt, mint az exitAction esetben, hanem a fenti konstansok hasznlatval,
akkor a keretrendszer az aktulis platformnak megfelel alaprtelmezett bil-
lentyparancsot hasznlja. Ezzel nagyban nveljk az alkalmazsunk hor-
dozhatsgt. A msodik klnbsg az exitActionhz kpest, hogy itt egy sajt
szlotot hasznlunk az akci esemnynek a kezelsre, nevezetesen az add-
NewContact fggvnyt, hiszen itt sajt alkalmazsspecifikus logikt szeret-
nnk rni: megjelenteni egy dialgusablakot.
A konstruktor vgn ltrehozzuk az alkalmazs fablaknak kzponti ve-
zrljt (central widget), ez tlti ki az ablak kzps rszt, amelyet ppen
nem foglalnak el az eszkzsorok, a mensor, a sttuszsor, illetve az esetlege-
sen dokkolt lebegablakok. A kzponti vezrl tetszleges QWidget lehet, itt a
QTableWidget tpust hasznljuk. A ltrehozs utn az ablak setCentralWidget
fggvnyvel meg kell adni, hogy ez legyen a kzponti vezrl. A QTable-
Widget konstruktorban most sem kellett megadni a szlvezrlt, mert a set-
CentralWidget automatikusan belltja. A tblzatnak nhny tulajdonsgt
is testre szabjuk: megadjuk, hogy 2 oszlopbl lljon (setColumnCount), hogy
egyszerre csak egy cellt lehessen kijellni (setSelectionMode), s specifikl-
juk az oszlopok fejlceinek a cmt (setHorizontalHeaderLabels). Ez utbbi
belltshoz szksg van egy QStringList tpus objektumra, ebben szveg-
konstansok listjt lehet hatkonyan trolni. A QStringList osztly felldefini-
lja a opertort is, ennek a segtsgvel knyelmesen tudunk j elemeket
hozzadni a listhoz (lsd a fenti kdrszletben).
Az alkalmazs gy mkdik, hogy ha kivlasztunk egy cellt a tblzat-
ban, akkor egy rvid ideig a sttuszsoron is kirjuk az adott sorhoz tartoz ne-
vet. Ehhez egy rtestsre van szksgnk arrl, ha a kijellt cella megvltozik,
ezrt sszekapcsoljuk a tbla itemSelectionChanged szignljt az update-
StatusText szlottal, amelyet mi ksztnk el
A konstruktor vgn ltrehozzuk a SearchDialog osztly egy pldnyt, de
nem hvunk rajta show metdust, ezrt ez nem jelenik meg. Termszetesen le-
hetsg lenne ezt az objektumot magt a dialgusablak els megjelentse
eltt is ltrehozni, nem pedig itt a konstruktorban. A SearchDialog definci-
jt ks'bb mutatjuk be, m elzetesen megllapthat, hogy publikl egy
searchInvoked nev szignlt, amellyel jelezni tudja, hogy valamilyen szvegre
akar keresni a felhasznl. A searchInvoked szignl paramterlistja egy
476
8.4. Ablakok s vezrlk
QStringbl n, ez lesz az a szveg, amelyre keresnk. A search szlotfggvnyt
ktjk ssze a szignllal. A connect fggvnyben a SIGNAL s a SLOT mak-
rk hasznlatakor a paramterlistt is jellni kell.
A konstruktor utn jnnek a tagfggvnyek implementcii. A show-
Search ellenrzi, hogy lthat-e a keresablak, ha nem, akkor a show hvssal
megjelenti.
A search szlotfggvny felels a keress elvgzsrt. Pldnkban csak a
nevekben keresnk, az e-mail cmekben nem. Szeretnnk, ha a keress gy
mkdne, hogy a dialgusablak ltal kibocstott szignlnl az ppen kijellt
cella sora utni sorokban trtnjen csak a keress. Ha a keress sorn tal-
lunk egy olyan nevet, amelyben szerepel a kifejezs, akkor jelljk ki az adott
cellt. Ha az utols sorban sem tallunk tallatot, akkor egyszeren megszn-
tetjk a kijellst a tblzatban. gy teht folytonosan tudunk keresni a tbl-
zatban, s minden elfordulst megtallunk. A fenti logika implementcijhoz
a QTableWidget nhny metdust is meg kell ismernnk. A selectedltems
visszaadja azoknak a cellaelemeknek a listjt, amelyeket ki lettek jellve.
A tblzat inicializlsakor megadtuk, hogy egyszerre maximum egy cella lehet
kijellve, gy felttelezhetjk, hogy a visszaadott listnak 0 vagy 1 eleme lehet.
A QList egy olyan sablonosztly, amellyel adott tpus elemek listjt tudjuk
kezelni, ebben az esetben QTableWidgetltem pldnyok mutatit. A listn a
szoksos mveletek hajthatk vgre, pldul beszrs, trls, keress. A tovb-
biakban csak a lista mrett visszaad size fggvnyre s az els elemmel vissza-
tr first fggvnyre lesz szksgnk. A QTableWidget rowCount fggvnnyel
a sorok szma, az itemmel pedig egy adott sor- s oszlopindex cellaelem kr-
dezhet le. A clearSelection fggvny, ahogyan a neve is mutatja, megsznteti a
kijellst a tblzatban. Vgezetl a QTableWidgetltem setSelection fggvnyt
emltjk meg, amellyel egy adott cellt tudunk kijellni.
A closeEvent fggvny virtulis, azeltt hvdik meg, mieltt az ablak be-
zrdik. A fggvny egyetlen paramternek tpusa QCloseEvent tpus. Eb-
ben a fggvnyben egy felugr ablakban megkrdezzk a felhasznlt, hogy
valban ki akar-e lpni az alkalmazsbl. Az ablaknak cmet adunk (set-
WindowTitle), s megadjuk a kirand szveget (setText), majd belltjuk,
hogy milyen gombokat jelentsen meg Ehhez a QMessageBox osztlyban de-
finilt StandardButton felsorolstpus elemeit hasznljuk fel, jelen esetben a
QMessageBox::Yes s a QMessageBox::Cancel konstansokra van szksgnk,
hogy a felhasznl az Igen" vagy Mgsem" gombok kzl tudjon vlasztani.
Az ablakot modlisan jelentjk meg, ezrt az exec fggvnyt hasznljuk,
amelynek visszatrsi rtke annak a gombnak a kdja lesz, amellyel bezr-
tuk a szvegdobozt. Ha a felhasznl vlasza QMessageBox::Cancel, vagyis
meg 'akarja szaktani a kilpst az alkalmazsbl, akkor a paramterknt
megkapott event vltozn meghvjuk az ignore fggvnyt, ezzel megszaktjuk
az ablak bezrst. Ha ezt nem hvjuk meg, akkor a closeEvent visszatrse
utn valban megtrtnik az ablak bezrsa.
477
8.fej ezet:AQtk eretrendszerprogramoz sa
Az addNewContact szlotfggvny implementcijban elszr ltreho-
zunk egy ContactDialog pldnyt, ezutn megjelentjk a dialgusablakot.
A dialgusablaknak a visszatrsi eredmnyt a korbbi pldban a result
fggvnnyel krdeztk le, de ugyanez lesz az exec fggvny visszatrsi rt-
ke is. Ha a dialgusablakot jvhagytuk, akkor lekrdezzk a bert nevet s
e-mail cmet, majd ezeknek megfelelen ltrehozunk kt j cellt. A tblzat-
ba az insertRow fggvnnyel beszrunk egy j sort, ennek a sornak a cellit
mr tudjuk vltoztatni a setltem fggvny segtsgvel.
A msik szlotfggvny az updateStatusText, ezzel kapunk rtestst arrl,
ha a tblzatban j elemet vlasztottunk ki. Ismt a tblzat selectedltems
fggvnyt hasznljuk annak lekrdezsre, hogy van-e kijellt cella, s ismt
kihasznljuk, hogy maximum egy darab cella lehet egyszerre kijellve. A kije-
llt cellhoz tartoz sor els oszlopbl kiolvassuk az aktulis nevet, majd ezt
2 msodpercig megjelentjk a sttuszsoron. Ehhez a QStatusBar osztly
showMessage fggvnyt hasznljuk, amelynek els paramtere a megjelen-
tend szveg, msodik pedig a megjelents idtartama milliszekundumban.
Ezzel az alkalmazsablak elkszlt, mr csak a dialgusablakok defin-
cija hinyzik. A ContactDialog kdjt a korbbiakban mr trgyaltuk, az
albbiakban a SearchDialogot mutatjuk be:
/*searchdialog.h*/
#ifndefSEARCHDIALOG_H
#define SEARCHDIALOG_H
#include<QtGui>
classsearchDialog:public QDialog
{
Q_OBJECT
public:
explicitSearchQialog(Qwidget*parent=0);
signals:
v oidsearchinv ok ed(Qstringexpresssion);
publicslots:
v oidsearch();
protected:
QH8oxLay out*lay out;
Qi_ineEdit *txtExpression;
QP ushButton*btnsearch;
}
;
#endif//SEARCHDIALOG_H
478
8.4. Ablakok s vezrlk
/*searchdialog.cpp*/
#include"searchdialog.h"
SearchDialog::Searchpialog(QWidget*parent):
Wialog(parent)
{
lay out=newQHBoxLay out;
this->setLay out(lay out);
txtExpression=newQLineEdit;
lay out->addwidget(txtExpression);
btnSearch=newQP ushButton(tr("Keress"));
lay out->addwidget(btnSearch);
connect(btnSearch,SIGNAL(click ed()),this,SLOT(search()));
}
v oidSearchoialog::search(){
emitsearchInv ok ed(txtExpression->text());
A dialgusablak kdja a Qt keretrendszer eddig trgyalt elemeinek ismeret-
ben nem szorul rszletes magyarzatra. A dialgusablakon egy egysoros sz-
vegbeviteli mezt (QLineEdit) s egy nyomgombot (QPushButton) helyeznk
el vzszintesen egyms mellett. A keressgomb megnyomsakor bocstja ki a
dialgusablak a searchlnvoked szignlt.
Ezutn mr csak a main fggvnyre van szksg, amelyben inicializljuk
az alkalmazst, s megjelentjk a fablakot:
/*main.cpp*/
#include"contactswindow.h"
#include<QtGui>
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
ContactsWindow*w=newContactsWindow;
w->show();
returnapp.exec();
8.4.5. Lokalizci
Azokat az alkalmazsokat, amelyekben lehetv akarjuk tenni, hogy a fellet
tbb klnbz nyelven is elrhet legyen, rdemes gy megtervezni, hogy a
klnbz nyelv fordtsokat lehetleg minl kevesebb tovbbi programozs
nlkl, minl egyszerbben tudjuk megadni. Az ilyen jelleg tervezst nemzet-
kziestsnek (internationalization) nevezzk. Lokalizcinak (localization)
hvjuk azt, amikor az alkalmazsunkat egy adott nyelvre lefordtjuk.
479
8. fejezet: A Qt keretrendszer programozsa
A Qt keretrendszerben ez a folyamat gy mkdik, hogy a megjelentett
szvegkonstansokat klnll erforrs-llomnyokban troljuk, amelyeket
egyenknt lefordthatunk klnll nyelvekre, ezeket a fordtsokat pedig
mellkeljk a programunkhoz. A lokalizci teht abbl ll, hogy az erfor-
rs-llomnyoknak elksztjk a klnbz nyelv fordtst (ehhez semmi-
lyen programozi tuds nem kell), illetve gondoskodunk a betltskrl a
programon bell.
Az elz pldban emltettk, hogy azokat a szvegkonstansokat, melye-
ket lokalizlni szeretnnk, kln meg kell jellni a forrskdban. Erre a
QObject osztlyban definilt tr fggvnyt hasznljuk:
QSt ri ng QObject: : t r (
const char sourceText,
const char * disambiguation = 0,
int n = -1 )
A tr fggvny els paramtere az alaprtelmezett szveg, a tovbbi paramte-
rek opcionlisak. Elfordulhat, hogy ugyanazt a szveget az alkalmazs kt
klnbz helyn mshogyan akarjuk lefordtani, ilyenkor a kt kontextust
meg akarjuk klnbztetni, erre szolgl a msodik paramter. Ha a szveg s
a kontextus is megegyezik, akkor ugyanaz lesz a fordts is. A harmadik, int
tpus paramternek a tbbes szm kpzsben van szerepe. Ha az eredeti
szvegkonstans tartalmazza a %n" szveget, akkor ezt a vgleges szvegben
a harmadik paramter (n) rtkvel helyettestjk. A fordtsnl megadhat
az adott kifejezs tbbes szm s egyes szm vltozata is, az n rtktl
fggen a megfelelt hasznlja fel a keretrendszer.
A lokalizland szvegek megjellse utn a kvetkez lps a lehetsges
fordtsok elksztse. A klnbz nyelv fordtsokat klnll fjlokbl ol-
vassa be a rendszer. Minden nyelvhez ltre kell hozni egy .ts kiterjeszts
xml llomnyt. Az llomny minden egyes szveg-kontextus proshoz tartal-
maz egy fordtst.
Az xml llomny vzt automatikusan generlhatjuk a Qt fordtprog-
ramjval, ennek neve lupdate. Ha ltre szeretnnk hozni egy ilyen llomnyt,
a projektllomnyban ezt jeleznnk kell:
TRANSLATIONS+=ContactsApplication_en_US.ts
A fenti sor jelzi, hogy egy ContactsApplication_en_US.ts nev llomnyban
szeretnnk fordtst kszteni az alkalmazsunkhoz. A fjl nevnek a vgz-
dse konvenci szerint a fordts nyelvt jelzi, de ez nem ktelez, tetszleges
fjlnevet is hasznlhatunk. Termszetesen tbb klnbz fordtst is kszt-
hetnk, ekkor tbb nevet kell megadni. Ezutn kell a projekt llomnynev-
vel meghvni az lupdate programot, pldul:
lupdate ContactsApplication.pro
480
8.4.Ablak ok sv ez rlk
A program legenerlja a megfelel xml llomny vzt. Az lupdate bejrja a
teljes forrskdot, s megkeresi a tr fggvnnyel megjellt hvsokat, majd
resen hagyja az adott szveg fordtst. Ezeket a rszeket kell neknk a for-
dtssal kiegsztennk. Fontos tulajdonsga az lupdate programnak, hogy
amennyiben a generland llomny mr ltezik, akkor nem trli annak a
tartalmt, csak az idkzben a forrskdba bert jabb fordtand szvegek
alapjn kiegszti. gy inkrementlisan hasznlhat az alkalmazs rsnak
klnbz fzisaiban a fordtsok elksztsre. Ennek az xml llomnynak a
vzt teht nem kell manulisan sszelltani, ez jelents munktl s az xml
sma ismerettl kmli meg a programozt. Az albbi kd a Contacts-
Application alkalmazs angol nyelv fordtsnak egy rszt mutatja be.
Lthat benne az eredeti szveg, a fordts, illetve az eredeti szveg helye:
<?xmlv ersion="1.0"encoding="utf-8"?>
<!DOCTYP ETS>
<TSv ersion="2 .0"language="en_US"sourcelanguage="hu_Np"
<context>
<name>ContactDialog</name>
<message>
<locationfilename="contactdialog.cpp"line="6"/>
<source>j bej egy z s</source>
<translation>Newcontact</translation>
</message>
</context>
</TS>
A .ts llomnyok teht xml formtumban troljk az adatokat, a program fut-
tatsa sorn mgsem ezeket hasznljuk, hanem egy tmrtett vltozatukat,
amelynek kiterjesztse .qm. Minden .ts llomnybl kell egy ilyet generlni,
erre az lrelease program hasznland:
1 rel ese ContactsAppli cation. pro
A fejezet ksbbi rszben rszletesen is bemutatjuk, hogy milyen alkalmaz-
sok s technolgik segtik a gyors alkalmazsfejlesztst a Qt-krnyezetben,
m mr itt megjegyezzk, hogy mind az lupdate s az lrelease programok
automatikus futtatsra, mind az xml llomnyok szerkesztsre hatkony
grafikus alkalmazsok llnak rendelkezsre egy integrlt fejleszti krnye-
zetben: ezek a szoftverek a fejleszts teljes munkafolyamatt nagymrtkben
egyszerstik.
A Qt keretrendszerben ksztett alkalmazsok lokalizcijra a QTrans-
lator osztlyt hasznljuk. Ha nem az alkalmazs forrskdjba bert alapr-
telmezett szveget, hanem annak valamilyen nyelv fordtst szeretnnk
hasznlni, akkor ltre kell hozni egy QTranslator objektumot, majd a load
fggvnyvel be kell tlteni a megfelel .qm llomnyt. Ezutn az alkalma-
zsobjektum installTranslator fggvnyvel jelezni kell, hogy ezentl ezt a
481
8.fej ezet:AQtk eretrendszerprogramoz sa
fordtst szeretnnk hasznlni. Termszetesen elfordulhat, hogy a fordtsok
tbb llomnyban vannak, ilyenkor minden ilyen llomnyhoz kln QTrans-
lator pldnyt kell ltrehozni:
/*mdos tottmain.cpp*/
#include"contactswindow.h"
#include<QtGui>
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
QTranslatortranslator;
translator.load(QString("ContactsApplication_en_US"));
app.installTranslator(&translator);
QTranslatorqtTranslator;
qtTranslator.load(QString("qt_en"));
app.installTranslator(&qtTranslator);
Contactsw ndow*w=newcontactswindow;
w->show();
returnapp.exec();
}
A fenti kdrszlet alapjn lthat, hogyan kell mdostani az alkalmazsunk
main fggvnyt, hogy a ContactsApplication _en_US llomnyban megadott
angol fordtst tudja hasznlni A .qm llomnynak ebben az esetben a futta-
tott llomnnyal egy knyvtrban kell lennie, vagy a load fggvnyben az el-
rsi tvonalat is meg kell adni az llomny neve eltt.
Az elz pldban a lefordtott kdrszleten kvl egy qt_en nev fordtst
is betltnk. Erre azrt van szksg, mert az alkalmazsunk nemcsak ltalunk
rt vezrlket tartalmaz, hanem a Qt keretrendszer rszt kpez beptett fel-
hasznli felleti elemeket is, ilyenek pldul a felugr ablakokon megjelentett
Jvhagys" s Mgsem" nyomgombok. Az ezeken megjelen szvegek ford-
tsrl is neknk kell gondoskodnunk. A keretrendszer teleptsekor meg-
adott mappban megtallhatk ezeknek a beptett szvegeknek a fordtsai, a
qt_en ahogyan a neve is mutatja ppen az angol nyelv fordtsokat tartal-
mazza, de a magyarral egytt sok ms nyelvhez is megtallhat itt a fordts.
A fenti kdrszletben azt felttelezzk, hogy ezt az llomnyt az alkalmazsun-
kat tartalmaz knyvtrba msoltuk, ezrt nem adunk meg elrsi tvonalat
Termszetesen az gy felhasznlt llomnyt is tetszs szerint mdosthatjuk, ha
jobban testre akarnnk szabni a lefordtott szvegeket.
482
8.4. Ablakok s vezrlk
8.4.6. Sajt vezrlk ksztse
Sajt vezrlnek (custom widget) nevezzk azokat az jrafelhasznlhat
vezrlket, amelyeket magunk definiltunk. Sajt vezrlk ksztsre tbb
lehetsgnk is van a Qt keretrendszerben. Az els lehetsg, hogy egy ltez
vezrlosztlybl leszrmaztatunk, ekkor ennek csak azokat a tulajdonsgait
vltoztatjuk meg, amelyek szmunkra fontosak. A msik mdszer az, hogy
a QWidget sosztlybl leszrmaztatva mi magunk rjuk meg a teljes vezr-
lt. Mivel minden QWidgetnek lehetnek tartalmazott vezrli, elfordulhat,
hogy a sajt vezrlnket egyszeren ms ltez vezrl'k komponlsval sz-
szellthatjuk. Ilyenkor az j vezrlnek csak a tartalmazott komponensek
elhelyezsrt kell felelnie. A legbonyolultabb eset az, amikor sajt megjelen-
tst szeretnnk definilni, a kvetkez rszben ezt az esetet vizsgljuk meg
rszletesen.
Sajt vezrl ksztshez az albbi feladatokat kell megoldanunk:
Hogyan kapja a vezrl az esemnyeket a felhasznltl?
Hogyan kommunikl a vezrl a szljvel?
Hogyan rheti el a sajt terlett a vezrl, s hogyan rajzolhat r?
A rendszer ltal tovbbtott esemnyek mondjk meg azt a vezrlnek, hogy
jra kell rajzolnia a fellett, mert a felhasznl tmretezte, elmozgatta, az
egrrel a felletre kattintott, vagy billentyket ttt le. Termszetesen en-
nek kezelse Qt alatt a szignl-szlot mechanizmussal trtnik. Ugyanakkor
sajt vezrlk ksztsekor mindig ugyanazokat a szlotokat kell megadnunk,
hiszen pldul a rajzolsi esemnyt mindig kezelnnk kell. Sokszor jobb len-
ne, ha valamilyen alaprtelmezett mkdst felttelezhetnnk, s csak akkor
kellene kezelni az adott szignlt, ha ettl a mkdstl el szeretnnk trni.
A QWidget tmogatst nyjt ebben: a szlotok olyan virtulis fggvnyek,
amelyneknek a mkdst tetszs szerint fellrhatjuk vagy megtarthatjuk.
gy az els krdsre a vlasz az, hogy a QWidget virtulis fggvnyek
meghvsval ad lehetsget az esemnyek kezelsre. Mindegyik me-
tdus rendelkezik egy, az esemny jellemzit ler paramterrel. A szrmazta-
tott osztlyok ezeket a fggvnyeket tetszs szerint felldefiniljk. Az egyes
fggvnyek implementcijtl fgg, hogy az adott elem milyen szerepet va-
lst meg, hogyan reagl egy adott esemnyre. A QWidget osztlyban tbb tz
ilyen virtulis fggvnyt tallunk, ezek neve ltalban az Event" szveggel
vgzdik. A leggyakrabban hasznltak a paintEvent s a resizeEvent. Az els-
vel a vezrl jrarajzolst jelzi a rendszer, a msodikkal azt, hogy a vezrlt
tmreteztk. Kln fggvnyeket tallunk a billentyzet (keyPressEuent, key-
ReleaseEvent) s az egr (mousePressEvent, mouseDoubleClickEvent, mouse-
MoveEvent, mouseReleaseEvent) fell rkez esemnyek kezelsre. A tovbbi
fggvnyek megtallhatak a QWidget osztly dokumentcijban.
483
8. fejezet: A Qt keretrendszer programozsa
A vezrl a szlablakkal kzvetlenl szignl-szlot alapon kom-
munikl. A QWidget a QObject osztlybl szrmazik, ezrt implementlja a
szignl-szlot metdust. A vezrl szignlokat hasznl, hogy jelezze a felhasz-
nl beavatkozsait vagy az llapotnak a megvltozst.
A rajzolst a QPainter osztllyal vgezzk. A QPainter osztly ala-
csony szint rajzfunkcikat biztost, amelyekkel az adott vezrlnk terletre
rajzolhatunk. gy nagyon sokfle rajzfunkci rhet el az egyszer vonalh-
zstl a bonyolultabb alakzatok megjelentsig. Lehetsg van tovbb sz-
veg s kpek kezelsre is.
Feladat Ksztsnk egy vezrlt, amely kezdetben megjelent egy tglalapot, amelynek a ke-
rete s a kt tlja 4 pixel szles kk szn vonal, a belseje pedig piros szn. Amikor a fel-
hasznl rkattint a vezrlre, akkor a kitlts megvltozik, ekkor egy ellipszist rajzolunk ki,
amelynek stlusa megegyezik a tglalapval.
Sajt vezrl
8. 7. b r a . Sajt vezrl llapotai
Ebben a pldban megmutatjuk, hogyan kapunk rtestst arrl, hogy a ki-
rajzolsnak meg kell trtnnie, s hogyan lehet tetszleges tartalmat rajzolni
a vezrl felletre. Az elksztett alkalmazs felhasznli fellete a 8.7. b-
rn lthat.
/* customwidget.h */
#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H
#1 ncl ude <QtGui >
class customwidget : public Qwidget
{
Q_OB JECT
public:
explicit customwidget(Qwidget *parent =0);
enum Shape { Rectangle, Ellipse };
QSize sizeHint0 const;
484
8.4. Ablakok s vezrlk
signals:
v oidshapechanged(intnewshape);
protected:
v oidmousePressEvent(QMouseEvent *ev ent);
v oidpaintEvent(QPaintEvent *event) ;
priv ate:
intcurrentShape;
} ;
#endif//CUSTOMWIDGET_H
A CustomWidget osztly minden vezrl sosztlybl, a QWidgetbl szrma-
zik. Mivel szeretnnk sajt szignlt is definilni, ezrt a deklarcija a
Q_OBJECT makrval kezddik. Szksgnk lesz kt konstansra (Rectangle
s Ellipse), ezek segtsgvel jelezzk, hogy ppen melyik llapotban van a
vezrl. Az aktulis llapotot a currentShape tagvltozban troljuk.
Minden vezrlnek lekrdezhet az alaprtelmezett mrete, ezt adja visz-
sza a sizeHint fggvny, amely a QWidget osztly egy virtulis fggvnye.
A CustomWidget osztly definil egy szignlt is (shapeChanged), ezzel je-
lezzk, amikor az aktulis llapot megvltozik. A fggvny int tpus param-
tere az j llapotot tartalmazza. Az osztlyban felldefinilunk kt tovbbi vir-
tulis fggvnyt is, ezek a mousePressEvent s a paintEvent. Az els fggvny-
nyel kapunk jelzst arrl, hogy egrkattints-esemny trtnt a vezrlnkn,
a msodik fggvny pedig azt az esemnyt jelzi, hogy a vezrlnk egszt
vagy egy rszt jra ki kell rajzolni. Erre pldul akkor van szksg, ha a ve-
zrl egy rszt eddig egy msik ablak takarta, m most jra lthatv vlik.
Egy msik oka lehet az jrarajzolsi esemnynek, ha a programunkbl meg-
hvtuk a vezrln az update vagy a repaint tagfggvnyeket. Ezekkel a fgg-
vnyekkel jelezhetjk, hogy jra akarjuk rajzolni a vezrlt, mert pldul a
megjelentett adatok megvltoztak, s gy frissteni kell a megjelentst.
Magt a paintEvent fggvnyt kzvetlenl sosem szabad meghvni, csak az
elz fggvnyek egyikvel kzvetetten. Az update s a repaint kztt az a
klnbsg, hogy az utbbinl az jrarajzols azonnal megtrtnik, mg az els
hvsakor az jrarajzolsi krs zenetknt bekerl az ablak zenetsorba,
s csak akkor trtnik meg a kiszolglsa, amikor az eltte lv zeneteket
feldolgoztuk. ltalban csak akkor haszljunk repaintet, ha a szlotban mr
szksgk van a kirajzols megjelentsre.
485
8. fejezet: AQt keretrendszer programozsa
/*customwidget.cpp*/
#include"customwidget.h"
CustomWidget::Customwidget(Qwidget*parent):
Qwidget(parent)
{
currentshape=Rectangle;
setSizeP olicy (QSizeP olicy ::minimum,QSizeP olicy ::Minimum);
}
v oidcustomwidget::mouseP ressEv ent(QMouseEv ent*ev ent){
currentShape=currentShape==Rectangle?Ellipse:Rectangle;
update();
emitshapeChanged(currentShape);
}
v oidCustomwidget::paintEv ent(QP aintEv ent*ev ent){
QP ainterpainter(this);
QP enpen;
pen.setColor(Qt::blue);
pen.setWidth(4);
painter.setP en(pen);
QBrushbrush;
brush.setColor(Qt::red);
brush.setSty le(Qt::SolidP attern);
painter.setBrush(brush);
switch(currentshape){
caseRectangle:
painter.drawRect(0,0,this->size().width(),
this->size().height());
painter.drawLine(0,0,this->size().width(),
this->size().height());
painter.drawLine(0,this->size().height(),
this->size().width(),0);
break ;
caseEllipse:
painter.drawEllipse(0,0,this->size().width(),
this->size().height());
break ;
QSizeCustomWidget::sizeHint()const
{
returnQSize(2 00,2 00);
}
486
8.4 . Ablakok s vezrlk
A konstruktor implementcijban elszr belltjuk a kezdllapotot, ez a
Rectangle konstans lesz. A kvetkez lps a setSizePolicy fggvny meghv-
sa. Minden vezrl esetben meg lehet hatrozni, hogy milyen szablyok sze-
rint lehet tmretezni Amikor az adott tpus vezrl elrendezsrt egy
elrendezskezel objektum a felels, akkor ennek figyelembe kell venni eze-
ket a szablyokat:
void setSizePolicy (
QSi zePol cy : :Policy horizontal,
QSizePolicy: :Policy vertica7 )
A setSizePolicy fggvny els paramtere a vzszintes tmretezs szablyt,
a msodik a fgglegest definilja. A lehetsges belltsokat a 8.3. tblzat
tartalmazza.
8.3. tblzat. A vezrlk tmretezsi szablyainak lehetsges tpusai
A szably kdja Lers
QSizePolicy::Fixed A vezrl mrett nem lehet megvltoztatni, az
mindig az alaprtelmezett rtk lesz.
QSizePolicy::Minimum A vezrl alaprtelmezett mrete a minimumr-
tk, teht annl kisebbre nem lehet tmretezni.
QSizePolicy::Maximum A vezrl alaprtelmezett mrete a maximumr-
tk, teht annl nagyobbra nem lehet tmretezni.
QSizePolicy::Preferred A vezrl alaprtelmezett mrete az optimlis
mret, de ha szksges, kisebbre s nagyobbra is
lehet lltani.
QSizePolicy::Expanding Ha van elg hely, a vezrlt rdemes minl na-
gyobb mretre tmretezni, de szksg esetn a
mretet cskkenteni is lehet.
QSizePolicy::MinimumExpanding
A vezrlt kisebbre nem lehet venni, mint az
alaprtelmezett rtk, de ha lehetsges, rdemes
minl nagyobbra venni.
QSizePolicy::Ignored A vezrl alaprtelmezett rtkt figyelmen k-
vl kell hagyni, akkora helyet tltsn ki, ameny-
nyit csak lehet.
A konstruktorban hasznlt argumentumok mellett teht megmondjuk, hogy
a vezrlnek a sizeHint fggvny ltal visszaadott szlessge s magassga a
minimumrtk, ezeknl kisebbre nem lehet tmretezni egyik irnyban sem.
Az alaprtelmezettnl nagyobbra azonban t lehet mretezni.
Az egrkattintsi esemny bekvetkezsekor a mousePressEvent fggvny
hvdik meg. Ekkor megvltoztatjuk a vezrl eddigi llapott, majd a meg-
vltozott llapot miatt jrarajzoltatjuk az update fggvnyhvssal. Vgl ki-
bocstjuk a shapeChanged szignlt, jelezve, hogy a vezrl aktulis llapota
megvltozott.
4 87
8. fejezet: A Qt keretrendszer programozsa
Utolsknt a paintEvent fggvnyt implementljuk. Ez akkor hvdik
meg, amikor a vezrl tartalmt frissteni kell, a rajzolst a fggvnyen bell
vgezhetjk el. A rajzols megkezdshez szksg van egy olyan QPainter
pldnyra, amellyel az aktulis vezrl terletre tudunk rajzolni, ezt pedig
gy kaphatjuk meg, hogy a konstruktorban tadjuk az aktulis vezrlt.
Minden alakzat rajzolsakor meg kell hatrozni, hogy az alakzat krvonala
(toll pen) s a kitltse (ecset brush) milyen stlus legyen. Az elst egy
QPen tpus, a msodikat egy QBrush tpus objektummal rjuk le. A toll ese-
tn tbbek kztt meghatrozhatjuk a sznt, a vonalvastagsgot, a kitltst, az
ecset esetn ugyancsak a sznt s a kitltst. A pldban egy kk szn, 4 pixel
szles tollat s egy egyenletes piros kitltst inicializlunk. A QPen, illetve a
QBrush objektumok ltrehozsa utn a QPainter objektum setPen, illetve set-
Brush fggvnyeivel be is kell ezeket lltani a rajzolshoz. A QPainter osz-
tly drawRect s drawEllipse fggvnyeinek a felhasznlsval rajzolunk egy
tglalapot vagy egy ellipszist a vezrl aktulis llapottl fggen. Mindkt
fggvny esetben az adott alakzatot befoglal tglalap bal fels sarknak
koordintit, illetve szlessgt s magassgt kell tadni. A rajzols sorn
ktdimenzis koordinta-rendszerrel dolgozunk, amelynek bal fels sarknak
koordinti a (0,0), szlessge s magassga pedig a vezrl aktulis mrete,
amelyet a size fggvnnyel krdezhetnk le
A QPainter segtsgvel teht knnyen megvalsthatunk alacsony szint
rajzfunkcikat, m a kpessgei nem csak erre korltozdnak. Bonyolultabb
alakzatokat, sszetett szntmeneteket, koordintatranszformcit s sok
egyb szolgltatst biztost ez az osztly. A QPainter segtsgvel nemcsak
egy QWidgetre tudunk rajzolni, hanem brmilyen QPaintDevice tpus objek-
tumra, ez az objektum az alaposztlya azoknak az objektumoknak, amelyek
valamilyen rajzolhat felletet tartalmaznak Valjban a QWidget is ebbl
szrmazik. Tovbbi kt gyakran elfordul leszrmazott osztly a QPrinter s
a QPixmap. Az els segtsgvel kinyomtathat felletet rnk el, a msodik-
kal pedig a memriban trolt bittrkpet. A QPainterben a felhasznlstl,
teht a konkrt QpaintDevice-tl fggetlenl trtnik a rajzols ugyanazok-
kal a fggvnyekkel, vagyis az a kdrszlet, amely egy memriban trolt k-
pet rajzol ki, egy az egyben felhasznlhat arra, hogy egy vezrl felletre
vagy egy nyomtathat terletre rajzoljunk.
Vgezetl megmutatjuk a main.cpp llomnyt, amelyben az elksztett
vezrl hasznlathoz ltrehozunk egy alkalmazsablakot, amelyben a kz-
ponti vezrljnek belltjuk a CustomWidget egy pldnyt:
/* main.cpp */
#include <QtGui >
#include "customwidget.h"
int mai n(i nt argc, char * argv[])
{
QAppl cati on app (argc , a rgv) ;
Qmai nwi ndow " w =new Qmai nwi ndow;
488
8.5. A dokumentum/nzet architektra
w->setwindowTitle("saj tv ez rl");
Customwidget*c=newCustomWidget;
w->setCentralWidget(c);
w->show();
returnapp.exec();
8.5. A dokumentum/nzet architektra
Ebben a fejezetben megvizsgljuk, hogyan lehet sszetettebb alkalmazsokat
fejleszteni gy, hogy a program struktrja mindvgig ttekinthet, bonyo-
lultsga pedig kezelhet legyen.
A felhasznli fellettel rendelkez (GUI) alkalmazsok fejlesztsekor
nagyon sok esetben adott valamilyen adathalmazunk, amelyet tbbflekp-
pen, tbb nzetbl szeretnnk megjelenteni. Miutn megjelentettk az ada-
tokat, a felhasznl mdostani szeretne rajtuk valamelyik esetleg egyms
utn tbb klnbz nzetben. A felhasznl termszetes elvrsa az, hogy
ha egy adott nzetben megvltoztatott valamit, mind az adathalmaz, mind a
tbbi nzet a vltoztatsnak megfelelen frissljn.
Erre knl egyfajta ltalnos megoldst a dokumentum/nzet (docu-
ment / view) architektra. Az adatok egyes megj elentsi formjt nzetnek
(view) nevezzk. Az adatokat a dokumentum (document) trolja. Ha egy nze-
ten keresztl megvltoztatunk valamit, a nzet frissti a megfelel adatokat a
dokumentumban is. A dokumentum feladata az, hogy ha az llapotban vl-
tozs trtnt, akkor az sszes hozzkapcsold nzetet azonnal rtestse, s
ezzel biztostsa, hogy a nzetek mindig a legfrissebb adatokat mutatjk. Ha
teht egy nzeten keresztl mdostottuk a dokumentum adatait, akkor az
sszes tbbi nzet is automatikusan rtestst kap errl. Az rtestett nzetek
lekrdezik a dokumentumtl az j adatokat, s gondoskodnak sajt jrarajzo-
lsukrl. Egy dokumentum llapott termszetesen nem csak a nzeteken
keresztl lehet mdostani, m brmi okozza is a vltozst, a nzeteket min-
dig rtesteni kell rla.
ltalban ltezik egy a lka lma z s (application) szerepl is, amely inicializl-
ja magt a programot, feldolgozza a parancssori argumentumokat, felpti a do-
kumentumot, ltrehozza a nzeteket, s hozzkapcsolja ket a dokumentumhoz.
A fentiekbl kvetkezik, hogy a dokumentumnak tudnia kell azokrl a
nzetekrl, amelyeket rtestenie kell egy esetleges vltozs esetn. Ez imp-
lementcis szinten, C++ nyelven legtbbszr gy jelenik meg, hogy a doku-
mentum tartalmaz egy olyan listt, amelyben az rtestend nzetekre mutat
pointereket trol. gy egy nzet feliratkozhat" erre a listra, vagy lekapcso-
ldhat rla, a dokumentum pedig bejrhatja ezt a listt, s rtestst kldhet
a nzettpus listaelemek egy megadott tagfggvnynek a meghvsval.
489
8. fejezet: A Qt keretrendszer programozsa
Termszetesen a nzeteknek is tudnia kell az ltaluk megjelentett doku-
mentumrl A dokumentumot egy, a dokumentumnzet-architektrn kvli
osztlyban pldul az alkalmazsban trolhatjuk, s a nzet kzvetlenl az
alkalmazstl krdezi le a dokumentumot. Ha azonban tbb dokumentum is
ltezik egy programon bell, akkor ez nem megfelel megolds, ilyenkor a
legclszerbb az, ha a nzet kln eltrol egy referencit a hozztartoz do-
kumentumra.
Az alkalmazsablakok trgyalsakor mr sz volt arrl, hogy a Qt keret-
rendszer tmogatja az SDI- s az MDI-alkalmazsok ksztst, az SDI rvid-
ts az egy dokumentumablakos, az MDI a tbb dokumentumablakos felletre
utal. Fontos hangslyozni, hogy a Qt terminolgijban a dokumentumablak
a fablakon bell megjelentett olyan tovbbi ablakot jelent, amelyben az ak-
tulisan szerkesztett adatokhoz tartoz funkcikat elrhetjk. Az SDI s az
MDI kifejezsek teht csak arra utalnak, hogy ilyen ablakokbl hny darab
lehet egyszerre megnyitva, vagyis pusztn a felhasznli fellet szempontj-
bl osztlyozzk az alkalmazsokat. A dokumentumablak s a dokumen-
tum/nzet architektra dokumentumkomponense kt klnbz tnyez, csak
a nevk hasonl. Knnyen elkpzelhet pldul, hogy a dokumentum/nzet
architektra szerint egyszerre csak egy dokumentum tallhat egy alkalma-
zsban, de ehhez tbb nzetet jelenthetnk meg klnll ablakokban. gy a
Qt terminolgija szerint MDI-alkalmazsfelletrl beszlnk.
Ebben a fejezetben egy MDI-alkalmazsfelleten keresztl bemutatjuk,
hogyan tudunk tbb dokumentumablakkal egyszerre dolgozni a Qt keret-
rendszerben. A tbb dokumentum kezelsre alkalmas pldaalkalmazs kom-
ponenseit a dokumentum/nzet architektrra ptve kezeljk, gy mutatjuk
be, hogy ezzel a mdszerrel hogyan lehet kzben tartani nagyobb mret
programok bonyolultsgt.
Feladat Ksztsnk programot mrsi eredmnyek (0 s 10 kztti szmok) listjnak a keze-
lshez. Ezeket az eredmnyeket egy listban szeretnnk kirni a felhasznlnak (ez az egyik
nzet), illetve egy hisztogram formjban is meg akarjuk jelenteni ket (ez a msodik nzet).
A mrsi adatokat egy-egy llomnybl olvassuk be. Nemcsak megjelentjk az adatokat ktf-
le nzetben, hanem azt is felttelezzk, hogy a mrsi eredmnyeket szolgltat eszkztl
jabb adatok rkezhetnek folyamatosan, gy ezekkel is frissteni kell a dokumentumot.
A feladat megoldst az albbiakban rszletesen bemutatjuk, az alkalmazs
felletnek egy kpernykpe a 8.8. brn lthat. A pldban az adatforrs
megvalstsra a fellet biztost majd egy gombot, ezt megnyomva az aktu-
lis dokumentum fogadni tudja az adatokat. Egy dokumentumhoz tartoz kt
nzetet mindig egyazon dokumentumablakon bell jelentjk meg, s minden
dokumentumhoz kln ablak tartozik. Termszetesen ugyanolyan knnyen
megvalsthat lenne az is, hogy a kt nzet kt klnbz ablakban jelenjen
meg, m kiderl, hogy a dokumentum/nzet architektra mkdse szempont-
jbl ennek nincs jelentsge. Azrt vlasztottuk az els megoldst, mert gy
minden nzetrl egyrtelm, hogy ppen melyik dokumentumhoz tartozik.
490
)(4
/home/mark/Documents/1.data - K x Diume s63.clata'
8.2
9.6
2.3
1/
0
6.3
9.1
12
6.6
0.7
8.2
9.6
23
1.9
9.1
92
6.6
0.7
6.9
8.5.Adok umentum/n zetarchitek tra
KonyvMOI
Elle
8.8. bra. MDI-alkalmazs kpernykpe
8.5.1. Az alkalmazs szerepe
Az alkalmazskomponens ltalban az alkalmazs fablakt zrja egysgbe.
A fablak feladata, hogy a felhasznli fellet egyes elemeit (men, llapot-
sor, eszkzsv, ablakok) sszefogja:
#ifndefMDIMAINWINDOW_H
#defineMDIMAINWINDOW_H
#include<QtGui>
#include"document.h"
classmoimainwindow: public Qmainwindow
{
Q_OBJECT
public:
explicitmoimainwindow(Qwidget*parent= 0) ;
signals:
public sl ots:
v oidopen();
v oidsav e();
v oidattach5ource();
491
8. fejezet: A Qt keretrendszer programozsa
priv ate:
QMdiArea*mdiArea;
QToolBar*fileToolbar;
QMenu*fileMenu;
QAction*exitAction;
QAction*openDocumentAction;
QAction*sav eDocumentAction;
QAction*attachDataSourceAction;
QList<Document*>*documents;
;
#endif//mDIMAINWINDOW_H
Az MDIMainWindow osztly a QMainWindowbl szrmazik. QAction tpus
tagvltozkat deklarltunk a kilpsre, j dokumentum megnyitsra, az aktv
dokumentum mentsre, illetve arra, hogy az aktv dokumentumhoz hozzcsa-
toljunk egy adatforrst. Az alkalmazs fablakban lthat dokumentumabla-
kok kzl az ppen a fkuszt birtoklt nevezzk aktv dokumentumablaknak,
s az ehhez tartoz dokumentumot nevezzk aktv dokumentumnak.
A dokumentumok tpust a document.h llomnyban deklarljuk (lsd
ksbb) Az alkalmazsunkban lv dokumentumokat egy listban troljuk,
ehhez a QList osztlyt hasznljuk.
A fablaknak hrom fontos vezrlje van, amelyekhez kln tagvltozt is
rendelnk. A mensvon egy Fjl" felirat ment helyeznk el, ezt a QMenu
tpussal rjuk le. Megjelentnk tovbb egy eszkzsvot is (fileToolBar),
amelyben ugyanazok a funkcik lesznek elrhetk, mint a menben. Vgeze-
tl az alkalmazs kzponti vezrlje egy QMdiArea pldny lesz, amely bizto-
stja a tbb dokumentumablakos krnyezet hasznlatt:
moimainwindow::mDIMainWindow(OWidget*parent):
QMainWindow(parent)
{
mdiArea=newQMdiArea;
this->setCentralWidget(mdiArea);
documents=newOList<Document*>;
fileMenu = this->menusar0->addmenu(tr("&Fjl"));
fileToolbar = this->addToolBar(tr("Fi1 e"));
openDocumentAction=newQAction(tr("&Megny it s"),this);
openDocumentAction->setIcon(QIcon::fromTheme("document-open"));
openDocumentAction->setShortcut(OKey Seguence::Open);
fileMenu->addAction(openDocumentAction);
fileToolbar->addAction(openDocumentAction);
connect(openDocumentAction,SIGNAL(triggered()),this,
SLOT(open()));
492
8.5.Adok umentum/n zetarchitek tra
sav eDocumentAction=newQAction(tr("Ment &s"),this);
sav eDocumentAction->setIcon(QIcon::fromTheme("document-sav e"));
sav eDocumentAction->setShortcut(QKey Seguence::Close);
fileMenu->addAction(sav eDocumentAction);
fileToolbar->addAction(sav eDocumentAction);
connect(sav eDocumentAction,SIGNAL(triggered()),this,
SLOT(sav e()));
attachDataSourceAction=
newQAction(tr("Forr scs&atol sa"),this);
attachDataSourceAction->setIcon(QIcon::fromTheme(
"sy stem-run"));
fileToolbar->addAction(attachDataSourceAction);
connect(attachDataSourceAction,SIGNAL(triggered()),this,
SLOT(attachSource()));
exitAction=newQAction(tr("&k il p s"),this);
exitAction->setIcon(QIcon;:fromTheme("application-exit"));
exitAction->setShortcut(QKey Sequence::Quit);
fileMenu->addAction(exitAction);
connect(exitAction,SIGNAL(triggered()),this,SLOT(close()));
}
A konstruktorban lthat, hogy az sszes tagvltozt inicializljuk, s elhe-
lyezzk a menben s az eszkzsvon a megfelel funkcikat. A kilpshez
tartoz funkci csak a menben, az adatforrs csatlakoztatshoz tartoz
funkci csak az eszkzsvon jelenik meg.
A tovbbi fggvnyek implementcijt a dokumentum- s a nzetoszt-
lyok trgyalsa utn mutatjuk be.
8.5.2. A dokumentumosztly
A dokumentumnak (a pldban Document osztly) a kvetkez feladatai vannak:
trolnia kell az adatokat;
interfszt kell biztostania az adatok mdostsra;
trolnia kell a hozz tartoz nzeteket, s lehetv kell tennie jabb
nzetek hozzadst, egy mr trolt nzet eltvoltst;
gondoskodnia kell arrl, hogy ha a trolt adatok vltoznak, akkor az
sszes nzet frissljn;
interfszt kell biztostania az adatok lekrdezsre, ugyanis a nzetek
a frissts sorn lekrdezik a dokumentumtl, hogy milyen adatokat
is kell pontosan megjelenteni:
493
8. fejezet: A Qt keretrendszer programozsa
#ifndef DOCUMENT_H
#defineDOCUMENT_H
#i ncl ude <QtCore>
#i ncl ude <QtGui>
#i nclude "vi ew. h"
cl ass view;
cl ass Document : public QObject
{
Q_OBJECT
public:
explicit Document(QObject *parent = 0);
void addvi ew(Vi ew view);
void removevi ew(vi ew " view);
QList<double> * getState() ;
si gnal s :
public slots:
void appendoata(doubl e val ue) ;
bool openFi 1 e (QStri ng fi 1 eName) ;
bool saveFi 1 e() ;
protected:
void updateAllvi ews() ;
pri vate:
QLi st<double> " state ;
QLi st<View"> "vi ews ;
QString fi 1 ename ;
};
#endif //DOCUMENT_H
A dokumentumosztlyban hivatkozunk a View s a DocumentWindow oszt-
lyokra. A DocumentWindow osztly nem a dokumentum/nzet architektra
rszt kpezi, egyszeren arra szolgl, hogy minden dokumentumhoz megje-
lentsen egy vezrlt (ezek lesznek az adott dokumentumhoz tartoz doku-
mentumablakok), amelyen egyms mell helyezzk az adott dokumentumhoz
tartoz nzeteket egy elrendezskezel objektummal.
A View a nzet az osztlyok kzs se. Felttelezzk, hogy minden olyan
nzet ebbl szrmazik, amelyet a dokumentumhoz nzetknt szeretnnk ren-
delni. Hogy mirt van szksgnk arra, hogy a nzeteknek kzs sosztlya
legyen, a ksbbiekben mg visszatrnk. A nzetek listjnak kezelshez
szksg van mg a views tagvltozra, az addView s a removeView fggv-
nyekre. Az updateAllViews fggvny feladata pedig az, hogy az dokumen-
tumban trolt adatok vltozsakor a listban trolt sszes nzetet rtestse.
494
8.5. Adok umentum/n zetarchitek tra
A dokumentumok kezdeti adatait llomnyokbl olvassuk be, ezrt elt-
rolunk egy llomnynevet (filename tagvltoz) is, illetve openFile s saveFile
fggvnyeket deklarlunk az adatok beolvassra s elmentsre.
A vals adatokat egy QList tpus listban troljuk, ezekre a state tagvl-
tozval hivatkozunk, lekrdezni 'ket pedig a getState fggvnnyel tudjuk.
Pldnkban az adatforrs bizonyos idnknt egy jabb szmot kld, ezt a
dokumentum hozzfzi a korbbi adatlista vgre. Erre szolgl az appendData
fggvny, amelyet szlotknt definilunk, hogy lehetsg legyen aszinkron m-
don msik szlbl kldeni az jabb adatokat, ahogyan azt vals krnyezetben
egy kls eszkztl vrnnk. Ha pldul a listanzeten keresztl is lehetsg
lenne jabb elemek beszrsra, akkor az a nzet is ugyanezt a fggvnyt
hasznlhatn az jonnan beszrt adat jelzsre.
A fentiek alapjn nzzk meg a dokumentumosztly fggvnyeinek imp-
lementcij t:
Document::Document(Q0bj ect*parent):
QObj ect(parent)
{
state=newQList<double>();
v iews=newQList<View*>;
}
v oidDocument::addView(View*v iew){
this->v iews->append(v iew);
}
v oidDocument::remov ev iew(v iew*v iew)
{
this->v iews->remov eAll(v iew);
}
QList<double>*Document::getState(){
returnthis->state;
v oidDocument::appendData(doublev alue){
this->state->append(v alue);
updateAllViews();
boolDocument::openFile(QStringfileName){
this->filename=fileName;
QFilefile(fileName);
i f(!file.open(QI0Dev ice::ReadOnly I QI0Dev ice::Text))
returnfalse;
QTextStreamin(&file);
495
8. fejezet: A Qt keretrendszer programozsa
while (! in.atEnd()) {
QString valueStr = in.readLine();
double value = valueStr.toDouble();
this->state->append(value);
updateAllviews();
return true;
}
bool Document: :saveFi 1 e(){
QFile fi 1 e(fi 1 ename) ;
f ( ! fi 1 e . open(Qi0Devi ce :writeOnly QI0Devi ce: :Text))
return fal se;
QTextStream out (&fi le) ;
QL
-
i stiterator<doubl e> iterator(*state);
while (i terator .hasNext()){
out i terator. next() " \ n" ;
return true;
}
void Document::updateAllviews() {
QListIterator<View*> iterator(*views);
whi le (i terator . hasNext())
{
iterator.next()->updateView();
}
Az updateAllViews defincijban a QListlterator segtsgvel vgigiterlunk
a nzetek listjn. A QListhez hasonlan a QListIterator is egy sablonosztly,
inicializlskor t kell adni a konstruktornak azt a listt, amelyet be szeret-
nnk jrni. Ezutn az itertorobjektum hasNext fggvnyvel krdezhetjk
le, hogy van-e mg elem a listban, s ha igen, akkor azt a next fggvnnyel
krhetjk el. (Termszetesen for ciklussal is bejrhatjuk a listt, a size fgg-
vnnyel lekrdezhet a mrete s a hagyomnyos indexels [ ] opertor is
hasznlhat.) A ciklus belsejben minden egyes nzetnek meghvjuk az update-
View fggvnyt, amely egy, a View osztlyban deklarlt virtulis fggvny, gy
minden leszrmazott nzetosztly rendelkezik ilyen metdussal.
rdemes rviden beszlni az openFile fggvnyrl, amely egy adott nev
llomnyt nyit meg. Ehhez a QFile osztlyt hasznljuk. Az open metdussal
lehet hozzfrni egy llomnyhoz. A fggvny argumentumban jelezni kell,
hogy milyen mveletet szeretnnk az llomnyon vgrehajtani. A QText-
Stream osztly biztost egy olyan szvegfolyamot, amellyel olvasni tudjuk az
llomny tartalmt. Felttelezzk, hogy a beolvasott llomny minden egyes
sora egy darab double tpus szmot tartalmaz, betlts utn ezek lesznek a
dokumentum kezdeti adatai.
496
8.5. A dokumentum/nzet architektra
8.5.3. A nzetosztlyok
A nzetosztlyok egy kzs sbl szrmaznak, amelyet a View osztly defini-
l. A kzs s biztostja azt az interfszt, amelyen keresztl a dokumentum
rtesteni tudja a nzeteket:
#ifndefVIEW_H
#defineVIEW_H
#include"document.h"
#include<QtGui>
#include<QtCore>
classDocument;
classView: public QWidget
{
Q_OBJECT
public:
explicitv iew(Qwidget*parent=0);
v irtualv oidupdateView();
v oidsetDocument(Document*doc);
signals:
public slots:
protected:
Document*document;
} ;
#endif//VIEW_H
A nzet teht egy referencit tartalmaz a dokumentumra, s egy updateView
fggvnyt definil, amely virtulis, gy a leszrmazott konkrt nzetek fell-
definilhatjk:
View::View(QWidget*parent):
QWidget(parent){ }
v oidView::setDocument(Document*doc){
this->document=doc;
updateView();
v oidView::updatev iew(){ }
497
8.fej ezet:AQtk eretrendszerprogramoz sa
A nzet implementcijban egyedl a setDocument fggvnyt emeljk ki: ezzel
tudjuk belltani a nzethez tartoz dokumentumot Amint a bellts megtr-
tnt, meghvjuk az updateView fggvnyt is, hogy az jonnan hivatkozott
dokumentum alapjn a nzet mris frissljn. Az adott nzethez tartoz doku-
mentumot, akr a konstruktorban is tadhatnnk, mivel minden egyes nzet-
hez biztosan tartozik pontosan egy olyan dokumentum, amelyet megjelent.
Ktfle nzetre van szksgnk, ezrt kt osztlyt szrmaztatunk le a
View-bl. Az els egy tblzatban, pontosabban egy listban rja ki az adatokat,
ez a TableView, a msik hisztogram formjban rajzolja ki, ez a DiagramView.
A lists megjelents valamivel egyszerbb, mert itt a Qt beptett vezr-
ljt a QListWidgetet hasznljuk a megjelentshez:
#ifndefTABLEVIEW_H
#defineTABLEVIEW_H
#include<QtGui>
#include"v iew.h"
classTableView:publicvi ew
{
Q_OBJECT
public:
explicitTablev iew(0widget*parent=0);
v oidupdatev iew();
signals:
publicslots:
protected:
QListwidget*list;
QVBoxLay out*lay out;
};
#endif//TABLEVIEW_H
Az osztly tartalmaz egy referencit egy QListWidget tpus vezrlre, amely
az adatok megjelentsre szolgl. Tovbb felldefiniljuk az updateView
fggvnyt, amelyet a View sosztlyban definiltunk virtulis fggvnyknt:
Tablev iew::Tablev iew(0widget*parent):
vi ew(parent)
{
lay out=newQVBoxLay out;
this->setLay out(lay out);
list=new stwidget;
1ay out->addwidget(1st);
}
498
8.5.A dokumentum/nzet architektra
v oidTablev iew:updateView(){
1ist->clear();
Q^ist<double>*state=document->getStateO;
QListIterator<double>terator(*state);
whi1e(iterator.hasNext())
{
doublev alue=iterator.next();
1st->additem(Qstring:number(v alue));
}
A konstruktorban egy elrendezskezel objektum segtsgvel elhelyezzk a
listavezrlt. Az updateView fggvnyt akkor hvjuk meg, amikor a dokumen-
tum tartalma a korbban megjelentetthez kpest frisslt, ezrt ilyenkor jra
kell rajzolni a nzetet. Jelen esetben ez azt jelenti, hogy ki kell trlni a list-
bl az eddig trolt elemeket, lekrdezni a dokumentumtl az aktulis adato-
kat s hozzadni ket a listhoz.
Knnyen tudnnk mdostani a nzetet gy, hogy a felhasznl j rtket
is hozz tudjon adni ezen keresztl a dokumentumban trolt adatokhoz: ehhez
egyszeren arra lenne szksg, hogy pldul elhelyezznk egy QPushButton
tpus gombot, s megnyomsval feliratkozzunk egy szlotfggvnnyel. Ebben
meghvhatjuk a dokumentum appendData fggvnyt, amelynek tadunk
egy vletlen, 0 s 10 kztti double rtket, vagy beolvashatjuk ezt az rtket
a felhasznltl egy dialgusablakon keresztl. Ezutn a dokumentumban
mr automatikusan meghvjuk mindegyik nzeten az updateView fggvnyt,
gy a tbbivel egytt az aktulis nzet amelyen keresztl a mdosts tr-
tnt ugyancsak frissl.
Valamivel bonyolultabb a hisztogramos nzetet megvalst DiagramView
osztly, ezt egy custom widgetknt definiljuk. Ebben a nzetben a doku-
mentumban trolt adatokat egyms alatt, 10 pixel magas tglalapokkal br-
zoljuk, a tglalapok szlessge az egyes adatok rtkvel arnyos. 10-es rtk
esetn a tglalap a vezrl teljes szlessgt kitlti, 0-nl pedig 0 pixel a sz-
lessge. Elfordulhat, hogy tbb adat van, mint amennyivel egy 10 pixel ma-
gas tglalapot ki tudunk rajzolni egyms al a vezrl terletre, ilyenkor
csak a lista vgn lv (legfrissebb) adatokat jelentjk meg.
Ebben a vezrlben a QPainter osztly segtsgvel rajzolunk a vezrl fel-
letre, ezrt felldefiniljuk a paintEvent virtulis metdust (lsd korbban is).
A nzet implementcijnl alkalmazunk egy fontos mdszert, amelyet
gyakran hasznlunk sajt vezrlk ksztsekor Amikor maga a rajzols tbb
lpsbl ll, vagy gyakran kell frissteni a nzetet, a megjelents kzben azt
tapasztalhatja a felhasznl, hogy a vezrl villog. Erre a problmra egy sz-
les krben alkalmazott s tmogatott megolds a kettsbuffer-technika vagy
msknt a virtulis ablakok mdszere. A technika lnyege az, hogy ltreho-
zunk egy, a kpernyvel kompatibilis felpts memriaterletet amelyet a
Qt keretrendszerben a QPixmap osztllyal runk le , s arra rajzolunk, majd
a megjelentskor a memriaterletet egy mvelettel a kpernyre msoljuk.
4 99
8.fej ezet:AQtk eretrendszerprogramoz sa
A rajzols ugyangy trtnik, mintha a sajt vezrlnk terletre rajzol-
nm,(lsd a QPainterrel kapcsolatban is). A villogsnak kt oka is lehet: az
egyik az, hogy maga a rajzols tbb lpsbl ll, a msik pedig az, hogy a raj-
zols mvelete hossz, s gyakran kell ismtelni. A Qt keretrendszer 4 -es
verzija ta a vezrlk az els problmt automatikusan kezelik, vagyis ez
nmagban nem vezet villogshoz. Ms keretrendszerek hasznlatakor ez
nincs felttlenl biztostva, ezrt rdemes lehet megfontolni a kettsbuffer-
technika alkalmazst A msodik problma esetben viszont mindenkppen
rdemes hasznlni ezt a mdszert. Tegyk fel ugyanis, hogy a teljes kirajzo-
lst a paintEvent fggvnyen bell valstjuk meg, vagyis itt lekrdezzk a
dokumentumtl az adatokat, s a megfelel logikval kirajzoljuk ket.
A paintEvent nemcsak akkor fut le, amikor a dokumentum tartalma frissl,
hanem amikor pldul a takarsban lv nzetnk eltrbe kerl. Ha nzet
frisstse sorn a kirajzoland kpet a memriban troljuk, akkor elg egy-
szer ezt tmsolni, ahelyett, hogy a bonyolult s hosszadalmas logikval j-
bl ellltannk:
#ifndefDIAGRAMVIEW_H
#defineDIAGRAMVIEW_H
#include<0tGui>
#include"v iew.h"
classDiagramView: publicv iew
{
Q_OBJECT
public:
explicitDiagramView(QWidget*parent= 0);
v oidupdatev iew();
signals:
publicslots:
v oidpaintEv ent(0P aintEv ent*);
v oid resizeEv ent(QReszeEv ent*);
protected:
v oidupdate8uffer();
QP ixmap*buffer;
};
#endif//DIAGRAMVIEW_H
Nzzk meg teht, hogy a DiagramView osztlyban hogyan valstjuk meg a
kettsbuffer-technikt Szksg van egy QPixmap tpus bufferre (buffer),
amelyre majd rajzolni tudunk, s szksg lesz egy fggvnyre (updateBuffer),
500
8.5. A dokumentum/nzet architektra
amely majd a dokumentum aktulis llapota alapjn frissti a buffert. Ami-
kor a nzetet frisstjk, akkor a buffert is jra kell rajzolni, a paintEvent
fggvnyen bell pedig csak a buffer tartalmt kell tmsolni. A kirajzoland
tartalom azonban nemcsak a dokumentum llapottl fgghet, hanem a ve-
zrlnk mrettl. is. Ezrt szksg van a resizeEvent felldefinilsra is,
amely a vezrl tmretezsekor hvdik meg, ebben ugyanis szintn frisste-
ni kell a buffer tartalmt.
A fenti megfontolsok alapjn nzzk meg a nzet fggvnyeinek imple-
mentcijt:
Di agramVi ew: :Di agramVi ew(QWi dget *parent) :
View(parent)
{
thi s->setmi nimum5i ze(200 , 100) ;
buffer = NuLL;
}
void Di agramview: :pal ntEvent(QPai ntEvent * pai nEvent){
QPai nter pai nter(thi s) ;
if (buffer ! = NULL)
pai nter . drawPi xmap(rect () , *buffer) ;
void Di agramVi ew: : updatevi ew(){
updateBuffer ;
update() ;
void Di agramVi ew: updateBuffer
if (buffer ! = NULL)
del ete buffer;
buffer = new QPi xmap(rect si ze()) ;
QPai nter pai nter(buffer) ;
pai nter. setBrush(Qt: :whi te) ;
pai nter . fi 11Rect(rect() , Qt : :whi te) ;
pai nter. setPen(Qt: : bl ue) ;
QList<double> * data =this->document->getstate();
0/11'
int barHeight = 10;
int maxitems = rect().height() / barHeight;
int index;
int offset = 0;
for (index = data->size() - maxitems < 0 ? 0 :
data->size() - maxitems; index<data->size(); index++)
double value = data->at(index);
painter.drawRect(0, offset*barHeight,
(value/10)*rect().width(), barHeight);
offset ++;
501
8. fejezet: A Qt keretrendszer programozsa
v oidDiagramv iew;:resizeEv ent(QResizeEv ent*resizeEv ent){
updateBuffer();
update();
A paintEvent tmsolja a buffer tartalmt a vezrlre, ehhez a QPainter osz-
tly drawPixmap fggvnyt hasznljuk. Fontos ellenrizni eltte, hogy a
buffer valban megfelelen lett-e inicializlva, mert amg mg nem rendeltnk
dokumentumot a nzethez, addig nem trtnik meg a bufferbe rajzols sem.
Az updateView fggvnnyel rtesl a nzet a dokumentum vltozsrl,
ezrt ebben frissteni kell a buffert, majd hogy a vltozs meg is jelenjen
meg kell hvni az update fggvnyt, amely egy jrarajzolsi jelzst kld az
adott vezrlnek. Lehetsg van az update helyett a repaint fggvny haszn-
latra is.
A resizeEvent fggvnyben, a vezrl mretnek megvltozsakor ugya-
nezt a logikt kell megrni, frissteni a buffert, majd az update hvssal meg-
jelenteni a friss tartalmat.
A tartalom ellltst az UpdateBuffer fggvny vgzi. Ebben a rajzols
ugyangy, egy QPainter objektummal trtnik, mintha magra a vezrlre
rajzolnnk kzvetlenl, csak itt a memriabeli kp mutatjt kell tadni a
konstruktorban. A QPixmap pldnyokat az inicializls utn nem lehet t-
mretezni, ezrt a fggvny minden egyes futtatsakor j QPixmap pldnyt
hozunk ltre. A tovbbi kdrszlet a korbban lert megjelentst vgzi el, va-
gyis kiszmtja, hogy hny tglalap fr el a vezrl terletn, s ettl fggen
kirajzolja az utols nhny adatnak megfelel tglalapot. A barHeight loklis
vltoz rgzti, hogy a megjelentett tglalapok magassga 10 pixel, a max-
Items loklis vltozban troljuk azt, hogy ekkora tglalapokbl legfeljebb hny
darab fr el a vezrl aktulis terletn. A for ciklusban a data gyjtemnyben
trolt utols maxltems darab elem indexn iterlunk vgig. Termszetesen, ha
a data elemeinek a szma kisebb, mint a maximlisan megjelenthet elemek
szma, akkor az sszeset kirajzolja a program. A QList generikus gyjtemny
elemeinek a szmt a size fggvnnyel, mg egy adott indexhez tartoz elemet
az at fggvnnyel krdezhetnk le. Az offset loklis vltozt hasznljuk arra,
hogy megadjuk, hnyadik tglalapot razoljuk ki, ez azrt fontos, mert a kiraj-
zolt tglalapok szmtl fgg, hogy a tglalap bal fels sarknak mi legyen a
fggleges koordintja. Azrt nem a for ciklus index nev fut vltozjt
hasznljuk erre, mert nem biztos, hogy a gyjtemny minden elemt megje-
lentjk. Kiemelend mg a QPainter osztly drawRect fggvnye, amely az
aktulis tollal s ecsettel kirajzol egy tglalapot. A drawRect fggvnynek
tbbfle paramterezse is ltezik, a fenti pldban elszr a bal fels sarok
vzszintes s fggleges koordintit, majd a tglalap szlessgt s magas-
sgt kell tadni.
502
8.5.Adok umentum/n zetarchitek tra
8.5.4. Tovbbi osztlyok
A teljessg kedvrt bemutatjuk a DataSource osztly defincijt is, amelynek
segtsgvel egy adatforrst tudunk a dokumentumokhoz kapcsolni. Egy vals
alkalmazsban ennek a komponensnek a segtsgvel fogadnnk a kls eszkz-
rl rkez adatokat. Ebben a pldban egyszeren egy vletlenszm-genertor
kld msodpercenknt jabb mrsi eredmnyeket" a dokumentumosztly-
nak.m A dokumentum appendData fggvnye egy szlot, gy a msik szlban fut
adatforrs a szignl-szlot mechanizmusra ptve kldhet rtestst:
#ifndefDATASOURCE_H
#defineDATASOURCE_H
#include<QtGui>
#include"document.h"
classDocument;
classDataSource:publicQObj ect
{
Q_013 7ECT
public:
explicitDataSource(Qobj ect*parent=0);
v oidsetDocument(Document*doc);
signals:
v oiddataReceiv ed(doubledata);
publicslots
v oidtimerTimedOut();
v oidstopTimer();
priv ate
Document*document;
QTimer*timer;
;
#endif//DATASOURCE_H
A DataSource osztly deklarcija a kvetkez fontosabb tagokat tartalmazza:
idzt (timer), timerTimedOut s stopTimer szlotfggvnyek, illetve a data-
Received szignl.
11
Jelen trgyalsban a hangsly az adatforrs s a dokumentumosztly kztti kommuni-
kcin van, a mrsi adatok rkezst csak szimulljuk. A gyakorlatban az adat rkezhet
egy eszkzvezrltl, hlzatrl, msik szltl s szmos egyb mdon.
503
8.fej ezet:AQtk eretrendszerprogramoz sa
Az idztshez a Qt beptett idztosztlyt, a QTimert hasznljuk.
A QTimer objektumok a timeout szignllal jelzik, hogy eltelt az elre bell-
tott id, erre a timerTimedOut szlottal iratkozunk fel. A dataReceived szignl-
lal jelez az adatforrs a dokumentumnak, hogy j adat rkezett. A stopTimer
fggvnyben lltjuk le az idztt, amikor mr nincsen r szksg, mert
amikor egy dokumentumot bezrunk, akkor a hozzkapcsold adatforrsban
mkd idztt is felszabadthatjuk:
DataSource::DataSource(Q0bj ect*parent):
QObj ect(parent){ }
v oidQataSource::setDocument(Document*doc){
this->document=doc;
timer=newQTimer(this);
connect(timer,SIGNAL(timeout())this,SLOT(timerTimedOut0)) ;
connect(this,SIGNAL(dataReceiv ed(double)),doc,
SLOT(appendData(double)),Qt::QueuedConnection);
timer->start(1000);
v oidDataSource::merTimedOut(){
emitdataReceiv ed((double)(qrand()%100)/10.0);
}
v oidDataSource::stopTimer(){
this->timer->stop();
}
A DataSource osztly setDocument fggvnyvel tudjuk az adatforrst egy
dokumentumhoz csatolni, ilyenkor indtjuk el az idztt, amelynek a jelzs-
rl a timerTimedOut szlottal kapunk rtestst. Az idztt a QTimer osztly
start metdusval indtjuk el. Szintn a setDocument fggvnyben ktjk sz-
sze a dataReceived szignlt s a dokumentum appendData szlotfggvnyt.
A timerTimedOut szlotban a qrand fggvnnyel generlunk egy vletlen
szmot, majd ezt normalizlva egy 0 s 10 kztti vletlen rtkk generl-
juk, kibocstjuk a dataReceived szignlt, jelezve, hogy j adat rkezett. Vge-
zetl pedig a stopTimer szlot az idzt lelltsrt felels.
A DocumentWindow osztly sszefogja s megjelenti az egy dokumen-
tumhoz tartoz nzeteket. Ismt hangslyozni kell, hogy ez az osztly nem
kpezi a dokumentum/nzet architektra rszt.
A DocumentWindow egy olyan QWidgetbl szrmaz vezrl, amely egy
vzszintes elrendezskezel objektum segtsgvel kirajzolja az ablakhoz az
addView fggvnnyel hozzadott nzeteket. A DocumentWindow egy referen-
cit trol a dokumentumra, s ha ltezik, akkor a dokumentumhoz kapcsolt
adatforrsra is:
504
8.5.Adok umentum/n zetarchitek tra
#ifndefDOCUMENTWINDOW_H
#defineDOCUMENTWINDOW_H
#include<QtGui>
#include"document.h"
#include"datasource.h"
classDocument;
classv iew;
class DataSource;
classDocumentwindow: public Qwidget
{
Q_OBJECT
public:
explicitDocumentwindow(Qwidget*parent =0);
v oidsetDocument(Document*doc);
v oidsetDataSource(DataSource*source);
DataSource*getDataSource();
v oidaddv iew(v iew*v iew);
Document*getDocument();
signals:
public slots:
priv ate:
Document*document;
priv ate:
QHBoxLay out*lay out;
DataSource*source;
};
#endif /7 DOCUMENTWINDOW_H
Az implementciban csak a setDataSource fggvny rdemel kln emltst.
Ezzel lltjuk be az adatforrs-referencit egy j adatforrsra. A bellts
utn az adott vezrl destroyed szignljt sszektjk az adatforrs stop-
Timer szlotjval, gy az adott ablak bezrsakor az adatforrs is befejezi az
adatok kldst:
Documentwindow::Documentwindow(Qwidget*parent):
Qwidget(parent)
this->lay out=newQHBoxLay out;
this->setLay out(lay out);
this->source=NULL;
}
505
8.fej ezet:AQtk eretrendszerprogramoz sa
v oidDocumentwindow::setDOCUment(DoCUment*doc){
this->document=doc;
}
v oidDocumentWindow::addView(v iew*v iew){
this->lay out->addwidget(v iew);
this->update();
}
Document*Documentwindow::getDocument(){
returnthis->document;
v oidDocumentWindow::setDataSource(DataSource*source){
this->source=source;
connect(this,SIGNAL(destroy ed()),source,SLOT(stopTimer()));
}
DataSource*Documentwindow::getDataSource(){
returnthis->source;
}
Vgezetl bemutatjuk az alkalmazsosztly implementcijt:
mDimainWindow::MDIMainwindow(Qwidget*parent):
QMainwindow(parent)
{
mdiArea=newQMdiArea;
this->setCentralwidget(mdiArea);
documents=newQList<Document*>;
fileMenu=this->menuBar()->addmenu(tr("&File"));
fileToolbar=this->addToolBar(tr("File"));
openDocumentAction=newQAction(tr("&Open"),this);
openDocumentAction->setIcon(QIcon::fromTheme("document-open"));
openDocumentAction->setShortcut(QKey Seguence::Open);
fileMenu->addAction(openDocumentAction);
fileToolbar->addAction(openDocumentAction);
connect(openDocumentAction,SIGNAL(triggered()),this,
SLOT(open()));
sav eDocumentAction=newQAction(tr("&Sav e"),this);
sav eDocumentAction->seticon(QIcon::fromTheme("document-sav e"));
sav eDocumentAction->setShortcut(QKey Seguence::Close);
fileMenu->addAction(sav eDocumentAction);
fileToolbar->addAction(sav eDocumentAction);
connect(sav eDocumentAction,SIGNAL(triggered()),this,
SLOT(sav e()));
506
8.5.A dokumentum/nzet architektra
attachDataSourceAction=newQAction(tr("&Attach"),this);
attachDataSourceAction->
setIcon(QIcon::fromTheme("sy stem-run"));
fileToolbar->addAction(attachDataSourceAction);
connect(attachDataSourceAction,SIGNAL(triggered()),this,
SLOT(attachSource()));
exitAction=newQAction(tr("E&xit"),this);
exitAction->setIcon(Qicon::fromTheme("application-exit"));
exitAction->setShortcut(Qxey Sequence::Quit);
filemenu->addAction(exitAction);
connect(exitAction,SIGNAL(triggered()),this,sLOT(close()));
}
v oidmDimainwindow::open(){
QStringfileName=QFileDialog::getOpenFileName(this,
tr("Opendocument"),"/Documents",
tr("Documentfiles(*.data)"));
if(fileName=="")
return;
Document*doc=newDocument;
this->documents->append(doc);
doc->openFile(fileName);
Documentwindow*w=newDocumentwindow;
w->setObj ectName("Documentwindow");
QMdiSubwindow*wContainer=this->mdiArea->addSubwindow(w);
w->setDocument(doc);
wContainer->setwindowTitle(fileName);
Tablev iew*table=newTablev iew;
table->setDocument(doc);
w->addv iew(table);
doc->addv iew(table);
Diagramv iew*diagram=newDiagramv iew;
diagram->setDocument(doc);
w->addv iew(diagram);
doc->addv iew(diagram);
w->show();
v oidmDIMainwindow::sav e(){
QMdisubwindow*subwindow=this->mdiArea->activ esubwindow();
if(subwindow==NULL)
return;
Documentwindow*w=
subwindow->findChild<Documentwindow*>("Documentwindow");
w->getDocument()->sav eFile();
}
507
8. fejezet: A Qt keretrendszer programozsa
v oidmDimainwindow::attachSource(){
Qmdisubwindow*subwindow=this->mdiArea->activ eSubwindow();
if(subwindow== NULL)
return;
Documentwindow*w=subwindow->
findchild<Documentwindow*>("Documentwindow");
if(w==NULL)
return;
if(w->getDatasource()!=NULL)
return;
DataSource*source=newDataSource;
source->setDocument(w->getDocument());
w->setDataSource(source);
A konstruktorban felptjk a felhasznli felletet, ltrehozzuk a QAction
objektumokat, s elhelyezzk ket a menben s az eszkztrban. Az MDI
esetben az alkalmazs fablaknak kzponti vezrlje egy QMdiArea pl-
dny kell, hogy legyen.
Dokumentumot megnyitni az openDocumentAction segtsgvel tudunk,
ennek meghvsakor az open szlot fut le. A QFileDialog osztly statikus
getOpenFileName fggvnyvel megjelentnk egy dialgusablakot, amellyel
a .data kiterjeszts llomnyokat tudjuk kivlasztani. Ezutn ltrehozzuk a
dokumentumot s a hozztartoz kt nzetet. A kt nzetet nem kln abla-
kokban, hanem egy DocumentWindow pldnyban helyezzk el. A pldnynak
a setObjectName fggvnnyel adunk egy nevet, ez segt majd azonostani, ha
az adott elemet a vezrlk fastruktrjban akarjuk programozottan keresni
(lsd ksbb). A ltrehozott DocumentWindow pldnyt a QMdiArea osztly
addSubWindow fggvnyvel jelentjk meg egy jabb ablakknt a fablakon
bell. Ilyenkor a QMdiAren bell ltrejn egy QMdiSubWindow tpus ve-
zrl ez az addSubWindow visszatrsi rtke , amely felels a kirajzolt
ablak fejlcnek s keretnek a megjelentsrt. Ezen bell a kzponti vezr-
l lesz az addSubWindow fggvnynek tadott DocumentWindow pldny.
Az ablakot vgl a show fggvnnyel meg kell jelenteni.
Egy dokumentum aktulis llapott a save szlotfggvny menti el Amikor
a mentsi funkcit kivlasztjuk, az aktv ablak dokumentumt szeretnnk
menteni. Az aktv ablakot a QMdiArea osztly activeSubWindow fggvnyvel
krdezzk le, amely a korbbiakban elmondottak rtelmben egy QMdiSub-
Window pldnnyal tr vissza. Ennek a pldnynak a gyermekvezrlje az
adott dokumentumhoz tartoz DocumentWindow, amelyet legegyszerbben
a findChild sablonfggvnnyel krdezhetnk le. Ennek meg kell adni az
adott vezrl tpust s az objektum nevt, amelyet korbban belltottunk
a setObjectName fggvnnyel. gy megszereztk a referencit az aktv Docu-
mentWindow pldnyra, ettl mr lekrdezhet a dokumentum. Ezt a doku-
mentumot kell elmenteni a saveFile fggvnnyel.
508
8.6. Tovbbi technolgik
Az attachSource fggvny hasonlkppen mkdik. Miutn elrtk az ak-
tv ablakhoz tartoz DocumentWindow pldnyt s azon keresztl a doku-
mentumot, ltrehozunk egy DataSource objektumot, s a dokumentumhoz
kapcsoljuk.
sszefoglalva elmondhatjuk, hogy az alkalmazs az, amely inicializlja s
mozgsba hozza" a dokumentum/nzet architektrt. Az MDIMainWindow
s a DocumentWindow kzsen ltjk el az alkalmazskomponens feladatait,
vagyis a dokumentumok s nzetek ltrehozst s kezelst, de ez nem rin-
ti a dokumentum- s a nzetosztlyok hasznlatt.
8.6. Tovbbi technolgik
A Qt keretrendszer nem csak egy grafikus vezrlket tartalmaz osztly-
knyvtr. Tbb modulja van, amely a felhasznli fellet mgtti alkalmazs-
logika platformfggetlen programozst segti. A Qt-t gyakran hasznljk
csak konzolos alkalmazsok fejlesztsekor is.
A kvetkezkben ttekintjk a Qt keretrendszer nhny fontos technolgi-
jt s az azokhoz kapcsold osztlyokat. Az els a QtCore alapmodul rsze, s
a tbbszl programozst teszi lehetv. A msodik az adatbziskezels elr-
st tmogat knyvtr, amely egy kln modulban, a QtSqlben tallhat. Vgl
bemutatjuk a hlzati kommunikci programozshoz hasznlhat osztly-
knyvtrat, a QtNetwork modult.
8.6.1. Tbbszl alkalmazsfejleszts
A Qt keretrendszer QtCore moduljnak rsze a tbbszl programozst lehe-
tv tv osztlyknyvtr. Ez tmogatja j szlak indtst s a szlak kzt-
ti szinkronizcit.
Tbbszl alkalmazs rsakor figyelni kell arra, hogy az objektumokat
melyik szlban hoztuk ltre. Egy QObject tpus objektumot csak abban
a szlban szabad ltrehozni, amelyben a szlobjektumot hoztuk ltre, s
gondoskodni kell a ltrehozott objektumok trlsrl, mieltt magt a szlat
trlnnk.
A szlak kztti szinkronizcit s kommunikcit tbbfle segdosztly
teszi lehetv. Korbban mr bemutattuk, hogy a Qt keretrendszer fontos tu-
lajdonsga az, hogy a szignl-szlot mechanizmus alkalmas arra, hogy tbb-
szl krnyezetben hasznljuk, azaz lehetsg van bizonyos szignlokat ms
szlakban fut szlotokkal sszektni. A keretrendszer lehetv teszi, hogy
minden szlnak legyen kln esemnykezel ciklusa, s ez teszi lehetv a
vrakozsisor-alap sszekttetsek hasznlatt.
509
8. fejezet: A Qt keretrendszer programozsa
Az j szlak programozsnak bemutatsa eltt tekintsk t rviden, ho-
gyan indul el egy alkalmazs fszla a Qt keretrendszerben. Minden alkal-
mazs a main fggvny futtatsval kezddik, ebben a korbbi pldknl
ltalban ltrehoztunk egy QApplication tpus objektumot, itt a main fgg-
vny vgn meghvtuk az exec metdust. Ez az objektum felels az alkalma-
zs fszlnak, a grafikus szlnak a futtatsrt. Az exec hvsakor valjban
a fszlhoz tartoz esemnykezel ciklus indul el. Erre az esemnykezel cik-
lusra azrt van szksg, hogy az opercis rendszertl rkez zeneteket,
illetve a QObject pldnyok kztti zeneteket kezelni tudjuk. Ezrt egy ilyen
alkalmazsobjektumbl csak egy lehet a programunkban. Ha nem grafikus
fellettel rendelkez, hanem ms Qt-funkcikat hasznl konzolos alkalma-
zst runk, akkor a QApplication helyett a QCoreApplicationt kell pldnyos-
tani. Ez az osztly a QApplication se, s ugyancsak elindt egy zenetkezel
ciklust, de nem a grafikus fellet szmra.
A felhasznli felletet alkot vezrl'k mindig az alkalmazs fszlban
futnak, ezrt ezekhez az objektumokhoz csak a fszlban szabad hozzfrni.
Tegyk fel, hogy egy grafikus fellettel rendelkez alkalmazsban egy gomb
megnyomsnak hatsra idignyes szmtsi mveletet vgznk el. Ezzel
az a problma, hogy ha a mveletnek nem indtunk j szlat, akkor az az al-
kalmazs fszlban fut, amely egyben a megjelentsrt is felels. A mvelet
hosszabb ideig blokkolja a szl mkdst, gy a grafikus fellet a felhasznl
szmra elrhetetlen lesz, mert a felhasznli esemnyeket a mvelet befeje-
zsig nem tudja feldolgozni. rdemes teht ekkor j szlat indtani Ilyenkor
meg kell oldani a kt szl kztti kommunikcit. Ha pldul a szmts
eredmnyt egy szvegdobozban akarjuk megjelenteni, akkor a msik szlbl
egy zenetet kell kldennk a fszlnak a mvelet vgn, ugyanis a msik
szlbl nem mdosthatjuk a fszlban lv objektumok, pldul a vezrl'k
llapott. Erre a problmra a legknyelmesebb megolds a szignl-szlot
mechanizmus hasznlata, ez ugyanis a programoz szmra tltszan kezeli
azt, hogy a szignlt publikl s a szlotot definil objektumok ugyanabban
vagy msik szlban futnak-e.
Egy szl indtshoz szksg van egy olyan objektumra, amely a QThread
osztlybl szrmazik A szlak a main fggvny helyett a QThread osztly run
metdusnak meghvsval indulnak el. Sajt szl definilshoz a QThreadbl
kell leszrmaztatni s fellrni a virtulis run metdust. A szl vgrehajtsa ak-
kor fejezdik be, amikor a run fggvny visszatr, pontosan gy, ahogyan az al-
kalmazs futsa is vget r, amikor a main fggvny befejezdik:
v oid QT;ktr
dmr14 .'0..4 .
A run lthatsga protected, ezrt a szl elindtshoz nem kzvetlenl ezt a
fggvnyt hvjuk meg, hanem a QThread start metdust. Egy adott szl l-
lapott az isRunning, illetve az isFinished metdusokkal lehet lekrdezni a
QThread objektumtl, tovbb hrom szignl is rendelkezsnkre ll, ame-
lyek jelzik, amikor a szl elindult (started), befejezte a futst (finished), il-
letve a szlat lelltottk mg annak befejezse eltt (terminated):
510
8.6. Tovbbi technolgik
bool QThread::isFinished O const
bool QThread::isRunning O const
void QThread::started
void QThread::finished
void QThread: :terminated
// signal
// signal
// signal
j szl indtsakor szksg lehet sajt esemnykezel ciklusra, ha pldul a
szignl-szlot mechanizmust szeretnnk hasznlni. Ennek elindtsra az exec
fggvnyt hasznljuk, ezt a run fggvnyen bell kell meghvni:
QT
bre4d
-
-'
Ilyenkor a szl folyamatosan fut, amg az esemnykezel ciklust le nem llt-
juk. A lelltshoz a szl quit vagy exit fggvnyt kell meghvni. A quit meg-
egyezik az exit(0) hvsval. Az exit paramtere a szl visszatrsi rtke lesz,
s a szl elindtshoz hasznlt exec fggvny ezzel tr vissza. Mindkt fgg-
vnyt szlotknt definiltk, gy szignlok segtsgvel is knnyen lelltha-
tunk egy szlat:
voi Qrh read : qui t ()
void QTh red : : exi t ( i nt returncode = 0 )
Feladat Ksztsnk egy grafikus fellettel rendelkez alkalmazst, amely a felleten tallha-
t nyomgomb megnyomsra indt egy j szlat, amelyben elvgez egy szmtsi mveletet,
majd annak az eredmnyt megjelenti.
Ezen a pldn megmutatjuk, hogyan tudunk j szlat indtani, hogyan defi-
niljuk azt, hogy az indtott szl milyen mveletet hajtson vgre, s hogyan
tudunk a szignl-szlot mechanizmus segtsgvel kommunikcit megvals-
tani klnbz szlak kztt.
A 8.9. brn lthat az alkalmazs kpernykpe. A mvelet, amelyet el-
vgznk a 12 s a 13 szmok sszegnek kiszmtsa, ezt a 12 + 13 = ?" sz-
veg kirsval jelezzk, amelyre egy QLabelt hasznlunk. Alatta helyezkedik
el egy QPushButton tpus nyomgomb, amellyel elindthatjuk a szmtst
vgz szlat. Legalul egy msik QLabelt helyeznk el, ez kezdetben nem tar-
talmaz semmilyen szveget, az eredmnyt jelenti meg, amikor megtrtnt a
szmts.
8.9. bra. Tbbszl alkalmazs fablaka
511
8. fejezet: A Qt keretrendszer programozsa
Kezdjk a szmtst a vgz szl megrsval:
/* calculatorthread.h */
#i fndef CALCULATORTHREAD_H
#defineCALCULATORTHREAD_H
#include <QThread>
cl ass CalculatorThread : public QThread
{
Q_OBJECT
public:
explicit cal cul atorThread(Q0bject *parent =0) ;
void run() ;
si gnal s :
void resultcomputed(i nt resul t) ;
public slots:
void startcomputi ng(int a, int b) ;
}
;
#endif /7 CALCULATORTHREAD_H
A CalculatorThread osztly a QThreadbl szrmazik. Felldefiniljuk a run
metdust, amelyben a szl elindtsakor lefut logikt rjuk meg. A szl elin-
dtsa utn vrakozunk, amg a startComputing szlot meg nem hvdik. Te-
ht a run fggvnyben egyszeren csak elindtjuk az esemnykezel ciklust
az exec meghvsval. A startComputing fggvny kt int tpus argumentu-
ma adja meg, hogy milyen szmokon kell az sszeadst elvgezni. A szmts
vgeztvel a szl egy szignlt bocst ki, amely tartalmazza a mvelet ered-
mnyt. Ez a resultComputed szignl. A startComputing maga is egy szlot-
fggvny, gy egy szignl segtsgvel meg tudjuk hvni.
A connect fggvny bemutatsakor mr sz volt a vrakozsisor-alap sz-
szekttetsekrl. Ha a szignlt publikl s a szlotot definil objektumokat
kln szlban hoztuk ltre, akkor ez az alaprtelmezett sszekttets-tpus.
Ilyenkor a szignl kibocstsa utn a vezrls nem blokkoldik, aszinkron m-
don elkldjk a szignlrl az zenetet a msik szlban fut objektumnak.
sszefoglalva teht a szlosztly mkdst: elindtsa utn vrakozik az
esemnykezel ciklus, amg az osztly startComputing szlotjnak meghvs-
val nem indtunk el egy szmtst. A mvelet elvgzst a resultComputed
esemny kibocstsval jelezzk:
512
8.6. Tovbbi technolgik
/*calculatorthread.cpp*/
#include"calculatorthread.h"
CalculatorThread::CalculatorThread(Q0bj ect*parent):
QThread(parent){ }
v oidCalculatorThread::run(){
exec();
}
v oidCalculatorThread::startComputing(inta,intb)
intresult=a+b;
sleep(3 );//gy m rt ny leghosszmv elet
emitresultComputed(result);
}
Maga a szmts amelyet a startComputing fggvny valst meg a kt
paramterknt kapott szm sszeadst jelenti, ezutn az eredmnyt a
resultComputed szignlon keresztl kldjk el. Azrt, hogy a szmts val-
ban idignyes legyen, a QThread sleep fggvnyvel elaltatjuk 3 msodperc-
re a szlat, mieltt az eredmnyt visszakldennk. Erre a sleep fggvnyt
hasznljuk:
Az szlosztlyunk hasznlathoz ezt pldnyostani kell, bektni a megfelel
szignlokat s szlotokat, majd elindtani a start fggvnnyel, ezeket a fel-
hasznli fellet kdjnak trgyalsa utn vesszk sorra:
/*resultwindow.h*/
#ifndefRESULTWINDOw_H
#defineRESULTWINDOW_H
#include<QtGui>
classResultWindow:publicQWidget
{
Q_OBJECT
public:
explicitResultWindow(QWidget*parent=0);
signals:
v oidstartComputing(inta,intb);
publicslots:
v oidresultComputed(intresult);
priv ateslots:
v oidbuttonClick ed();
513
8.fej ezet:Atk eretrendszerprogramoz sa
priv ate:
QLabel*1blTask ;
QP ushwitton*btnCompute;
QLabel*1blResult;
QVBoxLay out*lay out;
} ;
#endif//RESULTWINDOW_H
A felhasznli felletet a ResultWindow osztly tartalmazza. Az osztly tag-
vltozi az a hrom vezrl, amelyet elhelyeznk a felleten, s egy QVBox-
Layout tpus elrendezskezel, amely fgglegesen egyms al igaztja ket.
A startComputing szignllal jelezzk majd, hogy szeretnnk, ha kt int
tpus szmon elvgeznnk a szmtsi mveletet. Ezt ktjk ssze a szlob-
jektum azonos nev szlotjval. Deklarlunk tovbb egy buttonClicked
szlotot is, ezzel kapunk rtestst majd a gomb megnyomsrl:
/*resultwindow.cpp*/
#include"resultwindow.h"
ResultWindow::Resultwindow(Qwidget*parent):
QWidget(parent)
{
lay out=newQv 8oxLay out;
1blTask =newQLabel("12 +13 =?");
lay out->addwidget(1b1Task );
btnCompute=newQP ushButton("Sz m t s");
lay out->addwidget(btnCompute);
1blResult=new ;
lay out->addwidget(lblResult);
this->setLay out(lay out);
connect(btnCompute,siGNAL(click ed()),
this,SLOT(buttonClick ed()));
v oidResultwindow::buttonclick ed()
emitstartcomputing(12 ,13 );
v oidResultwindow::resultComputed(intresult){
lblResult->setText(Qstring::number(result));
514
8.6. Tovbbi technolgik
A konstruktorban ltrehozzuk a vezrlket s az elrendezskezel objektu-
mot, majd a connect fggvnnyel sszekapcsoljuk a nyomgomb clicked szig-
nljt az osztlyban definilt buttonClicked szlottal.
A fellet megjelentse utn teht addig nem trtnik semmi, amg a
gombot meg nem nyomjuk, ekkor meghvdik a buttonClicked szlot, amelyben
kivltjuk a startComputing szignlt. Az argumentumai a felleten is kirt 12
s 13 szmok lesznek. Ezutn vrakozunk, amg a szmts elvgzse utn
meghvdik a resultComputed szlot, amelynek a paramtere tartalmazza az
eredmnyt. Ezt a QLabel osztly setText fggvnyvel rjuk ki a felletre. Mi-
vel a szmtst kln szlban vgeztk, gy a felhasznli fellet tovbbra is
mkdkpes marad, s reagl a felhasznli esemnyekre:
/*main.cpp*/
#include"calculatorthread.h"
#include"resultwindow.h"
#include<QtCore>
#include<QtGui>
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
Resultwindow*window=newResultWindow;
CalculatorThread*thread=newCalculatorThread;
QObj ect::connect(window,SIGNAL(startComputing(int,int)),
thread,SLOT(startComputing(int,int)));
QObj ect::connect(thread,sIGNAL(resultComputed(int)),window,
SLOT(resultComputed(int))):
thread->start();
window->show();
returnapp.exec();
}
A programunk main fggvnyben inicializlunk egy ResultWindow s egy
CalculatorThread pldnyt. A felhasznli fellet miatt ltrehozzuk a QAppli-
cation objektumot is, amely a fszl elindtsrt felels. Ezutn trtnik a
szignlok s a szlotok sszekapcsolsa. Vgl a szlat a start fggvnnyel in-
dtjuk el, az ablakot pedig a show metdussal jelentjk meg.
A Qt keretrendszer a szlak indtsn s a szignl-szlot mechanizmuson
tl is biztost szolgltatsokat tbbszl programok tmogatsra. A 8.4. tb-
lzatban lthat nhny fontosabb osztly, amelyek a szlak kztti szinkro-
nizcit segtik.
515
8. fejezet: A Qt keretrendszer programozsa
8.4. tblzat. Szlak kztti szinkronizcit tmogat osztlyok
QMutex Klcsns kizrst (mutex) megvalst zr.
QReadWriteLock Hasonl a mutexhez, de az objektumokhoz val hozz-
frs sorn megklnbzteti az rsi s az olvassi
szndkot.
QSemaphore Szemafort megvalst osztly.
QWaitCondition Lehetv teszi, egy felttel ltrehozst, ennek a be-
kvetkeztig egy szl vrakozik. A felttelt teljesl-
st ms szlakbl tudjuk engedlyezni.
Ezek a szinkronizcis osztlyok a QT-szint reprezentcii az 5. Prhuza-
mos programozs fejezetben trgyalt megoldsoknak.
8.6.2. Adatbziskezels
sszetettebb informcihalmazzal dolgoz alkalmazsokban az adatokat lta-
lban nem egyszer llomnyokba mentjk, hanem valamilyen adatbziskezel
rendszert hasznlunk a trolsukra. Az adatbzisok SQL nyelv programoz-
shoz szksges felletet a QtSql modul biztostja.
A modul lehetsget teremt a klnbz adatbziskezel rendszerek egy-
sges s platformfggetlen elrsre. A modulban definilt osztlyok kt cso-
portba oszthatk: az adatbziskezel-fgg vezrl- (driver) rteg osztlyai
biztostjk a kommunikcit a klnbz platformokhoz, mg az SQL prog-
ramozi interfsz (SQL API) osztlyai biztostjk az platformfggetlen
SQL-alap alkalmazsfejlesztst.
A modul elrshez a forrsfjljainkban be kell pteni a megfelel oszt-
lyokat, vagy a kvetkez sor segtsgvel egyszerre tudjuk bepteni a teljes
modult:
# ncl < QtSgl>
>
A modul hasznlatt tovbb a projektllomnyban is jelezni kell. Az albbi
sorral adhatjuk meg azt, hogy a fordts sorn a linker a QtSql knyvtrat is
vegye figyelembe:
QT += 541
Feladat rjunk alkalmazst, amely csatlakozik egy adatbzishoz, amelyben knyvek cmeit s
szerzit troljuk egy tblban. A csatlakozs utn rjuk ki az adatbzis tartalmt a konzolra.
516
8.6. Tovbbi technolgik
Ennek a pldnak az elksztsben bemutatjuk, hogyan kell kapcsoldni egy
adatbzishoz, hogyan tudunk SQL nyelv parancsokat kldeni a programun-
kon keresztl, s hogyan tudjuk egy lekrdezs eredmnyt programozottan
feldolgozni. A tovbbiakban egy MySQl-tpus adatbziskezelt hasznlunk,
amelyben azt felttelezzk, hogy egy qtDatabase nev adatbzisban troljuk
az adatokat. Az adatbzisban egyetlen tblt definiltunk, ebben knyveknek
az adatait (egyedi azonost, cm s szerz) troljuk. A tbla neve Book, az
oszlopai pedig a 8.5. tblzatban lthatk.
8.5. tblzat. qtDatabase adatbzis Book tbljnak oszlopai
Oszlop neve Tpusa Lersa
I d Int(11)
varchar(255)
A knyv azonostja (elsdleges kulcs)
Title A knyv cme
Author varchar(255) A knyv szerzje
A programunk egyetlen main fggvnybl ll, itt ptjk fel a kapcsolatot,
kldjk el a lekrdezst, s rjuk ki az eredmnyt a hibakeres konzolra:
/*main.cpp*/
#include<QtCore>
#include<iostream>
#include<QDebug>
#include<QtSql>
intmain()
{
QSq1Databasedb=QSq1Database::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setpatabaseName("qtQatabase");
db.setuserName("dbUser");
db.setP assword("passw");
if(!db.open())
{
quebug()"Cannotconnecttodatabase...";
quebug()db.lastError();
return1;
QsqlQuery selectQuery ;
if(!selectQuery .exec("select
fromBook "))
{
cpebug()"Errorwithexecutingquery ";
517
8. fejezet: A Qt keretrendszer programozsa
whi le (sel ectQuery. next())
{
gtring title = selectQuery.val ue(1) toString();
QString author = selectQuery.val ue(2) .toString();
cpebug() author ": " title;
}
db. cl ose() ;
return 0;
}
Az adatbzis-elrshez hasznlt osztlyok bemutatsa eltt rdemes felhvni a
figyelmet arra, hogy a fenti main fggvnyben nem hoztunk ltre QApplication
objektumot, mivel itt nincsen szksgnk esemnykezel ciklusra: nem hasznl-
juk a szignl-szlot mechanizmust, s nem hasznlunk olyan osztlyokat, amelyek
ilyen ciklus megltt kvetelik.
Az adatbzishoz val hozzfrs lpsei minden alkalmazs esetben a
kvetkezk:
1. Felptjk a kapcsolatot: ehhez szksg van az adatbzis cmre s a
belpsi adatokra.
2 . Elkldnk az adatbzisnak egy SQL nyelv utastst.
3. Feldolgozzuk az utasts eredmnyt. Ha az utasts egy lekrdezs,
akkor annak visszatrsi eredmnyt soronknt tudjuk bejrni s fel-
dolgozni. Egyb esetben a visszatrsi rtk egy skalr.
4 . Lezrjuk az adatbziskapcsolatot.
Az adatbzishoz val hozzfrs mindig a kapcsolat felptsvel kezddik,
ezt egy QSq1Database pldnnyal rjuk le. Egy program fejlesztse sorn tbb
klnbz adatbziskapcsolatra is szksg lehet, gy tbb pldnyt is ltre-
hozhatunk, mindegyiket egyedi nvvel azonostjuk. Lehetsg van egy alapr-
telmezett kapcsolatot is ltrehozni az alkalmazson bell, ennek nem adunk
meg nevet, ez trtnik a pldaalkalmazsban is. A tovbbiakban hasznlt
fggvnyek nagy rszre igaz, hogy opcionlis paramterknt vrjk az adat-
bziskapcsolat nevt, ha ezt nem adjuk meg, akkor az alaprtelmezett kap-
csolatot hasznljk.
Minden kapcsolat ltrehozsnl meg kell adni az adatbzis tpust, ez
alapjn a Qt keretrendszer a tovbbiakban a megfelel vezrlt hasznlja
a kommunikcira. A fenti pldban a db vltoz lesz az alaprtelmezett kap-
csolat, amelyet a QSq1Database osztly statikus addDatabase fggvnyvel
hozhatunk ltre. Ez a fggvny egyben el is trolja a ltrehozott adatbzis-
kapcsolatokat egy bels listban:
518
8.6. Tovbbi technolgik
QSg1DatabaseQSg1Database::addDatabase(
constQString& t y p e ,
constQString& conne ct i onName =
QLatin1String(defaultConnection))
A fggvny msodik, opcionlis paramtere az adatbzis-kapcsolat neve.
A QMYSQL" szveg azt jelzi, hogy egy MySQL-tpus adatbzishoz akarunk
csatlakozni. Az 8.6. tblzatban olvashat nhny olyan vezrlnv, amellyel
tovbbi adatbziskezel rendszerekhez frhetnk hozz.
8.6. tblzat. A Qt keretrendszer adatbziskezel vezrlinek azonosti
Vezrlnv Adatbziskezel rendszer
QDB2 IBM DB2
QSQLITE SQLite (3-as verzi)
QSQLITE2 SQLite (2-es verzi)
QOCI Oracle Call Interface Driver
QPSQL PostgreSQL
QODBC ODBC-(Open Database Connectivity) kompatibilis adatbzis-
kezelk, pldul Microsoft SQL Server
Az adatbzis-kapcsolat pldnynak inicializlsa utn meg kell adnunk a
kapcsolds paramtereit, ezek az adatbzisszerver cme, az adatbzis neve,
illetve a felhasznl neve s jelszava. A fenti pldban az adatbzisszerver az
alkalmazssal egy gpen fut, ezrt a cme localhost.
Ahhoz, hogy a kapcsolat valban fel is pljn, meg kell hvni a kapcsolat
open fggvnyt, amelynek bool tpus visszatrsi rtke jelzi, hogy sikeres
volt-e a kapcsolds. Ha hiba trtnt, akkor arrl tovbbi informcit a QSql-
Database statikus lastError fggvnyvel krhetnk le:
QSglErrorQSg1Database::lastError()const
A QtSql modul tbbi osztlynl is ltalban ilyen mdszerrel lehet megtudni
az elfordul hibk pontos adatait. A fggvnyek tbbnyire csak azt jelzik,
hogy hiba trtnt, amelyet a lastError fggvnnyel lekrdezhetnk.
Ha a program sorn egy adatbzis-kapcsolatra mr nincsen szksgnk,
akkor eltvolthatjuk a listbl a QSqlDatabase statikus removeDatabase
fggvnyvel. Eltte azonban be kell zrni a kapcsolatot a close fggvnnyel.
A fenti pldban a felhasznl szmra megjelentend adatokat a hiba-
keres konzolra rjuk, amelyet a QDebug osztllyal rnk el. Ez az osztly
egy kimeneti adatfolyamot (output stream) biztost, amelyre a C++-ban meg-
szokott opertor segtsgvel tudunk adatokat kldeni. ltalban ezt az osz-
tlyt nem kell explicit mdon pldnyostani, elg, ha meghvjuk a qDebug()
fggvnyt, amely egy alaprtelmezett pldnnyal tr vissza.
519
8. fejezet: A Qt keretrendszer programozsa
A kapcsolat sikeres felptse utn lehetsgnk van SQL nyelv utast-
sokat kldeni az adatbzisnak. Egy SQL-parancsot a QSqlQuery osztllyal
rhatunk le, amelynek meg kell adni a parancs szvegt. A korbbiaknak
megfelelen, opcionlisan megadhat az adatbzis-kapcsolat is. Az utasts
tpustl fggetlenl az exec fggvnnyel tudjuk ezt lefuttatni:
bool QSql Query : : exec ( const QString & query )
bool QSql Query : :exec ()
Mind a konstruktornak, mind az exec fggvnynek tbbfle paramterezse
ltezik, az SQL-parancsot megadhatjuk a konstruktorban vagy az exec fgg-
vny argumentumn keresztl is. Az open fggvnyhez hasonlan ennek is a
bool tpus visszatrsi rtke jelzi, hogy trtnt-e hiba, ha igen, akkor annak
rszleteit a korbban ismertetett mdszerrel tudhatjuk meg.
Ha olyan utastst adunk ki, amelynek az eredmnye nem lekrdezs
(pldul insert utasts), akkor ezutn tbb feladatunk nincsen. A pldnk-
ban szerepl parancs azonban egy lekrdezs, eredmnye a Book tblban t-
rolt sszes sor. A QSqlQuery osztly segtsgvel a lekrdezs eredmnyt
soronknt tudjuk feldolgozni. Az eredmnyhez gy frnk hozz, mintha egy
virtulis kurzorunk (itertorunk) lenne, amellyel szekvencilisan haladha-
tunk az eredmny sorain. A kurzort tovbblptethetjk a next fggvnnyel,
illetve a kurzor ltal mutatott sornak lekrdezhetjk az adatait. A next fgg-
vny visszatrsi rtke bool tpus, minden lptets utn jelzi, hogy volt-e
tovbbi sor az eredmnyben. A kurzor kezdetben nem az els sorra mutat,
ahhoz, hogy a lekrdezs els sorhoz hozzfrjnk, eltte ugyangy meg kell
hvni a next fggvnyt, mint a ksbbiekben egy jabb sorhoz val ugrsnl.
Ha a lekrdezs eredmnye egyetlen sort sem tartalmaz, akkor mr az els
hvsnl false lesz a visszatrsi rtk. Annak a sornak az adatait, amelyre
ppen a kurzor mutat, a value fggvnnyel krdezhetjk le:
QVariant QSqlQuery: :val ue ( int index ) const
A fggvny egyetlen paramtere a sor egy oszlopnak indexe, visszatrsi rt-
ke pedig egy QVariant tpus objektum. A QVariant segtsgvel egysgesen
tudjuk trolni egy cella tartalmt annak tpustl fggetlenl. A QVariant tag-
fggvnyeivel a trolt adatot a megfelel Qt tpusra lehet konvertlni.
Az aktulis adat tpust a type fggvnnyel le is krdezhetjk:
Type QVari ant: :type () const
A visszatrsi rtk QVariant::Type felsorols tpus, ebben a lehetsges
adatbzistbla-tpusok vannak felsorolva. A konvertlshoz toT formj
fggvnyeket kell hasznlni, ahol T helyre a megfelel tpus azonostjt
kell behelyettesteni. Erre plda a fenti kdban lthat toString fggvny,
amely az adott rtket QString tpusv alaktva adja vissza. Ha olyan tpus-
520
8.6. Tovbbi technolgik
ra prblnnk talaktani a cella tartalmt, amilyenre nem lehet, akkor az
adott tpustl fgg, hogy mi lesz a fggvnyhvs eredmnye. Termszetesen
lehetsg van ellenrizni is mg az talakts eltt, hogy talakthat-e az
adat a megfelel tpusra, ehhez hasznlhatjuk a canConvert fggvnyt:
bool QVariant::canConv ert(Ty pet)const
A 8.7. tblzatban nhnyat sorolunk fel a tpusok lehetsges rtkei kzl,
s jelezzk, hogy milyen Qt-osztlytpusra lehet az adott rtket talaktani.
8.7. tblzat. A QVariant osztlyban trolhat legfontosabb adattpusok
Konstans Adattpus Lers
QVariant::Inoalid hibs adat nincs tpus
QVariant::Bitmap QBitmap kp
QVariant::Bool bool logikai igaz/hamis rtk
QVariant::Date QDate dtum
QVariant::Daterime QDateTime dtum s idpont
QVariant::Time QTime idpont
QVariant::String QString szveg
QVariant::Int int egsz szm
A pldban az 1-es s a 2 -es index, azaz a msodik s a harmadik oszlop tar-
talmt alaktjuk t QString tpusra minden egyes sorban, s ezeket rjuk ki
a felhasznlnak. Az els oszlop az azonostt tartalmazza, erre itt nincsen
szksg.
A program vgn lezrjuk az adatbzis-kapcsolatot a close metdussal. Ter-
mszetesen a kapcsolat ltrehozsa utn tbb SQL-utastst is vgrehajthattunk
volna, nem kell minden egyes parancshoz jabb kapcsolatot inicializlni.
8.6.3. Hlzati kommunikci
Hlzati kommunikci programozsra is sajt osztlyknyvtrat biztost a
Qt keretrendszer, ezeket a QtNetwork modulban tallhatjuk sszegyjtve.
Segtsgkkel TCP/IP alap kliens-, illetve szerveralkalmazsokat kszthe-
tnk. A modul biztost nhny alacsony szint kommunikcit megvalst
osztlyt (pldul QTcpSocket, QUdpSocket, QTcpServer), illetve nhny ezek-
re pl alkalmazsrtegbeli protokollt egysgbe zr osztlyt (pldul http
s ftp kommunikci hasznlatra) is. A magasabb szint kommunikci is
termszetesen az alacsonyabb szint programozi interfszre pl, ezrt az
albbiakban ez utbbinak a hasznlatt trgyaljuk rszletesen.
521
8. fejezet: A Qt keretrendszer programozsa
A Qt keretrendszerben a hlzati programozs koncepcija alapveten
megegyezik a korbban bemutatott mdszerekvel. Az alaposztlyok a QTcp-
Socket, illetve a QUdpSocket, amelyek ahogyan a nevk is mutatja socke-
teket rnak le. Mind a szerver-, mind a kliensoldalon egy-egy socketosztlyon
keresztl trtnik az adatok rsa s olvassa. A knnyebbsg a Qt keretrend-
szer hasznlatban a korbbi megoldssal szemben elszr is a TCP-kapcsolat
szerveroldali programozsban rezhet: a QTcpServer osztly nagyban egy-
szersti a szerveroldali kapcsolat kiptst. Ez rja a le azt a szerverszolglta-
tst, amely egy adott cmen s porton vrja a berkez kapcsolatokat. Amikor
egy j kapcsoldsi krelem rkezik, akkor felpt egy QTcpSocketet. A mso-
dik knnyebbsg az, hogy a mr megszokott mdon, a szignl-szlot mecha-
nizmus segtsgvel kapunk rtestst minden olyan esemnyrl, amely a
socketeken trtnik. gy a hlzati programozs sorn valjban ltre kell
hozni a megfelel objektumokat, ezekban belltani a megfelel hlzati c-
meket, majd azokra az esemnyekre, amelyeket az alkalmazsunkban kezel-
ni szeretnnk, szlotfggvnyekkel kell feliratkoznunk.
A hlzatkezel modul hasznlathoz a projektllomnyt ki kell egszte-
nnk az albbi sorral. Ezzel jelezzk, hogy a linker a hlzati modul osztly-
knyvtrt is hasznlja:
QT += network
Ebben a fejezetben a TCP-csomagokkal trtn kommunikcit trgyaljuk
rszletesen, az UDP-alap kommunikci ehhez hasonl mdon trtnik.
Feladat rjunk egy egyszer csevegalkalmazst. A szerveroldali program tudjon klienseket
fogadni, s amennyiben egy kliens zenetet kld, azt tovbbtsa az sszes tbbi csatlakozott
kliensnek. A kliensalkalmazsnak legyen grafikus felhasznli fellete, s jelentse meg az sz-
szes berkezett s elkldtt zenetet.
Elszr a szerveralkalmazst rjuk meg. Mivel a QTcpSocketnek a szignljai-
ra kell feliratkozni, ehhez szksg lesz egy szlotokat definil osztlyra. Erre
szolgl a ChatServer osztly, amely a teljes alkalmazslogikt trolja, s a
szignl-szlot mechanizmus miatt a QObjectbl szrmazik:
/* chatserver.h */
#ifndef CHATSERVER_H
#define CHATSERVER_H
#include <QtCore>
#include <QtNetwork/QTcpServer>
class chatserver : public Q0bject
{
Q_OBJECT
522
8.6.Tov bbitechnolgi k
public:
explicitChatServ er(Q0bj ect*parent 0);
publicslots:
v oidnewConnection();
v oidtextReceiv ed();
priv ate:
QTcpServ er*tcpServ er;
QList<QTcpsock et*>*clientsock ets;
} ;
#endif//CHATSERVER_H
Az osztlynak kt privt tagvltozja van, egy QTcpServer s egy lista, amely
a QTcpSocketek mutatjt trolja. A QTcpServer felels a TCP-szerver ltre-
hozsrt, a listban pedig a csatlakozott kliensekkel kiptett socketeket
troljuk. Minden, a szerverre rkezett zenet esetben kirjuk a kliens sor-
szmt s magt az zenetet. A szerveralkalmazs nem grafikus, a konzolra
rja ki az zeneteket.
Az osztly kt szlotfggvnyt is tartalmaz. A newConnection segtsgvel
kapunk rtestst arrl, hogy egy kliens megprblt csatlakozni, a textReceived
szlottal pedig arrl, hogy egy klienstl adat rkezett:
/*chatserv er.cpp*/
#include"chatserv er.h"
#include<QtNetwork /QTcpServ er>
#include<QtNetwork /QTcpSock et>
#include<QDebug>
#include<QtCore>
ChatServ er::ChatServ er(Q0bj ect*parent):
QObj ect(parent)
{
tcpServ er=newQTcpServ er();
this->clientSock ets=newQList<QTcpSock et*>();
connect(tcpserv er,SIGNAL(newConnection()),this,
SLOT(newConnection()));
if(tcpServ er->listen(QHostAddress::Any ,993 5)){
dDebug()"Aszerv eralk almaz selindult...";
}
}
v oidChatServ er::newConnection(){
QTcpSock et*sock et=tcpServ er->nextP endingConnection();
clientSock ets->append(sock et);
connect(sock et,SIGNAL(ready Read()),this,
SLOT(textReceiv ed()));
cffiebug()"k liens["this->clientSock ets->size()-1"]
csatlak ozott";
}
523
8. fejezet: AQt keretrendszer programozsa
v oidChatServ er::textReceiv ed(){
QTcpSock et*sock et=(QTcpSock et*)sender();
intindex=this->clientsock ets->index0f(sock et);
QStringmessage=
"["%QString::number(index)%"]:"%sock et->readAll();
qDebug()message;
QListIterator<QTcpsock et*>iterator(*clientsock ets);
while(iterator.hasNext())
{
QTcpSock et*client=iterator.next();
if(client!=sock et)
{
client->write(message.toLatinl());
A szerverosztly implementcija a konstruktort s a kt szlotfggvnyt tar-
talmazza. A konstruktorban inicializljuk a szervert, s feliratkozunk ennek
newConnection szignljra, ez jelzi, ha csatlakozsi krs rkezett.
A listen fggvnnyel megadjuk, hogy a szerver egy adott cmen s portsz-
mon figyelje a berkez krseket. A fggvny nem blokkoldik, rgtn visz-
szatr. Ha valamilyen esemny trtnik, arrl a megfelel szignllal kapunk
rtestst:
bool QTcpServer : :1 i sten (
constQHostAddress&ad d re s s = QHostAddress::Any ,
quintl6p ort = 0)
A cmet a QHostAddress osztllyal rhatjuk le. A QHostAddress::Any egy
olyan konstans, amely jelzi, hogy a szerver az sszes hlzati interfszen fi-
gyel. A fenti pldban a portszmot is megadjuk, de tadhatunk 0-t is a m-
sodik paramternek, ilyenkor a szerverhez egy vletlen portszmot rendel
a rendszer. A listen fggvny visszatrsi rtke jelzi, hogy sikeres volt-e a
szerver indtsa.
A ChatServer osztly pldnyostsa utn teht elindul a szerver, s vrja
a berkez csatlakozsi krelmeket Amikor a kliens megprbl csatlakozni,
akkor a QTcpServer pldny kibocstja a newConnection szignlt, amelyre az
azonos nev szlotfggvnnyel iratkoztunk fel. Ebben a fggvnyben elszr
lekrdezzk az j kapcsolathoz tartoz QTcpSocket pldnyt a nextPending-
Connection fggvny segtsgvel, ezt a pldnyt pedig eltroljuk a client-
Sockets listban. Mivel a QTcpSocket most jtt ltre, ezrt itt kell feliratkozni
a readyRead szignljra, hogy rtestst kapjunk, amikor j olvashat adat
rkezik. Erre a textReceived szlotfggvnyt hasznljuk. Teht, amikor a kli-
ens adatot kld a szervernek, akkor a textReceived fggvny hvdik meg, eb-
ben egyszeren kirjuk a konzolra az rkezett adatot.
524
8.6.Tov bbitechnolgi k
Az els nehzsg, amely el'kerl a textReceived implementlsakor, az az,
hogy hogyan tudjuk meg, hogy melyik klienstl rkezett az adat, ugyanis az
sszes klienshez tartoz QTcpSocketnek a readyRead szignljra ugyanazzal
a fggvnnyel iratkozunk fel. A megolds a mr korbban bemutatott sender
fggvny. Ennek a segtsgvel kapunk pointert az adott klienshez tartoz
QTcpSocketre. A pldnkban a kliens sorszma a hozztartoz socketnek a
clientSockets listban eltrolt sorszma lesz.
A QTcpSocket osztlytl a kvetkez fggvnnyel tudjuk lekrdezni a kli-
enstl rkezett adatot:
QBy teArray QI0Dev ice::readAll()
Az aktulis zenet kiolvassa utn az adott szveget elkldjk az sszes csat-
lakozott kliensnek, kivve termszetesen az zenet kldjt. Erre szolgl a
fggvny vgn tallhat ciklus. A QTcpSocket readAll metdusval olvastuk
ki az adatokat, a write metdussal pedig el tudunk kldeni egy szveget. En-
nek a fggvnynek tbbfle paramterezse ltezik, a pldban a const char *
paramtert hasznljuk, amely a paramterknt tadott szvegkonstansot
kldi el a hlzaton keresztl:
qint64QI0Dev ice::write(constchar*data)
Vgezetl megmutatjuk a main.cpp forrsllomnyt, amelyben a Qt keretrend-
szer inicializlsn kvl mindssze a ChatServer osztlyt pldnyostjuk,
ugyanis ennek a konstruktorban a szerver is ltrejn. Mivel az alkalmazs
nem rendelkezik grafikus fellettel, viszont esemnykezelsre szksgnk
van, a QApplication helyett a QCoreApplication osztlyt pldnyostjuk:
/*main.cpp*/
#include<QtCore>
#include<QtNetwork /QTcpServ er>
#include<chatserv er.h>
intmain(intargc,char*argv [])
{
QCoreApplicationa(argc,argv );
ChatServ er*serv er=newChatServ er();
returna.exec();
}
A kvetkez feladat a kliensalkalmazs elksztse. Ebben nem kell QTcp-
Server objektumot inicializlni, mindssze egy QTcpSocket pldnyt kell lt-
rehozni, amelyet a megfelel cm megadsval a csatlakoztatunk szerverhez.
A kliensalkalmazs mr grafikus felhasznli fellettel rendelkezik, ez a
8.10. brn lthat. A fels csak olvashat szvegdoboz tartalmazza az ed-
dig elkldtt szvegeket, illetve a legels sorban van egy zenetet, amely azt
52 5
8.fej ezet:AQtk eretrendszerprogramoz sa
jelzi, hogy sikerlt-e felpteni a kapcsolatot a szerverrel, tovbb kirja az ed-
dig elkldtt zeneteket is. Alul lthat egy msik szvegdoboz, amelybe az el-
kldend zenetet lehet begpelni, mellette pedig egy gomb, amellyel el is lehet
kldeni. Amg a kapcsolds nem jrt sikerrel, a szvegdobozba nem lehet rni.
Uzenet: Klds
8.10. bra. Cseveg kliensalkalmazsnak kpernykpe
/*chatclientwindow.h*/
#ifndefCHATCLIENTWINDOW_H
#defineCHATCLIENTWINDOW_H
#include<Qwidget>
#include<QtGui>
#include<QtNetwork >
classChatC1ientWindow:publicQwidget
{
Q_OBJECT
public:
explicitChatClientwindow(Qwidget*parent=0);
publicslots:
v oidsendText();
v oidhostConnected();
v oidsock etReady Read();
priv ate:
Qv BoxLay out*v Lay out;
QHBoxLay out hLay out;
QTextEdit*txtChatHistory ;
QLineEdit*txtInput;
QLabel * 1b1Text;
QP ushButton*btnSend;
wrcpsocket * sock et;
#endif//CHATCLIENTWINDOW_H
526
8.6. Tovbbi technolgik
A chatclientwindow.h llomny tartalmazza a ChatClientWindow osztly
deklarcijt. A QWidgetbl szrmaz osztlynak a korbban bemutatott ve-
zrlknek megfelel tagvltozi vannak. Lthat tovbb, hogy kt elrende-
zssegt osztlypldny is szerepel: a QHBoxLayout segtsgvel a Szveg"
szveget, a szvegbeviteli dobozt s a nyomgombot helyezzk el egyms mel-
l, a QVBoxLayout pedig a korbbi zeneteket tartalmaz dobozt igaztja az
elbbi vzszintes tartalom fl. Szintn tagvltozknt definilunk egy QTcp-
Socketet (ennek a funkcijt lsd korbban).
A konstruktoron kvl hrom szlotfggvnyt definilunk. A hostConnected
fggvnnyel kapunk majd rtestst arrl, hogy sikerlt-e a csatlakozs a
szerverhez. A sendText szlotot a nyomgomb megnyomsakor kibocstott
szignl aktivlja, jelezve ezzel, hogy a begpelt adatot kldjk el a szerver-
nek. Vgl a socketReadyRead szlottal iratkozunk fel arra a szignlra, amely
j zenet rkezsekor jelez:
/*chatclientwindow.cpp*/
#include"chatclientwindow.h"
ChatClientwindow::ChatclientWindow(QWidget*parent):
Qwidget(parent)
{
v Lay out=newQVBoxLay out;
this->setLay out(v Lay out);
txtChatHistory =newQTextEdit;
txtChatHistory ->setReadOnly (true);
v Lay out->addwidget(txtChatHistory );
hLay out=newQHBoxLay out;
lblText=newQLabel;
lblText->setText("zenet:");
hLay out->addWidget(lblText);
txtlnput=newQLineEdit;
hLay out->addwidget(txtlnput);
btnSend=newQP ushButton;
btnSend->setText("Rld s");
connect(btnSend,SIGNAL(click ed()),this,SLOT(sendText()));
hLay out->addWidget(btnSend);
v Lay out->addLay out(hLay out);
txtChatHistory ->append("Szerv erk apcsolatm gnem pltfel.");
txtInput->setoisabled(true);
527
8. fejezet: A Qt keretrendszer programozsa
sock et=newQTcpSock et();
connect(sock et,SIGNAL(connected()),this,
SLOT(hostConnected()))
connect(sock et,SIGNAL(ready Read()),this,
SLOT(sock etReady Read()));
sock et->connectToHost("localhost",993 5);
v oidChatClientWindow:sendText()
QStringtext=txtInput->text();
txtinput->clear();
txtChatHistory ->append(
QTimecurrentTime()toString %" n:
sock et->write(text.toLatinl());
sock et->flush();
1 1
%text);
v o dChatClientwindow::hostConnected(){
txtChatHistory ->clear();
txtChatHistory ->append("Szerv erk apcsolatfel p tv e");
txtInput->setEnabled(true);
v oidChatClientWindow::sock etReady Read(){
QStringmessage(sock et->readAll());
txtchatHistory ->append(
QTime::currentTime().toString()%""%message);
Az implementcis llomny a konstruktorral kezddik. Elszr a felleten
elhelyezett vezrlket s az elrendezskezel objektumokat inicializljuk a
korbban mr ismertetett mdon. Mivel a fenti szvegdoboz tbbsoros, ezrt
azt a QTextEdit vezrlvel hozzuk ltre, mg a lentebbi, egysoros szvegdoboz
a QLineEdit osztly pldnya. A ltrehozott vezrlknek nhny tulajdons-
gt mdostjuk. A QTextEdit osztly setReadOnly metdusval csak olvasha-
tv tesszk a fels szvegdobozt, illetve az append fggvnnyel egy jabb
szveget adunk hozz a doboz eddigi tartalmhoz. A QLineEdit setDisabled
fggvnyvel nem engedlyezett llapotba helyezzk a lenti szvegdobozt, ezzel
jelezve, hogy nem lehet bele rni, amg a kapcsolat ltre nem jtt. A QPush-
Button tpus gomb szvegt a setText fggvnnyel lltjuk be, ugyanitt be-
ktjk a sendText szlotot a gomb clicked szignljhoz.
A konstruktor msodik fele a hlzati kapcsolat felptst vgzi el.
A QTcpSocket ltrehozsa utn sszektjk ennek a connected szignljt a sa-
jt osztlyunk hostConnected szlotfggvnyvel, majd a connectToHost fgg-
vnnyel megprblunk csatlakozni a szerverhez. Az utbbi fggvny els
paramtere a szerver cme, a msodik pedig a portszma. Mg a csatlakozs
eltt feliratkozunk a szerversocket egy msik szignljra, a readyReadre is.
Ez a szignl jelzi, hogy j adat rkezett (lsd a szerveralkalmazsnl).
528
8.6. Tovbbi technolgik
Amikor teht a fenti ablakot inicializljuk, s lefut a konstruktor, akkor el-
helyezzk a vezrlket, s a fenti szvegdobozban megjelenik egy szveg, amely
szerint a hlzati kapcsolatot mg nem sikerlt felpteni, majd megprblunk
csatlakozni a szerverhez. Ha sikerlt, akkor automatikusan meghvdik
a hostConnected szlot. Ebben a fggvnyben mdostjuk a felhasznli felle-
tet, a fels szvegdobozba kirjuk, hogy a kapcsolat most mr ltrejtt, illetve
a lenti szvegdobozt is engedlyezzk a setEnabled fggvnnyel.
A tovbbi teendk a felhasznlra vrnak. Miutn bert egy szveget az al-
s szvegdobozba, meg kell nyomnia a kldsgombot, ennek hatsra a send-
Text szlot hvdik meg. Ebben elszr kiolvassuk a szvegdoboz tartalmt, majd
ezt az aktulis idponttal egytt kirjuk a fels szvegdobozba, tovbb a mr
korbban emltett write fggvnnyel elkldjk a hlzaton keresztl a szve-
get. A flush fggvny meghvsval biztostjuk, hogy a QTcp Socket buffer-
nek a tartalmt azonnal elkldjk.
Amikor j zenet rkezik a szervertl, a socketReadyRead szlotfggvny
hvdik meg, ebben kiolvassuk az j zenetet, majd kirjuk a szvegdobozba.
A teljessg kedvrt a kliensalkalmazs main fggvnyt is bemutatjuk:
/*main.cpp*/
#include<QtGui>
#include"chatclientwindow.h"
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
ChatClientWindow*client=newChatClientWindow;
client->show();
returnapp.exec();
}
A main.cpp llomnyban inicializljuk az alkalmazsobjektumot s a Chat-
ClientWindow osztlyunkat, majd megjelentjk az utbbit. Innen maga a
widget felels a hlzati kommunikcirt.
52 9
8. fejezet: A Qt keretrendszer programozsa
8.7. sszefogla l s
Ebben a fejezetben bemutattuk a Qt keretrendszer legfontosabb technolgi-
it, s ismertettk nhny fontos osztlyt. A Qt keretrendszer grafikus felle-
tek programozsa mellett nagyban tmogatja a legklnbzbb konzolos
alkalmazsok fejlesztst, tovbb knnyen megvalsthat az alacsony s
magasabb szint alkalmazsok kztti kommunikci.
Bemutattuk a Qt szignl-szlot mechanizmust, dialgusablakok, sszetett
alkalmazsablakok s sajt vezrl'k ksztsnek a mdszereit. A dokumen-
tum/nzet architektrban lthattuk, hogyan lehet sszetett alkalmazsok-
nl is kzben tartani a program mkdsnek tlthatsgt a klnbz
komponensek szerepeinek sztvlasztsval. Vgl a Qt keretrendszer rszt
kpez nhny fontos technolgit, a tbbszl programozst, az adatbzis-
elrst s a hlzatkezelst trgyaltuk.
A Qt keretrendszer azonban nemcsak egy alkalmazsprogramozi knyv-
trbl ll, hanem egy teljes szoftvercsomagbl, amely nagyban egyszersti
nemcsak a grafikus felhasznl fellettel rendelkez, de a konzolos vagy be-
gyazott alkalmazsok fejlesztst egyarnt.
A knyv rsnak idpontjban a Qt keretrendszerhez ajnlott els szm
fejleszteszkz a QtCreator, amely egy ingyenes, platformfggetlen integrlt
fejleszti krnyezet s a Qt keretrendszer rsze. A QtCreator tbbek kztt a
kvetkez eszkzket biztostja a fejlesztshez:
Forrskdszerkeszt funkcik tbbek kztt C++ s Javascript nyel-
vekhez automatikus kdkiegsztssel.
Teljes projektmenedzsment rendszer, amely automatikusan kezeli a
.pro projektfjlokat, gy ezeket nem szksges kzzel szerkeszteni.
A projekteket automatikusan fordtja s futtatja.
Szoros integrci verzikezel rendszerekkel.
A krnyezet rsze a Qt Designer, amely egy grafikus felhasznli fel-
lettervez alkalmazs. A felleten keresztl megtervezhetjk az
alkalmazsunk kinzett, elhelyezhetjk a vezrlket, elrendezs-
objektumokat hozhatunk ltre. Tovbb lehetsg van szintn a fel-
leten keresztl az egyes vezrl'k ltal definilt szignlok s szlotok
sszekapacsolsra. gy egyetlen programsor rsa nlkl is megal-
kothatjuk a felhasznli fellet s az esemnykezels vzt. A kiala-
ktott fellet lerst egy .ui kiterjeszts xml llomnyban trolja a
rendszer, amelybl automatikusan generlja egy annak megfelel osz-
tly kdjt, gy ezt utna felhasznlhatjuk az alkalmazsunkban
A QtLinguist program segtsgvel egy grafikus felleten tudjuk szer-
keszteni a .ts kiterjeszts xml llomnyainkat, amelyek az alkalma-
zsaink lokalizlt szvegeit troljk.
530
8.7. sszefoglals
A QtCreator rsze egy QML szerkeszt is. A QML (Qt Markup Language)
egy jauctscipt alap nyelv, amelynek a segtsgvel deklaratvan lehet
lerni a felhasznli felleteket. A QML rsze a QtQuick keretrend-
szernek, amely kpes az gy lert felletet futtatni. A QML nyelv bemu-
tatsa meghaladja ennek a knyvnek a kereteit, de fontos megemlteni,
mert egyre elterjedtebb mdszer a Qt-alap fejlesztsekben.
A fent felsorolt funkcik, a platformfggetlen fejleszt'krnyezet s a keret-
rendszer azon kpessge, hogy a mobileszkzktl a begyazott rendszereken
t az asztali szmtgpekig nagyon sok opercis rendszeren mkdik, a Qt-t
az egyik legsokoldalbb alkalmazsplatformm teszik.
531
A FGGELK
Fejleszteszkzk
Linux alatt a fejleszteszkzk szles vlasztka ll rendelkezsnkre. Ezek-
bl kivlaszthatjuk a neknk megfelelt, m nhny fontos eszkzt minden-
kinek ismernie kell.
A Linux-disztribcik szmtalan megbzhat fejleszteszkzt tartalmaznak,
amelyek fknt a Unix rendszerekben korbban elterjedt eszkzknek felelnek
meg. Ezek az eszkzk nem rendelkeznek bartsgos fellettel, a legtbbjk pa-
rancssoros, felhasznli fellet nlkl. m sok ven keresztl bizonytottk
megbzhatsgukat, hasznlhatsgukat. Szmos j felhasznlbart program a
httrben tovbbra is ezeket a parancssoros eszkzket hasznlja.
A.1. Szvegszerkesztk
A Linuxhoz is tallhatunk tbb integrlt fejleszti krnyezetet (Integrated De-
velopment Environment, IDE), m tovbbra is gyakran hasznlunk egyszer
szvegszerkesztket. Sok Unix-fejleszt tovbbra is ragaszkodik ezekhez a ke-
vsb bartsgos, de a feladathoz sokszor tkletesen elegend eszkzkhz.
A Linux trtnete sorn az albbi eszkzk terjedtek el.
A.1 .1 . Emacs
Az eredeti Emacs programot Richard Stallman (az FSF alaptja) ksztette.
vekig a GNU Emacs volt a legnpszerbb vltozat. Ksbb elterjedt a grafi-
kus krnyezethez ksztett XEmacs.
A felhasznli fellete nem olyan feltn, mint sok ms rendszernl, m
szmos, a fejlesztk szmra jl hasznlhat funkcival rendelkezik. Ilyen
pldul a szintaxis-ellenrzs. Ha a fordtt hozzillesztjk, kpes annak hi-
bazeneteit rtelmezni s a hibkat megmutatni. Lehetv teszi tovbb a
hibajavt program krnyezetbe val integrlst is.
A fggelk: Fejleszteszkzk
A.1.2. vi (vim)
A vi egy egyszer szvegszerkeszt. Kezelst leginkbb a gpelni tudk ig-
nyeihez alaktottk. A parancskszlett gy lltottk ssze, hogy a lehet
legkevesebb kzmozgssal lehessen hasznlni. Tapasztalatlan felhasznl
szmra azonban a kezelse meglehetsen bonyolult lehet, ezrt npszers-
ge ersen megcsappant. Elsznt Linux/Unix felhasznlk szoktk alkalmazni.
A.1.3. nano (pico)
A nano s az eldje a pico egyszer kperny-orientlt szvegszerkeszt. lta-
lban minden Linux rendszeren megtallhat. Elterjedten hasznljk a ki-
sebb szvegek gyors mdostsra a terminlbl. Komolyabb feladatokra nem
ajnlhat. Ezekben az esetekben alkalmasabb a kvetkez rszben trgyalt
joe
vagy egy, a feladatnak megfelelen specializlt szerkeszt.
A program parancsai folyamatosan lthatk a kperny aljn. A ^ jel azt
jelenti, hogy a billentyt a Ctrl gomb nyomva tartsa mellett kell hasznlni.
Ha ez esetleg a terminl tpusa miatt nem mkdne, akkor az ESC gomb kt-
szeri megnyomst is alkalmazhatjuk helyette.
A.1.4. joe
A joe a nannl fejlettebb s nagyobb, szintn szveges terminlban hasznl-
hat szvegszerkeszt. Komolyabb feladatokra is alkalmas a magasabb szint
szolgltatsai rvn. Egyszerre tbb llomnyt is megnyithatunk vele kln-
bz opcikkal. Az llomnyokat a kiterjesztsk alapjn felismeri, s auto-
matikusan szintaxiskiemelssel segti a munkt.
Komolysgt a parancsok szmbl is lthatjuk, amelyet a <ctrl>-k-h
gombokkal hozhatunk el s tntethetnk el A jellsekben a ^" jel azt je-
lenti, hogy a billentyket a Ctrl gomb nyomva tartsa mellett kell hasznlni
A.1.5. mc
A Midnight Commander, rviden mc elterjedt alternatvja a Norton Comman-
der nev MS DOS/Windows alkalmazsnak. Szveges, kvzigrafikus fellettel
rendelkezik. Gyakran hasznljk olyan felhasznlk, akik nem szeretnek foly-
ton parancsokat berni, a grafikus fellethez kpest azonban alacsonyabb szin-
t megoldsra vgynak.
534
A.2. Fordtk
A Midnight Commander rendelkezik egy beptett szvegszerkesztvel,
amelyet mceditnek hvnak. Elrhet az F4 gombbal vagy nll programknt
indtva. Sokan hasznljk rvidebb forrskdok szerkesztsre. Ezt elsegti,
hogy ugyancsak rendelkezik szintaxiskiemel szolgltatssal.
A.1.6. Grafikus szvegszerkesztk
A grafikus krnyezetek (Desktop Environment) rendelkeznek sajt fejlett sz-
vegszerkesztkkel, amelyek tmogatjk forrskdok szerkesztst is. A KDE-
krnyezetben a kate j vlaszts, de a kwrite is jl hasznlhat. A GNOME-kr-
nyezet pedig a gedit nev programot nyjtja. Egyszer forrskdok megrsra
ezek jl hasznlhat eszkzk.
A.2. Fordtk
Linux alatt, a programozsi nyelvektl fggen, az albbi kiterjesztsekkel
tallkozhatunk:
.a Statikus fejleszti knyvtr
.c C nyelv forrs
.0 .cc .cpp .cxx .c++ C++ nyelv forrs
.class Java-byte-kd
.F .f .for Fortran nyelv forrs
.h C/C++ nyelv headerfjl
.hxx C++ nyelv headerfjl
java Java nyelv forrs
. m Objective-C forrs
.o Trgykd (object) fjl
.p Pascal-forrs
.patch Klnbsgllomny
.perl Perl-forrs
.ph Perl-headerfjl
.pl Perl-szkript
.pm Perl-modulszkript
.py Python-forrs
535
A fggelk: Fejleszteszkzk
llomnyuttag Jelents
.pyc
Lefordtott Python-kd
.S .s Assembly kd
.S0
Megosztott knyvtr
.tel .tk Tcl-szkript
Termszetesen a lista nem teljes, s nem is lehet az, hiszen mindig szletnek
jabb jellsek. Az uttagokhoz tartoz nyelvekhez kapcsoldan a tovbbi-
akban rviden ttekintjk a GNU Compiler Collection fordtcsomagot.
A.2.1. GNU Compiler Collection
A GNU Compiler Collection (http: //gcc.gnu.org/) a C (gcc), C++ (g++),
Objective-C, Fortran, Java (GCJ), Ada (GNAT) s a Go nyelvek fordtit fog-
lalja egy csomagba. Ezltal az elbb felsorolt nyelveken rt programokat mind
lefordthatjuk a GCC-vel.
Tovbbi nyelvekhez (Mercury, Pascal) is lteznek elttfelletek (front-
end), m ezeknek egy rszt mg nem integrltk a GCC hivatalos csomagj-
ba. Mi a tovbbiakban a C/C++ nyelvekre hagyatkozunk.
A.11. gcc
A gcc-nek nincs felhasznli fellete. Parancssorbl kell a megfelel paramte-
rekkel meghvnunk. Hasznlata szmos paramtere ellenre egyszer, ugya-
nis ltalnos esetben ezeknek a paramtereknek csak egy kis rszre van
szksgnk.
Hasznlat eltt rdemes ellenrizni, hogy az adott gpen a gcc melyik
verzijt teleptettk. Ezt az albbi paranccsal tehetjk meg:
gcc -v
Ebbl megtudhatjuk a gcc verzijt, tovbb azt a platformot, amelyre lefor-
dtottk.
A program gyakran hasznlt paramtereit az A.1. tblzat tartalmazza.
A.1 . tblzat. A gcc leggyakrabban hasznlt paramterei
Paramter Jelents
-o fjlnv
A kimeneti llomnynv megadsa. Ha nem adjuk meg, akkor
az alaprtelmezett fjlnv a.out lesz.
536
A.2. Fordtk
Paramter Jelents
-c Fordts, linkels nlkl. A paramterknt megadott forrsllo-
mnybl trgykd (object) fjlt kszt.
-Ddefinci=x Definilja a defincimakrt x rtkkel.
-Iknyvtrnv Hozzadja a knyvtrnv paramterben meghatrozott knyvt-
rat ahhoz a listhoz, amelyben a .h kiterjeszts (header) llo-
mnyokat keresi.
-Lknyvtrnu Hozzadja a knyvtrnv paramterben meghatrozott knyvt-
rat ahhoz a listhoz, amelyben a fejleszti knyvtr- (library) l-
lomnyokat keresi.
-llibrary A programhoz hozzkapcsolja a library nev programknyvtr
metdusait.
-static Az alaprtelmezett dinamikus linkels helyett a fordt a stati-
kus programknyvtrakat linkeli a programba, ha azok rendel-
kezsre llnak.
-g, -gN,
-ggdb, -ggdbN
A lefordtott llomnyt elltja a hibakeresshez (debug) szks-
ges informcikkal A -g opci megadsval a fordt a szabv-
nyos hibainformcikat helyezi el. A -ggdb opci arra utastja a
fordtt, hogy olyan tovbbi informcikat is elhelyezzen a prog-
ramban, amelyeket csak a gdb hibakeres rtelmez.
A paramter vgn megadhatunk egy szintet (N) 0 s 3 kztt. 0:
nincs hibakeressi informci, 3: extrainformcik is belekerl-
nek. Az alaprtelmezett a 2 -es szint.
-0, -ON Optimalizlja a programot az N optimalizcis szintnek megfele-
len. Az optimalizci sorn kisebb/gyorsabb kd ellltsra
trekszik a fordt.
A szint 0-tl 3-ig vlaszthat meg. 0 esetn nincs optimalizci.
Az alaprtelmezett 1-es szint esetn csak nhny optimalizcit
vgez a gcc. A leggyakrabban hasznlt optimalizcis szint a 2 -es.
-Wall Az sszes gyakran hasznlt figyelmeztetst (warning) bekapcsol-
ja. A csak specilis esetben hasznos figyelmeztetseket kln
kell bekapcsolni.
Pldaknt nzznk vgig nhny esetet a gcc program hasznlatra.
Egy tetszleges szvegszerkesztben elksztettk a mr jl megszokott
kdot:
/* hello.c */
#include <stdio.h>
int main()
{
printf("Hello vilag!\n");
return 0;
}
537
A fggelk: Fejleszteszkzk
Ezutn kiprbljuk a programunkat Ehhez az albbi paranccsal fordthatjuk le:
-o hllO h
Ha nem rontottuk el a kdot, akkor a fordt hibazenet nlkl lefordtja a for-
rst, s a programra a futtatsi jogot is belltja. Hibtlan kd esetn a fordt
nem r ki semmilyen zenetet. Innen tudhatjuk, hogy sikeresen dolgoztunk.
Ezutn mr csak futtatnunk kell a programot:
"Vh;04
,
A programunk fut, s a konzolon megjelenik a kvetkez felirat:
H ell o vilag!
Vagyis meghvtuk a gcc programot, amely lefordtotta (compile) a kdot, majd
meghvta az ld nev linkerprogramot, amely a lefordtott kdunkhoz hozz-
fzte a fejleszti knyvtrakbl a felhasznlt fggvnyeket, s ltrehozta a
futtathat binris llomnyt
Ha csak trgykd llomnyt (object file) akarunk ltrehozni (amelynek
kiterjesztse .o), vagyis ki szeretnnk hagyni a linkels folyamatt, akkor a -c
kapcsolt hasznljuk a gcc program paramterezsekor:
gcc.-c hello.c
Ennek eredmnyekppen egy hello.o nev trgykd fjl jtt ltre. Ez az llo-
mny gpi kdban tartalmazza az ltalunk rt programot. Ezt termszetesen
linkelnnk kell mg, hogy egy ksz futtathat binrist kapjunk:
gcc -o hello
A o kapcsol segtsgvel tudjuk megadni a linkels eredmnyeknt ltrejv
futtathat fjl nevt. Ha ezt elhagyjuk, alaprtelmezsben egy a.out nev l-
lomny jn ltre.
A kvetkezkben megvizsgljuk azt az esetet, amikor a programunk tbb
(esetnkben kt) forrsllomnybl ll. Az egyik tartalmazza a fprogramot:
/* si ncprg .c */
#i ncl ude <stdi o h>
double si nc (doubl e) ;
int mai n()
{
double x;
538
A.2 .Ford tk
printf("Kerem az x-et: ");
scanf("%lf", &x);
printf("sinc(x) = %6.4 f\n", sinc(x));
return 0;
}
A msik implementlja a sinx/x fggvnyt:
/* sinc.c * I
#i ncl ude <math h>
double sinc(double x)
{
return sin(x)/x;
}
A teljes program lefordtsa a kvetkez:
gcc -o sincprg sincprg.c sinc.c -1m
gy a sincprg futtathat fjlhoz jutunk. Ugyanezt megoldhattuk volna tbb
lpsben is:
gcc -c sincprg.c
gcc -c sinc.c
gcc -o sincprg sincprg.o sinc.o -1m
Az /m kapcsolra azrt van szksgnk, hogy a sin() fggvnyt tartalmaz
matematikai programknyvtrat hozzfzzk a programunkhoz. Ha ezt elmu-
lasztjuk, akkor egy hibazenetet kapunk a fordttl arrl, hogy nem tallja a
sin() fggvny referencijt. Az 1 kapcsol ltalban arra szolgl, hogy egy
programknyvtrat hozzfordtsunk a programunkhoz. A Linux rendszerhez
szmos szabvnyostott programknyvtr tartozik, amelyek a /lib, illetve
a /usr/lib knyvtrakban tallhatk. Ha a felhasznlt programknyvtr
mshol tallhat, az elrsi tvonalat meg kell adnunk az L kapcsolval:
gccprog.c-L/home/my name/my libsmy lib.a
Hasonl problmnk lehet a .h-kiterjeszts llomnyokkal (header file).
A rendszerhez tartoz headerllomnyok alaprtelmezetten az /usr/include
knyvtrban (illetve az innen kiindul knyvtrstruktrban) tallhatk. gy
ha ettl eltrnk, az I kapcsolt kell hasznlnunk sajt headertvonalak
megadshoz:
gccprog.c-I/home/my name/my headers
53 9
#ifdef DEBUG
ri ntf CAsz l el I riddl t "
A fggelk: Fejleszteszkzk
Ez azonban ritkn fordul el, ugyanis a C-programokbl ltalban az aktulis
knyvtrhoz viszonytva adjuk meg a sajt .h-llomnyainkat, vagyis relatv
tvonalmegadst hasznlunk:
gcc prog. c
. . inly heeder
A C-elfeldolgoz (preprocessor) msik gyakran hasznlt funkcija a #define
direktva. Ezt is megadhatjuk kzvetlenl parancssorbl. A
gcc DMAX_ARRAY_SZ=80priig. c o
Prdg
hatsa teljes mrtkben megegyezik a prog.c programban elhelyezett
M~R, ZE
preprocesszordirektvval. Ennek a funkcinak gyakori felhasznlsa a
paramterezs. Ilyenkor a programban feltteles fordtsi direktvkat he-
lyezhetnk el a hibakeress megknnytsre:
A fenti esetben ltjuk az j szlak indulst debug zemmdban, amikor a
DEBUG makrt definiljuk. Viszont ez az informci szksgtelen a felhasz-
nl szmra egy mr letesztelt program esetben, gy ekkor jrafordtjuk a
programot a DEFINE nlkl.
A.2.3. LLVM
A GNU Compiler Collection mellett egyre nagyobb npszersgre tesz szert
az LLVM (Low Level Virtual Machine, http://llvm.org/), amely a GCC-hez
hasonlan szmos nyelvet tmogat. Az LLVM egy olyan hatkony fordt-
program-fejleszt krnyezet, amely ksz megoldsokat ad szmos fordtsnl
hasznlatos funkcira, kztk (nyelvfggetlen) optimalizlsra, kztes bels
nyelvre, valamint kdgenerlsra. A clang (C nyelv") projekt az LLVM natv
C-fordtja, amely gcc kompatibilis, de figyelemremltan gyorsabb annl, to-
vbb lteznek olyan eszkzk, amelyek integrljk a gcc fellett a c/anggal.
A C, C++, Objective-C nyelvekhez hasznlhatjuk az LLVM GCC s a Clang
fellett is. Knnyen lehet, hogy az eszkz valamilyen formban tveszi a gcc
szerept.
540
A.3. Make
A.3. Make
A unixos fejlesztsek egyik oszlopa a make program. A Linux rendszereken a
GNU make terjedt el (http:/ /www.gnu.org/software/make/) . Ez az eszkz
lehetv teszi, hogy a programunk fordtsi menett knnyen lerjuk s auto-
matizljuk. Nemcsak nagy programok esetben, hanem akr egy forrsllo-
mnybl ll programnl is egyszerbb a fordts, ha csak egy make parancsot
kell kiadnunk az aktulis knyvtrban a fordt paramterezse helyett.
Tovbbi szolgltatsa a make programnak, hogy egy sok forrsllomny-
bl ll program fordtsakor csak a mdostott llomnyokat fordtja jra, il-
letve azokat, amelyekre ezek hatssal lehetnek.
Ahhoz, hogy mindezeket a funkcikat megvalsthassa a make egy gy-
nevezett Makefile
112
-ban le kell rnunk a programunk fordtsnak menett a
forrsllomnyok megadsval. Nzznk erre egy pldt:
1: # Makefile
2 :
3: objs = sincprg.o sinc.o
4 : libs = -1m
5:
6: sincprg: $(objs)
7: gcc -o sincprg $(objs) $(libs)
8:
9: install: sincprg
10: install -m 64 4 sincprg /usr/local/bin
11:
12 : . PHONY : i nstal 1
Az 1 . sorban egy megjegyzst (comment) lthatunk. A unixos tradcik alap-
jn a megjegyzst # karakterrel jelljk.
A 3. sorban definiljuk az objs vltozt, amelynek rtke: sincprg.o
sinc.o.
A 4 . sorban ugyanezt tesszk a libs vltozval. A ksbbiekben ezt
hasznljuk fel a linkelsi paramterek belltsra.
A 6. sorban egy szably (rule) megadst lthatjuk. Ebben a sincprg l-
lomny az objs vltoz rtkeitl fgg. A sincprg llomnyt hvjuk a szably
cljnak (target), s az $(objs) adja a fggsgi listt (dependency list).
Megfigyelhetjk a vltoz hasznlatnak mdjt is.
A 7. sorban egy parancssor tallhat, m ez tbbsoros is lehet. Azt mutatja
meg, hogy hogyan kszthetjk el a clobjektumot a fggsgi lista elemei-
bl. Itt llhat tbb parancssor is szksg szerint, m minden sort TAB karak-
terrel kell kezdeni.
112
Ha alkalmazzuk a make -f fjlnv szintaxist, akkor a make a megadott fjlt dolgozza fel
az alaprtelmezett Makefile llomnynv helyett.
54 1
A fggelk: Fejleszteszkzk
A 9. sor specilis. Ebben a szablyban valjban nem llomny ltrehoz-
sa a clunk, hanem az installcis mvelet megadsa.
A 10. sorban vgezzk el a programunk teleptst: az install program
meghvsval bemsoljuk az /usr/ local/bin knyvtrba.
A 12 . sor egy problma megoldst rejti. A 9. sorban a cl nem llomny
volt, hanem parancs. m, ha mgis ltezik egy install nev llomny, s az
frissebb, mint a fggsgi listban szerepl sincprg llomny, akkor nem fut
le a szablyunk. Ezt kszbljk ki a . PHONY kulcsszval, amely mdostja a
make mkdst. Ebben az esetben megadhatjuk vele, hogy az install cl ese-
tn ne figyelje az llomny ltt, hanem minden esetben hajtsa vgre a sza-
blyt, ha krjk.
ltalnosan megfogalmazva a Makefile-ok tfle dolgot tartalmazhatnak.
Ezek a kvetkezk:
megjegyzsek,
explicit szablyok,
i mplicit szablyok,
vltozdefincik,
direktvk.
A.3.1. Megjegyzsek
A megjegyzsek magyarzatul szolglnak, a make program gyakorlatilag fi-
gyelmen kvl hagyja ket. A # karakterrel kell kezddnik.
A.3.2. Explicit szablyok
A szably (rule) azt hatrozza meg, hogy mikor s hogyan kell jrafordtani
egy vagy tbb llomnyt. Az gy keletkez llomnyokat a szably cljnak
vagy trgynak (target) nevezzk." Hogy egy llomny ltrejjjn, ltal-
ban ms llomnyokra is szksg van. Ezek listjt nevezzk fggsgi lis-
tnak, feltteleknek vagy elkvetelmnynek. Pldul:
fcm
-
slefsh
gc -c g fk'.c
H3
m mint lthattuk, a cl nem minden esetben llomny ltrehozsa.
542
A.3. make
A fenti pldban a szably trgya a foo.o fjl, az el'kvetelmny a foo.c, illet-
ve a foo.h llomny. Mindez azt jelenti, hogy szksg van a foo.c s a defs.h
llomnyokra, tovbb a foo.o fjlt akkor kell jrafordtani, ha
a foo.o fjl nem ltezik,
a foo.c id'blyege ksbbi, mint a foo.o idblyege,
a defs.h idblyege ksbbi, mint a foo.o idblyege.
Azt, hogy a foo.o fjlt, hogyan kell ltrehozni, a msodik sor adja meg.
A defs.h nincs a gcc paramterei kztt: a fggsget egy - a foo.c fjlban ta-
llhat - #include defs.h"C nyelv preprocesszordirektva jelenti.
A szably ltalnos formja a kvetkez:
A TARGY egy llomnynv. Az ELOKOVETELMENYEK fjlnevek szkzzel
vannak elvlasztva. A fjlnevek tartalmazhatnak specilis jelents, gyneve-
zett helyettest karaktereket (wildcard characters), mint pldul a ." (aktulis
knyvtr), * " vagy %" (tetszleges karaktersorozat), -" (home knyvtr).
A RECEPT szerepelhet vagy az ELOKOVETELMENYEK-kel egy sorban pon-
tosvesszvel elvlasztva, vagy a kvetkez sorokban, amelyek mindegyikt
egy TAB ka r a kt er r el kell kezdeni. A parancssorozat vgt egy olyan sor
jelzi a make-nek, amelynek az elejn nincs TAB karakter.
tmutat gyeljnk arra, hogy sok szvegszerkeszt hajlamos a TAB gomb lenyomsra
space-karaktereket elhelyezni a szvegllomnyba, s ez ksbb hibt eredmnyez. jabban
azonban sok szvegszerkeszt az llomny nevbl detektlja, hogy Makefile-t ksztnk. Eb-
ben az esetben viszont az llomnynv megadsval clszer kezdennk.
Mivel a $ jel mr foglalt a vltozkhoz, ezrt ha a parancsban $ jel szerepelne,
akkor helyette $$-t kell rnunk.
Ha egy sor vgre \" jelet tesznk, a kvetkez sor az elz folytatsa
lesz, teljesen gy, mintha a msodik sort folytatlagosan rtuk volna. Erre
azrt van szksg, mert a make minden parancssort kln shellben futtat le.
Ezltal pldul a cd parancs hatsa is csak abban a sorban rvnyesl, aho-
va rjuk. Pldul:
cd konyvt a r ; \
gcc -c -g foo. c
Ha a make programnak paramterknt megadjuk egy trgy nevt, akkor az a
szably hajtdik vgre, amely a trgy ellltshoz kell. A make felpt egy
fggsgi ft, amelyet bejrva ellenrzi, hogy melyik rszeket kell jraford-
tani. Majd elvgzi a szksges lpseket, hogy ellltsa az aktulis clt.
54 3
A fggelk: Fejleszteszkzk
Ha a make programot paramterek nlkl futtatjuk, akkor automatiku-
san az els szably hajtdik vgre, valamint azok, amelyektl valamilyen m-
don fgg.
tmutat A make program hasznlatnl gyeljnk arra, hogy mivel a lpsek szksgessgt
a trgy- s a fggsgllomnyok idblyege alapjn vizsglja, ezrt ha az idbelltsok meg-
kavarodnak, akkor nem lesz j a mkds. Ilyen helyzet leggyakrabban akkor fordul el, ha a
fejleszts sorn gpet vltunk, s a kt szmtgp rja nem jr szinkronban. Termszetesen
az id visszalltsa is okozhat ilyen problmt. Ilyenkor clszer az idblyeget aktualizlni a
touch paranccsal, s a kztes llomnyok letrlsvel jrafordtani az egsz projektet.
A.3.3. Hamis trgy
Gyakran elfordul, hogy valamilyen mveletre egy szablyt ksztnk, amely-
nek a receptrsze tartalmazza a vgrehajtand parancsokat. A szably clja
ilyenkor nem egy ellltand llomny, hanem pusztn nvknt funkcionl az,
amellyel a szablyra hivatkozunk. Az ilyen trgyakat hvjuk hamis trgynak.
Ha azonban valamelyik mvelet tnyleg ltrehozn a trgyknt megadott
llomnyt, s az frissebb lenne a feltteleknl, akkor a szablyhoz tartoz re-
cept parancsai egyltaln nem hajtdnak vgre. Gyakori, hogy nincs megadva
felttel a hamis szablyhoz. Ilyenkor egyltaln nem hajtdik vgre a sza-
bly, ha a trgyllomny ltezik.
Azrt, hogy elkerljk a korbban vzolt problmkat, a .PHONY kulcs-
szval egyrtelmen deklarlnunk kell a hamis clokat. Pldul:
.P HONY:clean
cl ean:
rm * .o prg
Ha egy knyvtrban tbb program forrsa is szerepel, akkor gyakran ksz-
tnk egy hamis szablyt all" nven, amely mindent lefordt s elllt. s
hogy ez az alaprtelmezett szably is legyen egyben, ezrt els szablyknt r-
juk meg. Pldul:
alt: prgl prg2
.P HONY: all
prgl:prgl.o
gcc-oprglprgl.o
prg2 :prg2 .o
gcc-oprg2 prg2 .o
544
A.3. Make
A.3.4. Vltozdefincik
Mint az els pldban is lthattuk, gyakran elfordul, hogy egyes llomny-
neveknek tbb helyen is szerepelnik kell. Ilyenkor, hogy megknnytsk
a dolgunkat, vltozkat hasznlunk. Ekkor elegend egyszer megadnunk a
listt, a tbbi helyre mr csak a vltozt helyezzk. A vltozk hasznlatnak
msik clja, hogy a Makefile-unkat rendezettebb tegyk, megknnytve ezzel
a ksbbi mdostsokat.
A Makefile-ban a vltozk tpusa mindig szveg. A vltozk megadsnak
szintaxisa a kvetkez:
Erre a vltozra ksbb a
'.414
vagy a
szintaxissal hivatkozhatunk.
A vltoz neve nem tartalmazhat :", #", =" s semmilyen resmez-
karaktert. A gyakorlatban mg szkebb halmazt hasznlunk: betket, sz-
mokat s a : karaktert. A vltozk nevnl a rendszer figyeli a kis- s nagy-
betket. A tradci az, hogy a vltoz nevt csupa nagybetkkel rjuk. Jelen-
leg azonban gyakrabban kisbets neveket hasznlunk a Makefile-ban, s a
nagybets nevek inkbb rendszerfunkcikra vannak fenntartva. Egyes nagy-
bets vltozk felldefinilsval mdosthatjuk a rendszer mkdst.
Emellett nhny karakterkombincinak specilis jelentse van. (Ezeket lsd
az automatikus vltozkrl szl fejezetben.)
Lehetsgnk van arra, hogy a vltozk rtknek megadsakor ms vl-
tozk rtkeit is felhasznljuk. Pldul:
Prgs' = $ (Prgl) . . g. PrO W
Van azonban egy olyan tulajdonsga a rendszernek, amelyre figyelnnk kell.
A vltozk kirtkelse a felhasznls helyn trtnik. Azokat az rt-
keket veszi figyelembe a rendszer, amelyeket addig definiltunk, s szksg
szerint rekurzvan kifejti. Pldul:
objs = $(objl) $ (obj2 )
objl = el so.o
obj 2 = masodi k.o
prg : $ (obj s)
545
A fggelk: Fejleszteszkzk
Amikor a prg" szablyt meghvjuk, akkor a feltteleknl kirtkeli a prog-
ram az objs" vltozt. Ennek rtke $(objl) $(obj2 )". A program kirtkeli
mindkt vltozt, gy megkapjuk az elso.o masodik.o" szveget, amelyet be-
helyettest.
Ennek a megoldsnak van azonban egy msik oldala is. A vltozk hasz-
nlatakor kerlnnk kell a kvetkez megoldst:
objs = elso.o
objs = S(objs) masodik.o
Azonnal arra szmtannk, hogy szekvencilisan hajtdnak vgre a mvele-
tek, s a vgeredmnyknt az elso.o masodik.o" szveg helyettestdik majd
be a $(objs)" helyre. Ezzel szemben egy vgtelen ciklust idznk el, s a
behelyettests helyn vgtelen masodik.o" szveg lesz, mivel ez az utoljra
belltott rtk.
A.3.5. A vltoz rtkadsnak specilis esetei
Lthatan a felhasznls helyn elvgzett rekurzv kirtkels csapdkat rejt
magban. Erre megolds az egyszer kirtkels, amelyet a definils he-
lyn vgez el a rendszer. Ennek jele a :=" karakterkombinci. A mkdst a
kvetkez plda szemllteti:
a := egy
b := $(a) ketto
a := harom
Ez egyenl azzal, mintha a kvetkezket rtuk volna:
b:=egy k etto
a:=harom
Az elzekben emltett hibs pldra is van helyes megolds. Vagyis megoldha-
t, hogy a vltoz rtkhez hozzadjunk tovbbi szvegeket. Ezt a +=" jel-
lel tehetjk meg. A korbban ltott plda helyesen a kvetkez:
objs = elso.o
objs += masodik.o
gy az objs" vltoz hasznlatakor az eredmny nem vgtelen ciklus lesz,
hanem az elso.o masodik.o" szveg.
Az eddig ltottak mellett van lehetsgnk feltteles rtkadsra is.
Ebben az esetben a vltoznak csak akkor adunk rtket, ha mg nincs defi-
nilva. Ennek jele a ?=". Az albbi pldn nzzk meg a mkdst:
546
A.3. Make
=egy
7= . ketto
Ez egyenl a kvetkezvel:
egy
Br ebben a pldban nem ltszik kzvetlenl az eszkz haszna, m egy sz-
szetett, elgazsokat vagy tovbbi llomnyokat tartalmaz Makefile esetn
nagyon hasznos tud lenni.
A.3.6. Tbbsoros vltozk definilsa
A define direktva hasznlatval is adhatunk a vltozknak rtket. Szintaxisa
lehetv teszi, hogy az rtk jsor-karaktereket is tartalmazzon:
definek et-sor=
echo$(a)
echok etto
endef
A define szt a vltoz neve kveti. Ezt kveti a mvelet. Alaprtelmezett a
=" jel, amelyet el is hagyhatunk. m hasznlhat a +=" jel is, ezltal bvt-
hetjk a vltoz korbbi rtkt. A mveleti jel utn mst mr nem rhatunk
az els sorba. Az rtkek a kvetkez sorokban kvetkeznek, s a blokkot az
endef sz zrja. Az endef eltt szerepl jsor-karakter mr nem szmt bele az
rtkadsba.
Lthatan az rtkadsnl hivatkozhatunk ms vltozkra is, ahogy a
korbbi esetekben is. Szksg esetn meg is szntethetjk a definilt vltozt
az undefine kulcsszval:
undefinek et-sor `
A.3.7. A vltoz hivatkozsnak specilis esetei
A helyettest hivatkozs rvn lehetsgnk van arra is, hogy a vltozra
val hivatkozs sorn az rtkt mdostva helyettestsk be. Ilyenkor egy
konverzis szablyt definilhatunk. A konverzi sorn az rtket szavanknt
kezeljk, s a szavak vgn tallhat szvegrszleteket cserljk le ms ka-
raktersorozatokra. Nzznk egy pldt:
s
547
A fggelk: Fejleszteszkzk
Ebben a pldban az objs" vltoz rtke elso.o masodik.o" lesz. Vagyis egy
szlistbl knnyen elllthatunk mdostott listkat is. A helyettest hi-
vatkozs hivatalos formtuma a kvetkez:
$(v altozo:a=b)
vagy
${ v altozo:a=b}
Itt a valtozo" egy vltoz, amely szavakbl ll listt tartalmaz. A mvelet
minden sz vgn lecserli az a" szvegrszletet b" szvegre.
Egy msik specilis vltoz-hivatkozsfajta a szmtott vltoznevek
hasznlata. Ebben az esetben a hivatkozott vltoz nevt egy msik vltoz
tartalmazza. Egy pldn demonstrlva:
a = b
b = c
eredm := $($(a))
A $(a)" rtke b". Ezt behelyettestve a $($(a))" kifejezsbe $(b)"-t kapunk.
Ennek rtke c". Vagyis az eredm" vltoz rtke c" lesz.
A szmtott vltozneveket a helyettest hivatkozsokkal is kombinl-
hatjuk:
src_1 := elso.c
src_2 := masodik.c
objs := $(src_S(a): .c=.o)
Az a" vltoz rtktl fggen vagy az src_1" vagy az src_2 " rtkbl l-
ltjuk el az objs" rtkt, s ennek sorn a .c" kiterjesztst .o"-ra cserljk.
A.3.8. Automatikus vltozk
A receptek ksztsnl gyakran sokat segt, ha a forrs- s a clllomnyok
nevt nem kell minden esetben bernunk, hanem a szably cljbl s felt-
teleibl generlhatjuk. Ez az eddig trgyalt esetekben knnyebbsget jelent,
m tbb ksbb trgyalt esetben nlklzhetetlen eszkz. ltalnos szablyo-
kat nem tudunk gy definilni, hogy az llomnyneveket ne generlnnk, hi-
szen ezekben az esetekben nem tudunk konkrt llomnyokat megadni.
Az llomnynevek ellltst az automatikus vltozkkal vgezzk.
Az A.2. tblzat foglalja ssze az automatikus vltozkat a jelentskkel.
548
A.3. Make
A.2. tblzat. Automatikus vltozk
Automatikus vltoz Jelents
$ @ > A clllomny neve.
$< A fggsgi lista els elemnek a neve.
$? Az sszes olyan felttelfjl neve (sorban, szkzzel elv-
lasztva), amely frissebb a clllomnynl.
Az sszes felttelfjl neve szkzzel elvlasztva.
$+
Jelentse nagyrszt egyezik az elzvel, m ha a feltte-
lek kzt tbbszr szerepel a fjl, akkor azt ugyangy tbb
pldnyban tartalmazza.
$* A clfjl nevnek uttag nlkli rsze.
A kvetkez fejezetekben tallkozunk az alkalmazsi terletekkel is.
A.3.9. Tbbszrs cl
Egy szably megadsakor nemcsak egy trgyat, hanem trgyak listjt is meg-
adhatjuk szkzkkel elvlasztva Ekkor minden trgyra kln-kln vgre-
hajtdik a szably. Ez teht olyan, mintha ugyanazt a szablyt lemsoltuk
volna annyiszor, ahny clllomnyunk van, s mindegyik szably trgyhoz
bernnk egy-egy clllomnyt. Termszetesen ennek csak gy van rtelme,
hogyha nem pontosan ugyanazt a parancsot hajtjuk vgre minden esetben.
Azt az ellenttet, hogy a recept egyforma, de a vgrehajtott parancsok mgis
klnbzek legyenek, az automatikus vltozkkal tudjuk feloldani.
Nzznk egy pldt, ahol egy forrsllomnybl kt klnbz programot
fordtunk eltr paramterezssel:
debug_flags :=-g3 -00
rel ease_fl ags :=-g0 -03
prgs :=debug release
alt: $(prgs)
. PH0NY: all
$(prgs): hello.c
gcc $($(@)_flags) -o $@$<
A make parancs kiadsa utn kt fordts trtnik. Ltrejn egy debug" s
egy release" nev llomny:
gcc -g3 -00 -o debug hello.c
gcc -g0 -03 -o release hello.c
549
A fggelk: Fejleszteszkzk
A kt fordts eltr paramterezssel jn ltre. A $($(@)_flags)" kifejezsben
lthatunk egy automatikus vltozt: $(@)", amely az aktulis trgy rtkt
veszi fel. Ezt a flags" szveggel kiegsztve egy msik vltoz nevt adja ki,
amelyet felhasznlva beillesztjk annak rtkt. A ltrehozott llomny neve
a trgy ($@"), mg a forrs a felttellista els eleme ($<").
A.3.10. Mintaszablyok
Az elz fejezet pldjban lthattuk, hogyan tudunk tbb llomnyt is ell-
ltani ugyanannak a receptnek az alapjn. m ha megfigyeltk, a mdszer-
nek van egy kellemetlen megktse. Az elkvetelmny-lista kzs. Vagyis
csak olyan esetekben mkdik, amikor minden clllomny ellltshoz
ugyanazokra a forrsllomnyokra van szksg.
A problmnkat a statikusminta-szablyok oldjk meg, amelyek lehe-
tv teszik, hogy a clllomnyok nevbl generljuk a feltteleket. Ennek l-
talnos alakja a kvetkez:
T RGYAK:T RGY-MINTA:ELKVETELMNYEK-MINT JA;RECEP T
RECEP T
Hasonlan az egyszer szablymegadshoz a trgyak listjnl hasznlhatunk
helyettest karaktereket. A TRGY-MINTA s az ELKVETELMNYEK-
MINTJA megadja, hogyan szmthat ki egy trgy nevbl a hozztartoz
el'kvetelmnyek neve. A mintk egy helyen tartalmazzk a %" karaktert.
A trgy nevre illesztve a trgy mintjt a %" helyre es szveget a rend-
szer az el'kvetelmny mintjnak %" karakterrel jellt helyre illeszti, s
gy elllt egy j felttelt.
A knnyebb rthetsg kedvrt egy pldn reprezentljuk a statikus-
minta-szablyok hasznlatt:
objs := elso.o masodik.o
all : $(objs)
$(objs): %.o: %.c
gcc -c -o $@ $<
Ez a szably az albbi parancsok vgrehajtst eredmnyezi:
gcc-c-oelso.oelso.c
gcc-c-omasodik .omasodik .c
550
A.3. Make
Vagyis a szably meghvdik elszr az elso.o" cllal. A mintk alapjn eb-
ben az esetben az el'kvetelmny az elso.c" llomny lesz. A fordts sorn a
parancssorba behelyettestdik a clllomny neve s az el'kvetelmny-lista
els eleme mint forrs. Ez eredmnyezi az els parancssort. Majd ezt kvet-
en a masodik.o" clra is vgrehajtdnak ezek a mveletek. Ez eredmnyezi a
msodik parancssort.
A statikusminta-szablynak ltezik egy ltalnostott formja, amelyet
egyszeren mintaszablyoknak neveznk. Mg a statikusminta-szablyok-
nl megadtunk egy trgylistt, s a szably csak azokra az esetekre rvnyes,
addig az ltalnos mintaszablyoknl ezt elhagyjuk, s amolyan alaprtelme-
zett szablyt alkotunk. Ez a szably azonban csak akkor lesz rvnyes, ha a
rendszer nem tall egy specifikus szablyt az adott clllomny ellltsra.
Az ltalnos mintaszably szintaxisa a kvetkez:
Az elz pldnl maradva:
obj s:=elso.omasodik .o
all:$(obj s)
%.o:%.c
gcc-c-o$@$<
A hats ltszlag ugyanaz, mint a statikusminta-szably esetben. m ebben
az esetben egy ltalnos szablyt fogalmaztunk meg, amely lerja, hogy a .0"
vg llomnyok ellltshoz szksg van egy .c" vg llomnyra, illetve
lerja az elllts metdust. Vagyis minden tovbbi .0" vg llomny el-
lltsra is mkdik ez a szably.
A.3.11. Klasszikus ragozsi szablyok
A mintaszablyok eldei a ma mr httrbe szorult ragozsi szablyok.
A make programnak megadhat az uttagok listja, illetve az, hogy az egyik
uttaggal rendelkez llomnybl hogyan llthat el egy msik uttaggal
rendelkez llomny. Hasonlan a mintaszablyokhoz ezek a szablyok is
csak akkor jutnak rvnyre, ha az adott clllomny ellltsra nincs speci-
fikus szably.
Pldaknt nzzk egy ragozsi szably megadst:
551
A fggelk: Fejleszteszkzk
. C.0:
$(CC) C $(CFLAGS) $(CPPFLAGS) o $@$<
. SUFFIXES: . 0 . o
Ez a plda a .c" kiterjeszts forrsllomnyokbl a hozzjuk tartoz .0" ki-
terjeszts llomnyok ellltsra fogalmaz meg ltalnos szablyt. A pl-
dbl lthat, hogy az uttagokat a .SUFFIXES: specilis trgy utn fel kell
sorolnunk, majd pronknt adhatjuk meg, hogy hogyan ll el az egyik utta-
g llomnybl a msik, jelen esetben a .c kiterjeszts C-forrsfjlbl a .0"
kiterjeszts trgykd llomny. A ragozsi szablyok ltalnos alakja a
kvetkez:
Az Fs a forrsuttag, a Cs a cluttag. A forrsbl a cl ellltshoz a make
a RECEPT sorokban megadott utastsokat hajtja vgre. A ragozsi szab-
lyoknak nem lehetnek tovbbi el'kvetelmnyei, csak az az egy, amely gene-
rldik.
Lthatan a ragozsi szablyok ktttebbek, mint a mintaszablyok,
ezrt mostanban az utbbiakat hasznljuk.
A.3.12. Implicit szablyok
A C, C++, Pascal s ms nyelvek forrsllomnyainak lefordtsra megvan-
nak a kialakult fordtprogramok, illetve tipikus parancsok. Ezrt nagyban
egyszersten a fejleszt'k munkjt, ha ezeket a szablyokat nem kellene
mindig gpiesen belerni a Makefile-ba. Ezt a make kszti is felismertk,
ezrt a tipikus mveletek szablyait beleptettk a programba.
Ha a make programnak el kell lltania egy llomnyt, mert arra utast-
juk, vagy szerepel egy feldolgozand szably felttelei kztt, akkor megpr-
blja megkeresni a r vonatkoz szablyt. m ha nem szerepel az llomny
egyetlen szably trgyaknt sem, akkor megprbl egy alaprtelmezett sza-
blyt tallni r, s ha ez sikerl, akkor vgre is hajtja. Ezeket az alaprtel-
mezett szablyokat implicit szablyoknak nevezzk.
Az implicit szablyok nagy rsze elre adott, de mi is rhatunk ilyeneket.
Az elre adott implicit szablyokat a
Make-P
paranccsal nzhetjk meg. Ez a parancs azonban valjban a beptett szab-
lyok s az ltalunk rt Makefile unijt adja vissza. Vagyis ha csak a beptett
szablyokat akarjuk ltni, akkor nem lehet a knyvtrban Makefile.
552
A.3. Make
Az implicit szablyok nagy rsze ragozsi, illetve mintaszably. Hiszen
ezek olyan ltalnos szablyok, amelyek mindenki szmra hasznlhatk.
A recepteket azonban gy fogalmaztk meg, hogy egyes vltozk rtkvel befo-
lysolhatjuk a mkdsket. Pldul a C-llomnyok fordtsakor ez gy nz ki:
%.o: %.c
S(CC)$(CFLAGS)$(CP P FLAGS)S(TARGET_ARCH) -c $(0UTP UT_OP TION)$<
Lthatan pldul a CFLAGS vltoz rtkvel befolysolhatjuk, milyen opci-
kkal trtnjen a C-fordt meghvsa. Vagyis elg a Makefi/e-unkban ennek a
vltoznak ms rtket adni, ha az alaprtelmezett rtkek nem megfelelek,
s nem szksges a szablyt jra megalkotni. Az ilyen jelleg vltzk nev-
nl a konvenci a nagybetk hasznlata, ahogy a pldban is szerepel.
A.3.13. Specilis trgyak
Az eddigi fejezetek sorn lthattunk mr kt specilis clt is. Ilyen volt a
.PHONY s a .SUFFIXES. Az A.3. tblzatban sszegezzk a legfontosabbakat.
A.3. tblzat. Specilis clok
.PHONY Ennek a clnak az elfelttelei hamis cloknak minslnek. Va-
gyis a clhoz tartoz szablyt idblyeg-ellenrzs nlkl min-
denkppen lefuttatja a make.
.SUFFIXES A cl elfelttelei llomnynv-kiterjesztsek, amelyeket a make
a ragozsi szablyok keressnl hasznl.
. DEFAULT Ehhez a clhoz megadott recept fut le azokban az esetekben, ha
egy adott clhoz sem explicit, sem implicit szablyt nem tall a
rendszer.
.SILENT Ha megadunk elfelttelt ehhez a szablyhoz, akkor az ezek el-
lltsnl vgrehajtott parancsokat nem rja ki a make. Ha nem
adunk meg elfelttelt, akkor minden recept vgrehajtsa csen-
des" lesz.
. ONESHELL Korbban lthattuk, hogy a recept vgrehajtsakor minden sor
kln shellpldnyban hvdik meg. Ennek a specilis clnak a
hasznlatval ezt mdosthatjuk. Ebben az esetben a teljes re-
cept egy shellpldnyban hajtdik vgre.
553
Afggelk: Fejleszteszkzk
A.3.14. Direktvk
A direktvk nagyon hasonltanak a C nyelvben hasznlt preprocesszordirek-
tvkhoz Arra utastjk a make programot, hogy a Makefile olvassa kzben
valamilyen specilis mveletet vgezzen el. Ezek a mveletek a kvetkezk
lehetnek:
ms Makefile-ok beolvassa;
felttelek alapjn a Makefile egyes rszeinek hasznlata vagy figyel-
men kvl hagysa;
vltozk definilsa.
Elsknt nzzk meg ms llomnyok hozzadst a Makefile-unkhoz
include FAJL_NEVEK...
A pldban a FAJL_NEVEK egy olyan kifejezs, amely szkzzel elvlasztott
fjlnevekbl, specilis karakterekbl s vltozkbl llhat. A make betlti a
megadott llomnyokat, s beilleszti a Makefile-ba.
Felttelek alapjn a Makefile egyes rszeit kihagyhatjuk, vagy benne
hagyhatjuk a vgrehajtott mveletek kztt:
ifeq($(cC),gcc)
libs :=$(gcc_libs)
el se
libs :=$(normal_libs)
endif
A fenti pldban, ha a CC vltoz rtke gcc, akkor a msodik sor hajtdik
vgre, egybknt a negyedik.
Vltozkat a define direktvval definilhatunk. Erre lthattunk pldt a
tbbsoros vltozk ltrehozsnl. (Lsd az A.3.6. Tbbsoros vltozk defini-
lsa alfejezetben.)
A.4. Make alternatvk
Br a make hatkony eszkz, amely ms platformokon is jl hasznlhat, m
nagyobb projekteknl, amikor a clok szma megn, akkor a megrsa ssze-
tett, nehz feladat lehet. Emellett nehezen tud adaptldni a klnbz rend-
szerek eltr konfigurciihoz. Fordtplatformok vltsa esetn szksg lehet
a Makefile mdostsra.
554
A.4. Make alternatvk
A.4.1. Autotools
A GNU Autotools kiegszti a GNU make funkcionalitst kibvtett szably-
listval s rszletes fggsg-ellenrzssel. F clja a forrskdok hordozha-
tsgnak megteremtse a Unix rendszerek kztt. Szmos nylt forrskd
szoftvercsomag hasznlja.
A GNU Autotools tbb klnll programot tartalmaz, mint az Autoconf,
az Automake s a Libtool. m a programok a mkdsk sorn tovbbi esz-
kzkre is ptenek, pldul a pkg-configre s a gettextre.
Az Autoconf ltrehoz egy configure nev szkriptllomnyt a configure.ac
llomny alapjn. A configure llomnyt lefuttatva felderti a szksges fg-
gsgeket, vagyis a fordtshoz hasznlt programok s fejleszti knyvtrak
megltt s elrsi tjt. Ha minden szksges elemet megtallt, akkor az
eredmnyek s a Makefile.in llomny alapjn legenerlja azokat a Makefile-
okat, amelyekkel a fordtsokat elvgezhetjk.
Az Automake a Makefile.in llomnyok ellltsban segt. Bemenetknt
egy Makefile.am nev llomnyt hasznl, amelybl hordozhat Makefile l-
lomnyok ellltshoz hasznlhat Makefile.in llomnyt llt el.
A Libtool a fejleszti knyvtrak ellltsban segdkezik.
A felhasznlknak a fordtshoz nincs szksgk a teljes Autotools cso-
magra. A forrscsomagban lv configure szkript kpes az Autotools eszkzk
nlkl is elltni a feladatt.
A.4.2. CMake
A CMake (h,ttp:/ /www.cmake.org/) hasonlan a GNU Autotoolshoz Makefile-
okat hoz ltre, amelyekkel elvgezhetjk a tnyleges fordtst. Belltstl
fggen azonban akr Visual Studio-projektllomny ellltsra is alkal-
mas. Vagyis fordt- s platformfggetlen mdon gondoskodik a forrskd le-
fordtshoz szksges llomnyok legenerlsrl.
A.4.3. qmake
A qmake a Qt-csomag rsze. F feladata Qt-programok fordtsnak tmoga-
tsa. Automatikusan kezeli a moc s a uic segdprogramok hvst. Egyszer
konfigurcis llomny, s nagy mennyisg beptett tuds jellemzi. Mk-
dse hasonlt az elz kt eszkzhz. Eredmnyknt egy Makefile-t llt el,
amellyel elvgezhetjk a fordtst.
555
A fggelk: Fejleszteszkzk
A.4.4. SCons
Az SCons (http://www.scons.org/) egy szoftver-konstrukcis" eszkz. Automa-
tikusan vizsglja a forrskdokban a fggsgeket, elvgzi a platformadapt-
cis lpseket. Eredmnyknt ksz binris programokat llt el.
Az SCons Python-alap eszkz, gy a konfigurcis llomnyok s a ford-
tsi mveletek lersai Python-szkriptek.
A.5. IDE
Manapsg a fejlesztk a munkjukhoz olyan knyelmes krnyezetet szeret-
nnek, amely tveszi tlk a gyakran ismtld egyszer mveletek egy r-
szt. A Unix vilg hagyomnyos, fapados" fejleszti eszkzei nem elgtik ki
ezt az ignyt, ezrt szlettek meg az integrlt fejleszti krnyezetek (Integ-
rated Development Environment, IDE).
Az IDE ltalban tartalmaz:
szvegszerkesztt a forrskdok szerkesztshez,
fordtt,
fordtsautomatizlsi eszkzket,
hibakerest.
A Linuxos IDE-megoldsok ltalban ms eszkzkre ptenek. Fordtshoz
GNU-fordtt, automatizlshoz GNU Autottoolst vagy CMake-et s hibake-
resshez a GNU debuggert hasznljk. Ezeket az eszkzket vonjk ssze egy
jl kezelhet egysgbe.
Szmos IDE-eszkzt tallhatunk a Linuxra. Ebbl jelenleg taln az egyik
legelterjedtebb az Eclipse (http://www.eclipse.org/), amely multiplatformos,
tbb programozsi nyelvet tmogat eszkz.
A KDE, de ms C/C++-fejlesztsekhez is jl hasznlhat a KDevelop
(http:/ Ikdevelop.org/).
Hasonlan a GNOME projekt is rendelkezik IDE-eszkzzel, amely ltal-
nosan hasznlhat. Ez az Anjuta (http:/ /www.anjuta.org/).
A Qt-fejlesztsekhez a legclszerbb eszkz a Qt Creator (h,ttp:/ /
qt.nokia.com / products / developer-tools), amely szintn hasznlhat ms
C/C++-fejlesztsekhez is.
556
B FGGELK
Hibakeress
A C az egyik legelterjedtebb programozsi nyelv, s egyrtelmen a Linux-rend-
szerek ltalnos nyelvnek tekinthet. Van azonban j pr olyan jellemzje, ame-
lyek hasznlata knnyen vezethet nehezen felderthet programhibkhoz. Ilyen
gyakori s nehezen felderthet hibafajta pldul a memriaszivrgs (memory
leak), amikor a lefoglalt memria felszabadtsa elmarad, vagy a tlrs (buffer
overrun), amikor a program a lefoglalt terleten kvlre r. Ebben a fejezetben
ezeknek s ms hasonl problmknak a megoldsra is ltunk pldkat.
B.1. gdb
A hibakeresknek, mint pldul a gdb-nek, az a rendeltetse, hogy belelssunk
egy program mkdsbe, kvethessk a futs sorn lezajl processzeket, to-
vbb hogy megtudjuk, mi trtnt a program sszeomlsakor, mi vezetett a
hibhoz.
A gdb-nek a funkciit alapveten ngy csoportba oszthatjuk:
a program elindtsa,
a program meglltsa meghatrozott felttelek esetn,
a program megllskori llapotnak vizsglata,
a program egyes rszeinek megvltoztatsa s a mdostsok hats-
nak vizsglata.
A gdb a C-ben s C++-ban rt programok vizsglatra hasznlhat elssorban.
m ms nyelvek rszleges tmogatsa is megtallhat benne (D, Modula-2 ,
OpenCL C).
B fggelk: Hibakeress
B.1.1. Plda a gdb hasznlatra
A gdb nagyon sok olyan paranccsal s lehetsggel rendelkezik, amelyek meg-
tallhatk a dokumentcijban. Egy tlagos hibakeresshez azonban a pa-
rancsok tredkt elg ismerni. Ebben a fejezetben bemutatunk egy ilyen
plda-hibakeresst ltalban a parancsokkal.
Az albbi hibs pldaprogramot vizsgljuk meg:
/* hibas.c - Hi bas program */
#i ncl ude <stdio. h>
#i ncl ude <string .h>
voi d hi basfv()
{
char* str =NULL;
strcpy (str, ,"Hello");
pri ntf("%s \n" , str) ;
}
{
hi basfv() ;
return 0;
A hibakeresshez az adott programnak tartalmaznia kell a hibakeressi infor-
mcikat, vagyis az adott programot a -g kapcsolval kell fordtani. m ha a
gdb-t hasznljuk, akkor clszer a programot a -ggdb kapcsolval fordtani:
114
$gcc-Wall -ggdb-ohibashibas.c
Elszr indtsuk el a gdb programot, s tltsk be a programunk kdjt:
$ gdb hibas
GNUgdb (ubuntu/Li naro 7.2-lubuntull) 7.2
Copyright (C) 2010 Free Software Foundation , Inc.
Li cense GPLv3+: GNU GP Lversion 3 or 1 ater
<http://gnu.org/li censes/gpl . html>
This is free software: you are free to change and redi stri bute i t.
There isNOWARRANTY,tothe extent permitted by law.
Type "show copying" and "show warranty" for details.
ThisGDBwas configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/...
Reading symbols from /tmp/hibas...done.
(gdb)
114
A
-ggdb kapcsol hasznlatakor az informci formtuma a gdb-re lesz optimalizlva.
Ms hibakeres programokat ez sszezavarhat. Ezrt csak a gdb esetn hasznlatos.
558
B.1. gdb
Helyezznk el egy trspontot (breakpoint) a hibasfu" nev fggvnynl:
(gdb) break hibasfv
Breakpoi nt 1 at 0x80483fa: fi 1 e hi bas . c , 1 i ne 7.
(gdb)
A programunk elindtshoz adjuk ki a run parancsot:
(gdb) run
starting program: /tmp/hibas
Ezt kveten a terminlban a programunk kimenett ltjuk, ha van ilyen, il-
letve amit berunk, az a program bemenete lesz. Esetnkben a pldaprogram
nem tartalmaz sem kirst, sem beolvasst a trspont eltt.
A program addig fut, amg elri a trspontot, amelyet a hibasfu" nev
fggvnyre lltottunk be Amikor ez az esemny bekvetkezik, akkor felfg-
gesztdik a program futsa, s visszakapjuk a gdb parancs promptjt:
Breakpoi nt 1, hibasfv () at hi bas . c :7
7 char* str = NULL;
(gdb)
Tovbblphetnk egy sorral a next parancs segtsgvel:
(gdb) next
8 strcpy(str, "Hello");
(gdb)
Lehetsgnk van arra, hogy a kvetkez sorra lpve belelpjnk a soron k-
vetkez fggvny rutinjba. Ezt a step paranccsal tehetjk meg.
A backtrace parancs segtsgvel megnzhetjk, melyik szubrutinban j-
runk ppen:
(gdb) backtrace
#0 hibasfv () at hibas.c:8
#1 0x08048435 in main (argc=1, argv=Oxbffff7e4) at hibas.c:14
(gdb)
Sorban minden aktv fggvny stackkerett megmutatja. gy lthatjuk azt is,
hogy az aktulis fggvny melyik msikbl hvdott meg. Ha szeretnnk b-
vebb informcikat ltni a loklis vltozkrl, akkor kiegszthetjk a full pa-
ramterrel:
(gdb) backtrace full
#0 hibasfv () at hibas.c:8
str = Ox0
#1 0x08048435 in main (argc=1, argv=Oxbffff7e4) at hibas.c:14
Nolocals.
(gdb)
559
B fggelk: Hibakeress
Ha egy vltoz aktulis rtkt akarjuk megvizsglni, akkor a print parancs
segt:
(gdb) print str
$1 = Ox0
(gdb)
Ha a forrskdnak azt a rszt szeretnnk ltni, ahol ppen jrunk, akkor a
list paranccsal kilistzhatjuk:
(gdb) list
3 #i nclude <stri ng .h>
4
5 void hi basfv()
6
7 char* str = NULL;
8 strcpy(str, "Hello");
9 printf("%s\n", str);
10
11
12 int mai n(i nt argc, char* argv )
(gdb)
Elre gyanakodhatunk, hogy hiba volt a karaktertmb allokcijnak az el-
mulasztsa, illetve az strcpy0 fggvnynl hiba trtnik, amikor a 0-s cmre
megprblunk majd szveget msolni.
Engedjk tovbb a program futst a continue paranccsal, s megltjuk a
hiba hatst:
(gdb) continue
Conti nui ng .
Program received signalSIGSEGV,Segmentation fault.
0x001a45c6 i n ?? () from /1 i b/i 386-1 i nux-gnu/1 i bc. so. 6
(gdb)
Ha a programunkban nem lenne hiba, akkor szablyosan lefutna. m ese-
tnkben fatlis hiba trtnt, s a rendszer a SIGSEGV jelzssel terminlja a
folyamatunkat. Mivel a gdb-vel futtatjuk a programunkat, ezrt a folyamat
nem r azonnal vget. Lehetsgnk van a korbban megismert parancsokkal
megvizsglni a folyamat llapott a jelzs rkezsnek pillanatban.
s vgl a quit paranccsal kilphetnk. Ha a folyamatunk mg ltezik,
mert csak felfggesztettk a futst, akkor kilps eltt rkrdez a gdb, hogy
akkor is ki akarunk-e lpni, ha ez a folyamat megszntetst jelenti:
560
B.1 . gdb
(gdb) quit
Adebugging session is active.
Inferior 1 [process 2 052 1] will be killed.
Quitanyway? (y or n)
B.1.2. A gdb leggyakrabban hasznlt parancsai
Foglaljuk ssze az elz pldban ltott gdb parancsokat. Minden parancsnak
ltezik rvidtett formja is, gy a B.1. tblzatban ezeket is feltntetjk.
B.1 . tblzat. A gdb parancsok
Parancs Rvid. Magyarzat
run r A folyamat elindtsa
next n A kvetkez sorra (next line) ugrs
step s Belps egy fggvnybe (step into)
print p Kirja (print) a megadott vltoz aktulis rtkt
backtrace bt A verem megjelentse
list l A forrskd kilistzsa az aktulis pozci krnykn
continue c A program futsnak folytatsa
Ctrl + D A program lelltsa (az EOF jel)
quit q Kilps a gdb programbl
Ha elfelejtennk valamelyik parancs szintaxist, akkor a help paranccsal
krhetnk segtsget.
B.1.3. A gdb indtsa
A gdb-t tbbfle argumentummal s opcival indthatjuk, s ezzel befolysol-
hatjuk a hibakeressi krnyezetet.
A leggyakrabban egy argumentummal hasznljuk, ez a vizsgland prog-
ram neve:
561
B fggelk: Hibakeress
m a program mellett megadhatjuk msodik paramterknt a core llo-
mnyt:
115
g 1,b .. :wogram><coref j l>
A core fjl helyett azonban megadhatunk egy folyamatazonostt (pid) is, ha
egy ppen fut processzt szeretnnk megvizsglni:
<pid>
Ilyenkor a gdb a megadott pid-szm folyamathoz kapcsoldik. Meglltja a
folyamatot (stop), hogy lehetsgnk legyen trspontokat belltani. Ezt k-
veten folytathatjuk a processz futtatst a continue paranccsal.
Az elzekben felsorolt funkcikat a gdb elindtsa utn parancsokkal is
elrhetjk, ha szksg van r.
Az eddig emltett funkcik mellett a gdb-t hasznlhatjuk tvoli hibakere-
ssre is, amikor egy msik gpen fut alkalmazs llapott kvetjk figyelem-
mel. Ezt olyankor alkalmazzuk, amikor az adott gpen nem vgezhetjk el a
hibakeresst. Pldul kernel vizsglatnl vagy korltozott erforrsokkal
rendelkez eszkz esetben. Ilyenkor a kt gpet soros nullmodem-kbellel
vagy Etherneten kell sszektnnk. Utbbi esetben egy TCP/IP kapcsolaton
keresztl folyik a kommunikci. Ha a kernel mkdst akarjuk tvolrl k-
vetni, akkor a kernelbe bele kell fordtanunk, majd be kell kapcsolnunk a
megfelel funkcikat. Alkalmazsok esetn tipikusan egy gdbserver nev al-
kalmazst futtatunk a tvoli gpen, amellyel a gdb kommuniklni tud.
B.1.4. Trspontok: breakpoint, watchpoint,
catchpoint
A trspont meglltja a program futst, amikor az elr egy meghatrozott
pontra. Minden trsponthoz megadhatunk plusz feltteleket is. Belltsuk
ltalban a break paranccsal s paramtereivel trtnik.
Trspontknt megadhatjuk a program egy sort, egy fggvnynevet
vagy egy egzakt cmet a programon bell:
break FUGGVENY
break FAJLNEV:FUGGVNY
115
Amikor a processz egy programhiba kvetkeztben lell, gyakran egy core nev llomny
jn ltre a processz munkaknyvtrban. (Ltrehozst az adott shell limitbelltsai sza-
blyozzk. A bash shell esetn ulimit -c. Emellett a kernel belltsai befolysolhatjk a
pontos llomnynevet s a ments helyt.) Ez az llomny a processz memria-pillanatfel-
vtelt tartalmazza a hiba pillanatban. A gdb program kpes ezt az llapotfelvtelt rtel-
mezni, s a fejleszt szmra rthet formban megmutatni a processz pillanatnyi llapott
a hiba bekvetkeztekor.
562
B.1. gdb
A forrsllomny a FUGGVENY fggvny meghvsnl helyezi el a trs-
pontot (lekezeli a C++-fggvny felldefinilst is):
break +OFFSET
break -CFFSET
Az aktulis pozcitl megadott szm sorral vissza vagy elrbb helyezi el a
trspontot:
break SORSZAM
Az aktulis forrsllomny SORSZAM sorban helyezi el a trspontot:
break FA31-N V: SORSZAM
A FAJLNEV forrsllomny SORSZAM sorban helyezi el a trspontot:
break m.
A CIM cmen helyezi el a trspontot:
break
Argumentum nlkl az aktulis verem kvetkez utastsra helyezi el a t-
rspontot:
break if COND
A trsponthoz feltteleket is megadhatunk. A COND kifejezs minden alka-
lommal kirtkeldik, amikor a trspontot elri a processz, s csak akkor ll
meg, ha az rtke nem nulla, vagyis igaz.
A watchpoint olyan specilis trspont, amely akkor lltja meg a prog-
ram futst, ha a megadott kifejezs rtke vltozik. Viszont nem kell megadni
azt a helyet, ahol ez megtrtnhet. A watchpointokat klnbz parancsokkal
llthatjuk be:
watch KIFEJEZES
A gdb meglltja a folyamatot, amikor a program mdostja, rja a KIFEJEZES
kifejezs rtkt. A kifejezs ltalban egy vltoz neve. Ebben az esetben, ha a
vltoz rtke valahol mdosul, akkor ott a program futsa megll. A felttelt
korltozhatjuk, hogy csak akkor lltsa meg a folyamatot, ha egy bizonyos
szl mdostja az rtket.
Az rtk olvasst is figyelhetjk:
rwatch KIFEJEZES
563
B fggelk: Hibakeress
Ebben az esetben a watchpoint akkor lltja meg a futst, amikor a program
kiolvassa (read) a KIFEJEZES kifejezs rtkt.
A kettt kombinlhatjuk is:
awatchKIFEJEZES
Ebben az esetben a watchpoint mind az olvasskor, mind az rskor megllt-
ja a program futst.
A belltsok utn a watchpointokat ugyangy kezelhetjk, mint a norml
trspontokat. Ugyanazokkal a parancsokkal engedlyezhetjk, tilthatjuk, t-
rlhetjk ket.
A catchpoint egy msik specilis trspont, amely akkor lltja meg a
program futst, ha egy specilis esemny kvetkezik be. Ilyen esemny lehet
pldul egy C++-programban bekvetkez kivtel (exception) vagy egy knyvtr
betltse. Ugyangy, mint a watchpointoknl, itt is tbb lehetsgnk van a t-
rspont belltsra. A catchpoint ltalnos belltsi formja a kvetkez:
Itt az ESEMENY kifejezs a B.2. tblzat elemei kzl valamelyik:
B.2. tblzat. Esemnyek s lersuk
jE
throw Egy C++-kivtel keletkezsekor
catch Egy C++-kivtel lekezelsekor
exec Az exec fggvny meghvsakor
fork
vfork
load [KONYVTARNEW
Az fork fggvny meghvsakor
Az vfork fggvny meghvsakor
A KONYVTARNEV knyvtr betltsekor
unload [KONYVTARNEW A KONYVTARNEV knyvtr eltvoltsakor
A catchpointokat ugyangy kezelhetjk a bellts utn, mint a korbbi t-
rspontokat.
Ha tbb trspontot is elhelyeznk a projektnkben, akkor nehz minde-
gyiket fejben tartani. m erre nincs is szksg, mert knnyen kilistzhatjuk
ket:
infobreak points
A lista tartalmazza a trspontok indext is, amellyel knnyen hivatkozha-
tunk rjuk tiltsnl, engedlyezsnl vagy trlsnl.
564
B.1. gdb
Ha a futtats sorn egy trspont elvgezte a feladatt, gyakran trlni
akarjuk. Ez nem felttlenl szksges, hiszen trls nlkl is tudjuk folytatni
a futtatst, m a ksbbiekben zavar lehet a trspont jelenlte. A trspon-
tok trlst fggetlenl a tpusuktl a delete vagy a clear paranccsal vgez-
hetjk el.
Ha a meglls utn a megllst okoz trspontot szeretnnk trlni, ak-
kor ezt a clear parancs egyszer meghvsval tehetjk meg:
cl gr
A msik lehetsgnk, hogy a trspontot a helyzete alapjn azonostjuk, ha-
sonlan, mint a break parancsnl:
Ahogy korbban sz volt rla, a trspont trlst az indexe alapjn is elv-
gezhetjk. Erre a delete parancs szolgl:
del e
te Wreakpoi nt
TO:
v} ,
r
A TARTOMANY paramterben hivatkozhatunk egy trspontra, de megad-
hatunk tbb indexet is, st akr egy tartomnyt is a trspontok listjban.
Ha elhagyjuk a paramtert, akkor az sszes trspontot kitrljk.
Nemcsak trlhetjk a trspontokat, hanem le is tilthatjuk 'ket. A tilts
sorn ugyangy nem lesz hatsuk, mint trls esetn. m ha a ks'bbiek so-
rn ismt szksgnk lesz az inaktivlt trspontokra, akkor knnyedn jra
engedlyezhetk.
Tiltskor s engedlyezskor a trspontoknak tbb llapotuk is lehet:
Engedlyezett trspont, amely meglltja a program futst.
Letiltott trspont, amelynek nincs hatsa a folyamatra.
Egyszer engedlyezett trspont, amely meglltja egyszer a program
futst, m automatikusan letiltott llapotba kerl.
A tbbszr engedlyezett trspont meghatrozott alkalommal megl-
ltja a folyamatot, mieltt letiltott llapotba kerl.
Egyszer engedlyezett trspont, amely a folyamat meglltsa utn
automatikusan trldik. A tbreak paranccsal llthat be a break pa-
rancsnl ltottak szerint.
565
B fggelk: Hibakeress
A trspontot tiltani a disable paranccsal lehet a delete parancsnl megismer-
teknek megfelelen:
d s b le [b i-ea kpoint s] ETARTOMANYj
Engedlyezsre tbb lehetsg is adott az engedlyezs fajtjtl fggen, vi-
szont minden esetben az enable parancsot hasznljuk. Az egyszer enged-
lyezs a kvetkez:
a b le [b r eRkPOns]
Egyszeri engedlyezs az albbiak szerint trtnik:
ena b le [b r e kpoint s] once TARTOMANY
Tbbszri engedlyezs pedig eszerint:
ena b le [b r ea kpoint s] SZAMTARTOMNY
A SZM paramter a szmll kezdrtkt tartalmazza. Minden alkalom-
mal, amikor a trspont meglltja a futst, a szmll eggyel cskken. Ami-
kor a szmll elri a 0 rtket, akkor a trspont automatikusan letiltdik.
Egyszeri engedlyezs automatikus trlssel az albbi:
ena b le [b r ea kpoint s] delet e TARTOMANY
B.1.5. Data Display Debugger (DDD)
A DDD (Data Display Debugger) olyan GNU-projekt, amelynek az a clja,
hogy gr a fikus elt t (front-end) segtsgvel megknnytse a parancssoros
hibakeresk, pldul a GDB, a DBX, a WDB, a Ladebug, a JDB, az XDB, a
Perl debugger vagy a Python debugger hasznlatt.
A DDD rgi, m manapsg is gyakran hasznlt program. A szoksos el-
ttfunkcik mellett (pldul a forrsllomnyok megtekintse) tbb jelents
szolgltatssal is rendelkezik. Ilyenek az interaktv grafikus adatbrzol-
sok, ahol az adatstruktrk grfknt vannak megjelentve. De kpes akr
grafikonokat is kszteni az adatainkbl.
A DDD fellett mutatja a B.1. bra.
Ennek rszletei a kvetkezk:
Az Ada t ablak az aktulis megfigyelt program adatait mutatja.
A For r skd ablak a program forrskdjt mutatja.
566
Mensv
Eszkzsv
Adatablak
b$:-*-me
F1L
0121111111M111111
MEll=
- Y.
II lin
,
t
114 1
tc, t.aori altat 11111C111
Itg_ttetttat thrt)
t
Ott .14
Ittt M. L'St
Itat-' t S
-
ot
lOtt ...t no. L st
Ittt-Artt- It- 111
atm. t tit- tttts tt
*ot, t 11 t:
4.140. I tt;
Forrskdabtak-
litt tett11 10.1t
Gpikd-abtak
tL/W1,p).1191-U.IW11.. .1 *4 Wlf< :
,
10 3 tl l :[.+
Ma .11,4_1nl,j0 .1% o. 4.1 141:a)..bs.
orwro
Hibakeres konzol
llapotsor
B.1. bra. A DDD fellete
.11t1
100 44410/ *(11 ..0 ~Ment
vol. IisAg *00~ I
FI* MA*, ot itst-mot->lert-Heel fia m ca , 4
B.1. gdb
A Hibakeres konzol fogadja a hibakeres (debugger) parancsokat,
s megmutatja ezek zeneteit.
A Parancsok a leggyakrabban hasznlt parancsok gombjait tartal-
mazza.
A Gpi kd ablak az aktulis gpi kd programot mutatja.
Ft!
Parancsok
Grdtsv
tmretez
-rtkjelzs
Fogtaltsgjetz
B.1.6. Az IDE-k beptett hibakeresje
Az integrlt fejleszti krnyezetek (IDE) gyakran tartalmaznak hibakerest.
Ezek valjban grafikus gdb-elttek. Gyakran a gdb funkcionalitsnak sz-
les skljt teszik elrhetv. Ugyanakkor mindezt a fejleszti krnyezeten
bell vgezhetjk el, ezrt hasznlatuk nagyon knyelmes.
Ha begyazott fejlesztseken dolgozunk, a fejleszti krnyezet gyakran
mg a tvoli hibakeresst is biztostja. Ilyenkor az alkalmazst tviszi a
teszteszkzre, majd a gdbserver programmal indtja el. A fejleszti gpen el-
indtva a gdb programot, az kapcsoldik a begyazott eszkzhz, s mris v-
gezhetjk a hibakeresst a fejleszti krnyezeten bell. Ilyen szolgltatst
pldul az elterjedt Eclipse IDE is tartalmaz.
567
B fggelk: Hibakeress
B.2. Memriakezelsi hibk
Korbban mr emltettk, hogy a C s a C++ nyelv hasznlatakor klnbz
memriakezelsi hibkat ejthetnk, amelyeknek feldertse nehz feladat.
Ennek megoldsra szmos eszkz szletett. Az albbiakban ezekbl ismerte-
tnk nhnyat.
Vizsglataink eltt lltsunk el egy hibs programot, amely az llator-
vosi l" szerept tlti be. A memriakezelsi hibktl hemzseg kdunk le-
gyen a kvetkez:
1 /"
2 "Hi bas kod
3 */
4
5 #include <stdlib.h>
6 #include <stdio. h>
7 #i nclude <string .h>
8
9 char gl obal i s [5] ;
10
11 int mai n(voi d)
12 {
13 char 1 okal i s [5] ;
14 char* dinamikus;
15
16 // 1. tuliras (kicsit)
17 dinami kus=mal loc(5);
18 strcpy(dinamikus, "12345") ;
19 printf("1: %s \ n" , dinamikus);
20 free(dinami kus);
21
22 // 2. fel szabadi tott terulet hasznalata
23 strcpy(dinamikus, "12345") ;
24 printf("2: %s \n" dinamikus);
25
26 // 3. tuliras (nagyon)
27 dinami kus=mal 1 oc(5) ;
28 strcpy(dinamikus, "12345678") ;
29 printf("3: %s \ n" , dinamikus);
30
31 // 4. el e i ras
32 "(dinamikus-1)i \ 0 ;
33 printf("4: %s \n" , dinamikus);
34
35 // memoriaszivargas! ! !
36
37 // 5. lokalis valtozo tuli rasa
38 strcpy(lokal i s , "12345") ;
39 printf("5: %s \n" , 1 okal i s) ;
40
568
B.2. Memriakezelsi hibk
41 // 6. lokalis valtozo eleirasa
42 lokalis[-1]=' \O' ;
43 printf("6: %s\n", lokalis);
44
45 // 7. globalis valtozo tul rasa
46 strcpy(globalis, "12345");
47 printf("7: %s\n", globalis);
48
49 // 8. globalis valtozo eleirasa
50 globalis[-1]-=' \O' ;
51 printf("8: %s\n", globlis);
52
53 return 0;
Ez a kd hromfle memrit allokl, s ezekkel kvet el hibkat. Az els tpus
a dinamikusan, malloc-kal alloklt memria, a msodik loklis vltoz, amely a
program vermben helyezkedik el, a harmadik pedig globlis vltoz, amely egy
kln rszen tallhat. Mindhrom esetben tlrjuk (buffer overrun) a lefoglalt
tartomnyt, illetve egy-egy byte-ot elrunk Ezek mellett a kd tartalmaz egy
mr felszabadtott memriarszhez val hozzfrst s egy fel nem szabadtott
memriarszt, az gynevezett memriaszivrgst (memory leak) is.
Elsre a kdot lefordtva s lefuttatva az albbit ltjuk:
$ gcc -ggdb -Wall -o bugos bugos.c
. /bugos
1: 12345
2: 12345
3: 12345678
4: 12345678
5: 12345
6: 12345
7: 12345
8: 12345
tmutat Habr a fenti programot bven ellttuk hibkkal, mgis ltalban problma nlkl
lefut. Ez azonban nem jelenti azt, hogy ezek a hibk lnyegtelenek. A tlrsok idvel a prog-
ram vratlan s elsre megmagyarzhatatlannak tn sszeomlshoz vezethetnek. A mem-
riaszivrgsok pedig idvel felemsztik a szmtgp memrijt.
A kvetkezkben megismerhetnk nhny eszkzt, amely ennl tbbet mutat
szmunkra.
B.2.1. Malloc hibakeresk
A malloc hibakeresk csaldjba olyan hibakeresst segt eszkzk tartoz-
nak, amelyek a malloc() s a free() fggvnyek felldefinilsval rik el a cl-
jukat, s segtik a memriakezelsi hibk megtallst. Lnyegben fejleszti
knyvtrak, amelyeket felhasznlunk a programunkban.
569
B fggelk: Hibakeress
A memriakezelsi hibk f problmja az, hogy nehezen detektlhatk,
mivel a folyamat a sajt adatterletn vgez illeglis mveleteket. Ezt sem az
opercis rendszer, sem a hibakeres nem rzkeli. Ezrt a f clunk az ilyen
jelleg a hibk rzkelse, lthatv ttele.
A malloc hibakeresk az opercis rendszer virtulismemria-kezel
rendszert hasznljk arra, hogy lthatv tegyk a memriakezelsi hibin-
kat. A szoksos allokcis mechanizmust lecserlik egy mdostott algorit-
musra, amely elri, hogy memriakezelsi hiba sorn a folyamat tiltott lapra
rjon. Ezt rzkelve az opercis rendszer az adott ponton segmentation fault
hibval lelltja a folyamatot. Ezltal a hiba lthatv vlik, s a gdb prog-
rammal knnyen elkaphatjuk".
A klnbz hibk feldertshez ms-ms stratgit hasznl a rendszer.
Ezek a megoldsok egyes esetekben tik is egymst, ezrt meg kell adnunk,
hogy ppen melyik hibkat vizsgljuk.
Vegyk sorra a hibkat s a feldertskre alkalmazott stratgikat.
B.2.1.1. Memriaterlet tlrsa
A tlrs hibjt akkor kvetjk el, ha a lefoglalt terlet utn runk. Vagyis
azt kell elrnnk, hogy a foglals utni terlet rsvdett legyen. m csak
memrialapokat tehetnk rsvdett. Ezrt a clunk elrshez a memria-
allokci sorn 2 lapot kell alloklnunk, s az egyes terleteket az albbiak
szerint kell elrendeznnk (B.2. bra):
Foglals
1. lap 2. lap
B.2. bra. Tlrs figyelse
A lefoglalt terletet az els lap vgre helyezzk el. gy ha tlrnnk, akkor bele-
runk a msodik, vdett lap terletbe. Ez azonnal egy kivtelt okoz, amelynek
hatsra az opercis rendszer megszaktja a folyamatot. gy pontosan rzkel-
hetjk a hiba helyt. Ugyanakkor lthat, hogy ha tlrst figyelnk, akkor az
elrst nem tudjuk rzkelni, ezt a rszt teht nem tudjuk levdeni.
m ebben az esetben is bevethetnk egy msodlagos vizsglatot. Ha a fogla-
ls sorn az els lap nem hasznlt rszt feltltjk egy meghatrozott byte-r-
tkkel (mgikus szm), akkor a felszabadts sorn ellenrizhetjk, hogy nem
rzkeljk-e mdosts nyomt. Ha valahol mdosult az rtk, akkor figyelmez-
tetni tudjuk a fejlesztt, hogy vizsglja meg a programot elrsi hibra.
A mgikusszm-mdszer nem olyan hatkony, mint a lapok hasznlata.
Egyrszt nem rzkeli, ha ppen a mgikus szmrtket rjuk a tiltott terlet-
re, msrszt a hibt csak a felszabadtsnl rzkeljk, gy igazbl nem tud-
hatjuk, hogy hol kvetkezett be. Figyelmeztet rendszernek azonban megfelel.
570
B.2. Memriakezelsi hibk
B.2.1.2. Elrs
A tlrsnl hasznlt mdszerek alkalmasak az elrs vizsglatra is. Mivel
most azt ellenrizzk, hogy trtnt-e a lefoglalt terlet el rs, ezrt csak
meg kell fordtanunk az elrendezst (B.3. bra):
Foglals
1. lap 2. lap
B.3. bra. Elrs figyelse
Ebben az esetben akkor okozunk laphibt, ha a lefoglalt terlet eltti lapra
runk. A tlrs ellen azonban vdtelenek vagyunk, ezrt a msodlagos md-
szerrel figyelnnk kell az elfordulst.
B.2.1.3. Felszabadtott terlet hasznlata
Elfordulhat, hogy a felszabadtott terletet a program tovbbra is hasznlja.
Ennek kidertse egy egyszer mdszerrel trtnhet. A foglalsokat a free()
fggvny hvsakor valjban nem szabadtjuk fel, csak vdett tesszk a lapot
a tovbbi hasznlattal szemben. Ha mgis hasznln mg a folyamat, akkor
az automatikusan laphibt okoz, s a vdelmi belltsok megsrtse miatt az
opercis rendszer meglltja a futst. Termszetesen ez a mdszer rendkvl
memriapazarl.
B.2.1.4. Memriaszivrgs
A memriaszivrgst a malloc hibakeresk knyvelses mdszerrel tudjk
felfedni. Knyvelnek minden memriafoglalst s felszabadtst Amikor a fo-
lyamat befejezdik, akkor a hibakeres eszkz sszeveti a foglalsokat a fel-
szabadtsokkal, s ha nem tall meg minden prt, akkor kilistzza, hogy
mely foglalsok nem lettek felszabadtva. Termszetesen azt nem tudhatja az
eszkz, hogy hol kellett volna elvgeznnk a felszabadtst. gy a fejleszt fe-
ladata megtallni az allokcihoz tartoz felszabadts helyt.
Nem minden malloc hibakeres tmogatja a memriaszivrgs feldert-
st, de tallhatunk olyan eszkzt, amely implementlja ezt a mdszert.
B.2.1.5. A malloc hibakeresk korltai
tmutat Mivel a malloc hibakeresk a malloc() s a free0 fggvnyek felldefinilsval
rik el hatsukat, ezrt csak dinamikus allokcik vizsglatra hasznlhatk. Csak itt hvdnak
meg ezek a fggvnyek.
571
B fggelk: Hibakeress
Ugyancsak korltot jelent a jelents memriaigny. A fejleszti gpet el kell
ltnunk memrival, hiszen minden egyes allokci minimum ktlapnyi ter-
letet foglal le a valsgban. (4 kB-os lapokkal szmolva ez 8 kB.) Ha a felszaba-
dtott terleteket is vdjk, akkor a foglalsok eltartanak a program futsnak
a vgig.
B.2.2. Electric Fence
Az Electric Fence egy elterjedten hasznlt malloc hibakeres implementci.
Br ez az eszkz a memriaszivrgs vizsglatra nem hasznlhat, a korb-
ban emltett msik hrom mdszert tartalmazza. Emellett sok ms malloc
hibakeresvel ellenttben az Electric Fence a hibs olvassokat is detektlja.
De legnagyobb elnyeknt taln azt lehet megemlteni, hogy szinte minden
Linux-disztribci tartalmazza.
Hasznlatakor azonban vegyk figyelembe, hogy csak C-programok ese-
tn alkalmazhat, mivel nem tartalmazza a C++ new s delete opertorainak
felldefinilst.
B.2.2.1. Az Electric Fence hasznlata
Az Electric Fence a C knyvtr norml malloc() fggvnyt cserli le a sajt
specilis allokcis rutinjra. gy egyetlen feladatunk, hogy a libefence.a vagy
a libefence.so knyvtrllomnyt hozzkapcsoljuk a programunkhoz. Ezt kt-
flekppen tehetjk meg.
A -lefence argumentummal fordtskor hozzlinkelhetjk a knyvtrllo-
mnyt a programunkhoz. Ez a pldaprogramunknl a kvetkez:
7`4feric"
A msik lehetsg dinamikus linkels esetn az LD_PRELOAD krnyezeti
vltoz hasznlata. Ezzel megadhatjuk, hogy a knyvtrllomny a program
futsa eltt betltdjn:
kOkl
vagy
A kt megolds kzl az utbbit javasoljuk, mert az els esetben a parancs
kiadsa utn a shellben indtott sszes program az Electric Fence hasznlat-
val fut le, ezzel is pazarolva az erforrsokat.
572
B.2. Memriakezelsi hibk
Ha ezek utn lefuttatjuk a programunkat, akkor mr nem garzdlkod-
hat" szabadon. Az Electric Fence vdelmi algoritmusai felfedik a hibt:
$./bugos
ElectricFence2 .2 .0Copy right(C)1987-1999BruceP erens
1:12 3 45
Segmentationfault
Mint lthat, az Electric Fence nem mondja meg, hol a hiba, viszont sokkal
rzkelhetbb teszi, s gy egy hibakeresvel, pldul a gdb-vel, megvizsgl-
hatjuk. (Ehhez termszetesen a programnak rendelkeznie kell a hibakeressi
informcikkal is.)
Esetnkben ez az albbiak szerint alakul:
$gdb./bugos
GNUgdbRedHatLinux(5.2 -2 )
Copy right2 002 F ree SoftwareFoundation,Inc.
GDBisfreesoftware,cov eredby theGNUGeneralP ublicLicense,
andy ouarewelcometochangeitand/ordistributecopiesofit
undercertainconditions.
ThisGDBwasconfiguredas"i3 86-redhat-Linux"...
(gdb)
Ha dinamikusan szeretnnk hozzadni a knyvtrllomnyt, akkor az alb-
biakra is szksgnk van:
(gdb)setenv LD_P RELOAD=libefence.so.0.0
Ezek utn megkezdhetjk a program vizsglatt:
(gdb)r
Startingprogram:/home/tomcat/bugos
[NewThread102 4(LWP 2 672 7)]
ElectricFence2 .2 .0Copy right(C)1987-1999BruceP erens
1:12 3 45
P rogramreceiv edsignalSIGSEGV,Segmentationfault.
[SwitchingtoThread102 4 (LWP 2 672 7)]
0x42 0807a6instrcpy ()from/lib/i686/libc.so.6
(gdb)where
#0 0x42 0807a6in strcpy () from/lib/i686/libc.so.6
#1 0x080484fcin main () atbugos.c:2 3
#2 0x42 017589in libc_start_main ()from/lib/i686/libc.so.6
(gdb)
Mint lthat, a 2 3. sorban mris elkapott egy hibt a rendszer:
2 3 strcpy (dinamik us,"12 3 45");
573
Bfggelk: Hibakeress
Ez az a hely, ahol a felszabadtott memriaterletre prbltunk rni. Ha ezt a
sort megjegyzss alaktjuk, akkor a 2 4 . sorban, a rendszer a felszabadtott
terlet olvassnl rzkeli a hibt. gy tovbbhaladva a kvetkez hiba a 2 8.
sorban tallhat, ahol jelentsen tlrjuk a lefoglalt memrit. Ezt is eltvo-
ltva tovbbi hibt nem rzkel, pedig mint lthat bven maradt mg.
B.2.2.2. A Memory Alignment kapcsol
Lthattuk, hogy az Electric Fence tszaladt az els tlrson, ahol a tarto-
mnyt csak egy byte-tal rtuk tl. A problma forrsa a memriailleszts.
A modern processzorok a memrit tbb-byte-os rszekre osztjk. Ez 32 bites
processzorok esetn 4 byte. A malloc0 ltalnos implementcija is ennek
megfelelen kerektve foglalja le a memrit. Alaprtelmezett belltsok
mellett az Electric Fence is ezt a mdszert alkalmazza, ezrt nem vette szre
az 1 byte-os differencit.
Ahhoz, hogy ezt a hibt megtalljuk, az Electric Fence-nek meg kell ad-
nunk, hogy 1 byte-os illesztst hasznljon. Ezt az EF ALIGNMENT krnye-
zeti vltoz 1-re lltsval tehetjk meg:
(gdb)set env EF_ALIGNMENT=1
(gdb)r
startingprogram:/home/tomcat/bugos
[NewThread102 4(LwP 2 6810)]
ElectricFence2 .2 .0copy right(C)1987-1999 Bruce Perens
P rogramreceiv edsignal SIGSEGV, Segmentationfault.
[switchingtoThread102 4(LWP 2 6810)]
0x42 0807a6instrcpy ()from/lib/i686/libcso.6
(gdb)where
#00x42 0807a6instrcpy ()from/lib/i686/libc.so.6
#10x080485f8inmain()atbugos.c:18
#2 0x42 017589in libc_start_main()from/lib/i686/libc.so.6
(gdb)
gy mr megtallta a 18. sorban tallhat kis tlrsunkat is.
B.2.2.3. Az elrs
Ahogy kiderlt, ez idig nem sikerlt detektlnunk a elrs esett, vagyis
amikor a lefoglalt terlet el rtunk egy byte-ot. Az EF PROTECT BELOW
vltoz 1-re lltsval azt krhetjk az Electric Fence-tt, hogy kapcsoljon t
az elrs vizsglatra. Termszetesen ilyenkor a tlrst nem tudja rzkel-
ni, mert a memrialapok adott mrete miatt nem vdhetjk mindkt oldalrl
a lefoglalt terletet:
574
B.2 .Memriak ezel sihib k
(gdb)setenv EF_P ROTECT_BELOW=1
(gdb)r
Startingprogram:/home/tomcat/bugos
[NewThread102 4(LWP 2 6868)]
ElectricFence2 .2 .0Copy right(C)1987-1999BruceP erens
1:12 3 45
3 :12 3 45678
P rogramreceiv edsignalSIGSEGV,Segmentation fault.
[SwitchingtoThread102 4(LwP 2 6868)]
0x08048658inmain()atbugos.c:3 2
3 2 (dinamik us-1)='\0';
(gdb)
B.2.2.4. Az Electric Fence tovbbi lehetsgei
Az eszkz hasznlatakor a B.3. tblzatban lthat kapcsolkkal tallkozha-
tunk mg:
B.3. tblzat. Az Electric Fence tovbbi kapcsoli
Vltoz Jelents
EF_PROTECT_FREE Ha rtke 1, akkor a felszabadtott memriaterletek
kiosztsa nem trtnik meg jra, hanem a rendszer
letiltja 'ket.
EF ALLOW MALLOC 0 Ha rtke 1, akkor engedlyezi a 0 mret terletek
alloklst.
EF FILL Amikor 0 s 2 55 kztt van az rtke, akkor a lefoglalt
terlet minden byte-jt feltlti a rendszer ezzel az rtk-
kel, gy segti az inicializcis problmk kiszrst.
B.2.2.5. Erforrsignyek
Az Electric Fence rendelkezik a malloc hibakeresk ltalnos problmjval, a
jelents memriaignnyel. Ha a tesztelt kdban sok kismret memriaallok-
ci van, akkor az Electric Fence hasznlatval tbb nagysgrenddel megnhet
a memriafelhasznls. Termszetesen a helyzet tovbb romlik, ha a felszaba-
dtott terleteket vdjk, mert ilyenkor valjban nem szabadul fel memria.
Ezrt, ha azt tapasztaljuk, hogy hasznlatakor a rendszernek nagyon meg-
fogyatkozik a szabadmemria-kapacitsa, akkor ajnlatos a lapcsere- (swap)
terletet megnvelni.
575
B fggelk: Hibakeress
B.2.3. DUMA
A DUMA malloc hibakeres az Electric Fence tovbbfejlesztse. C- s C++-
programok esetben egyarnt hasznlhat. Emellett nhny tovbbi funkci-
val egszti ki az eldjt:
Minden memriaallokcis fggvny implementcijt tartalmazza,
gymint malloc(), calloc(), memalign(), strdupQ, operator new, opera-
tor new[1, free(), operator delete s operator deletelj. Ezrt hasznlhat
C++-programokhoz is.
rzkeli, ha nem megfelel felszabadtfggvnyt hasznlunk az
adott foglalshoz.
Tartalmazza a memriaszivrgs rzkelst is.
B.3. Valgrind
A Valgrindn
6
egy keretrendszer-hibakeres analizleszkzk ksztshez.
A Valgrind eszkzei kzt tallunk olyanokat, amelyek lehetv teszik a memria-
vagy szlkezelsi hibk feldertst, illetve teljestmnyanalzisek futtatst.
A Valgrind eredetileg az eddig ltott memriakezelsi hibk kiszrshez
kszlt. Idvel azonban odig fejldtt, hogy egy ltalnos keretrendszer lett
belle. m a memriakezels ellenrzst vgz memcheck modul tovbbra is
a rsze s egyben az alaprtelmezett eszkze.
A Valgrind maga egy virtulis gp, amely futsidej (just-in-time, JII) for-
dtsi technikkat hasznl a programok ellenrzshez. A rendszer elszr
tfordtja a programot egy kztes kdra, amely az eredeti kd egy processzor-
fggetlen formja. Az eredeti kdbl semmi sem fut a hosztprocesszoron. A kz-
tes kdot a Valgrind mr igny szerint szabadon mdosthatja. A hasznlt
Valgrind modul kiegszti a kdot az ellenrzsekkel. Vgl az elkszlt kztes
kdot visszafordtja a rendszer a hosztprocesszor ltal futtathat formtumra.
A transzformcik s a beszrt ellenrzst vgz kdrszletek termsze-
tesen jelents teljestmnyromlst okoznak. A lassuls mrtke nagyban fgg
a hasznlt modul ltal beszrt kdoktl is. Pldul a memcheck modul eset-
ben egy memria-hozzfrs akr 10-50-szer lassabban fut, mint natv futta-
tskor. Ebbl lthatjuk, hogy ebben az esetben a fejleszti gpnek jelentsen
ersebb CPU-ra van szksge.
116
A Valgrind weboldaln: http:/ /valgrind.org/ tovbbi rszletes lersokat tallhatunk az
eszkzrl.
576
B.3. Valgrind
A Valgrind felptse modulris s knnyen bvthet. Akr sajt modu-
lokat is kszthetnk hozz. Tovbb a csomaggal szmos jl hasznlhat
modul is rkezik:
Memcheck: A C- s C++-programokban elkvetett memriakezelsi
hibkat derti fel.
Cachegrind: A gyorsttr-hasznlatot s az elgazsokat analizl
eszkz. A processzor Il, Dl s a L2 gyorsttrt szimullja. A prog-
ram analizlsakor meghatrozza a sikeres s a sikertelen gyorst-
tr-hozzfrseket s a feltteles elgazsok jslsnak a tvedseit.
A rszletes statisztikk alapjn optimalizlhatjuk a kdunkat
Callgrind: A fggvnyhivatkozsi grf segtsgvel analizlja a gyor-
sttr-hasznlatot. Funkcii tfedik a Cachegrindt, m tbbet is
nyjtanak annl.
Helgrind: A szlkezelsi hibk feldertst segt eszkz. A tbbszl
alkalmazsainkat ellenrizhetjk vele, hogy helyesen vgeztk-e el a
szinkronizlsokat.
DRD: Szintn szlkezelsi hibk feldertsre szolgl eszkz. Funk-
cionalitsban hasonlt a Helgrindre, m eltr technikkat hasznl.
Massif: Rszletes heapprofilt kpes kialaktani a rendszeres llapot-
mentseknek ksznheten. Segt cskkenteni a programunk mem-
riaignyt.
DHAT: Egy msik heaphasznlatot analizl eszkz.
A tovbbiakban a memcheck s a helgrind modulokat trgyaljuk rszletesebben.
B.3.1. Memcheck
Ahogy korbban emltettk, a memcheck a Valgrind els s az egyik legfonto-
sabb eszkze. Ha nem adjuk meg, melyik eszkzt vlasztjuk, akkor ez az alap-
rtelmezett.
A memcheck feladata a memriakezelsi hibk kiszrse. A hibk szle-
sebb skljt kpes kimutatni, mint egy malloc hibakeres, s a CPU haszn-
lata is intenzvebb. A kvetkez hibkat vizsglhatjuk vele:
A malloc hibakeresknl ltott heapallokci tlrsa, elrs, felsza-
badtott terlet rsa. Veremterlet tlrsa.
Inicializlatlan vltozk rtkeinek a hasznlata.
Hibs felszabadtsok. Dupla felszabadts vagy a nem megfelel fog-
lal-felszabadt fggvnyprok hasznlata.
577
B fggelk: Hibakeress
A memcpy0 fggvny hasznlata sorn a forrs- s a clbufferek tla-
poldsa.
Memriaszivrgs.
tmutat Arra figyeljnk, hogy a memcheck eszkz sem kpes kimutatni a tlrsokat/elrso-
kat statikusan vagy a veremben alloklt vltozk esetben. A problmra megoldst az SGCheck
modul prbl nyjtani, m ez az eszkz jelenleg csak ksrleti llapotban van.
Az eszkzt a kvetkezkppen hasznlhatjuk:
gcc -ggdb -wall bugos bugos.
valgrind ,-tool~antebeck bugos
A Valgrind parancs --tool=memcheck kapcsoljval vlaszthatjuk ki a hasz-
nlni kvnt memcheck eszkzt. Ezutn mr csak a binris nevt kell megad-
nunk, s a Valgrind elkezdi az ellenrzst.
A standard kimenetre kldtt jelents tartalmazza a felfedezett hibkat.
A vgn tallhat sszegzsben pedig a lthatjuk a knyvelsbl kimutatott
memriaszivrgsokat.
Szmos opcival befolysolhatjuk a modul mkdst, a vizsglatok s a ri-
port rszletessgt. Clszer ezeket tanulmnyozni, hogy a kvnt eredmnyt
rjk el.
B.3.1.1. A memcheck modul mkdse
A memcheck modul mkdst gy a legegyszerbb elkpzelnnk, mintha az
egy virtulis processzor lenne, amely br mindazt vgrehajtja, amit a vals
processzor, de emellett tovbbi memriakezelssel kapcsolatos informcikat
knyvel s ellenriz. Ezekbl a plusz informcikbl mondja meg, hogy hibz-
tunk-e valahol. Nzzk, hogyan trtnik mindez.
Az adatterlet minden egyes bitjhez, belertve a processzorregisztereket
is, egy V bit (valid-Value) trsul, amely jelzi, hogy az adott adatbit rvnyes
vagy rvnytelen rtket tartalmaz-e. Ez a V bit egytt mozog az adatbittel.
Amikor a virtulis processzor az adatbyte-ot beolvassa a regiszterbe, akkor a
V biteket trol byte is az adattal tart. Ha a processzor mveleteket vgez az
adattal, akkor a V bitek rtknek kiszmtsa is megtrtnik. s vgl a
memriba rsnl a V bitek is visszardnak. Vagyis ezek a bitek mindig tar-
talmazzk azt, hogy a hozzjuk tartoz adatbit rvnyes adatot tartalmaz-e,
vagy sem.
gy vlhetnnk, hogy ettl kezdve a memcheck modulnak mr csak az a
feladata, hogy mindig ellenrizze ezt a V bitet, s ha rvnytelen adatot olva-
sunk be a virtulis processzorunkba, akkor mindig rjon ki figyelmeztetseket.
Ezzel csak az a baj, hogy idnknt a C-programok teljesen jogosan msolgat-
nak inicializlatlan adatokat. Nzzk meg a kvetkez pldt:
578
B.3 .Valgrind
structs
{
charel;
chare2 ;
} ;
struct s sl ={'
struct s s2 ;
s2 =sl;
' b'} ;
Ltrehozzuk az s nev struktrnkat, amely 2 byte helyigny. Ebbl a
struktrbl ltrehozzuk az s/ s az s2 vltozkat, s sl-et inicializljuk. Azt
gondolnnk, hogy ezek kt byte mret adatblokkok, de tvednk. A C-ford-
tk gy optimalizljk a kdunkat, hogy valjban a processzor sz mretre
kerektik fel, hogy gyorsabban fut kdot kapjunk. Ezrt 4 byte-os szmret-
tel szmolva az s/ kt inicializlatlan byte-ot is tartalmaz. Amikor az s/ rt-
kt tmsoljuk s2 -be, akkor az inicializlatlan rtkeket is msoljuk. s ez
egy teljesen szablyos mvelet, amelyrl nem szeretnnk hibajelentst kapni.
A megoldst az jelenti, hogy nem minden mveletnl valsul meg a V bit
ellenrzse, csak a kvetkez esetekben:
ha az adatbl memriacmet szmolunk ki, amelyre hivatkozunk;
ha az adatot elgazshoz hasznljuk fel;
rendszerhvsoknl.
Ha az ellenrzsek sorn kiderl, hogy olyan adatot hasznlunk fel, amely
rvnytelen biteket is tartalmaz, akkor ez egy hibajelentst eredmnyez.
Mr csak az a problma, hogy az rvnytelen adatot vagy az abbl szr-
maztatott adatokat mshol is hasznlhatjuk, s ez ugyanarrl a hibrl egy
hibajelentsi lavint indthat el. Ezrt a hibajelents utn az adott biteket
rvnyesnek jelli a rendszer.
A V bitek mellett minden egyes adatbyte-hoz tartozik egy A bit (valid-
Address) is, amely a cm rvnessgt jelzi. Az A bit jelzi, hogy az adott byte-
hoz jogosultak vagyunk-e hozzfrni. Minden alkalommal, amikor egy memria
cmet olvas, vagy r a program, akkor a memcheck modul leellenrzi a hozz-
tartoz A bitet, hogy jogosultak vagyunk-e a mveletre. Ha azt tallja, hogy
nem, akkor hibajelzst ad ki. Ezzel prhuzamosan a V bitet rvnyesadat-
llapotba lltja. Ez a lps furcsa lehet, de ha nem lenne gy, akkor az illeglis
memria-hozzfrsek kapcsn rengeteg inicializlatlan adatrl szl hibajel-
zst is kapnnk.
Az A bitek llapotai a kvetkez esetekben mdosulnak:
A program indulsakor a globlis adatterlet engedlyezett vlik.
Amikor terleteket alloklunk, akkor a lefoglalt byte-ok engedlyezet-
tek lesznek. (Csak a lefoglalt byte-ok, teht a szillesztsnek erre
nincs hatsa.)
579
B fggelk: Hibakeress
Amikor a veremmutatt lltja a rendszer, akkor gy mdostja a
memcheck az A bit rtkt, hogy a veremmutat feletti rsz enged-
lyezett lesz, az alatta lv rsz pedig tiltott.
Bizonyos rendszerhvsok, pldul az mmap(), mdosthatjk a me-
mriaterletek elrhetsgt. A memcheck az A biteket is ennek meg-
felelen lltja be ilyenkor.
A felsoroltakon kvl a program explicit mdon is krheti egyes adatterletek
hozzfrsi engedlynek a mdostst, de erre ritkn van szksg.
sszegezve: minden adatbyte-hoz tartozik 8 V bit s 1 A bit.
117
Amikor
egy memriacmhez hozzfrnk, akkor az A bit rtkt ellenrzi a rendszer.
Az adatmveletek sorn a V bitek rtke frissl. Egyes mveleteknl a V bit
rtkt is leellenrzi a rendszer, s szksg esetn hibt jelez. A hibajelzsek
sorn a ksbbi felesleges jelzsek elkerlse rdekben a V bit rtkt mdo-
stja a rendszer.
A memcheck a memriakezel fggvnyeket kiegszti az ellenrz bitek
kezelsvel az albbiak szerint (B.4. tblzat):
B.4. tblzat. Az ellenrz bitek kezelse
malloc, new rvnyes rvnytelen
calloc rvnyes rvnyes
realloc Ha az j foglals kisebb, akkor Ha az j foglals nagyobb, akkor
a klnbsg rvnytelen lesz. a klnbsg rvnytelen lesz.
free, delete rvnytelen rvnytelen
B.3.2. Helgrind
A Helgrind a Valgrind rendszer szlhibk detektlshoz kifejlesztett eszkze.
Azon tbbszl programoknl hasznlhat, amelyek a POSIX pthread fejleszti
knyvtrral kszltek. A modul a kvetkez hibatpusokat kpes rzkelni:
a POSIX pthread API hibs hasznlata;
a zrolsi sorrend problmibl add holtpontveszlyes helyzetek;
versenyhelyzet, amikor kzs adatterletekhez a megfelel zrolsok,
szinkronizlsok nlkl frnk hozz.
117
Valjban a kisebb helyhasznlat rdekben a memcheck modul tmrti a V bitek tro-
lst, gy nem lesz duplja a memriaigny.
580
B.3. Valgrind
A felsorolt hibatpusok gyakran eredmnyeznek vletlenszeren jelentkez
szinte reproduklhatatlan problmkat. Ezrt a fejlesztknek trekednie kell
ezeknek a hibknak a kikszblsre.
A helgrind modult a memcheck modulhoz hasonlan hasznlhatjuk:
valgrind --tool=helgrind fajlnev
A program futsa sorn folyamatosan produklja a jelentseket a tallt hi-
bkrl.
tmutat A szlkezelsi hibk detektlsa mg a memriakezelsi hibknl is nehezebb.
Ebbl fakadan a helgrind modul sok tves riasztst is ad. Ha a fejlesztend programunkat
tesztelni akarjuk vele, clszer mr a fejlesztsi fzisban bizonyos irnyelveket kvetnnk,
hogy minimalizljuk a tvedseket.
Ahhoz, hogy a helgrind modult eredmnyesen hasznlhassuk, az albbi sza-
blyokat kell kvetnnk:
Szlkezelsre csak a POSIX-fggvnyeket hasznljuk. Ha sajt mecha-
nizmusokat implementlunk a pthread fggvnyek megkerlsvel,
akkor a helgrind nem ltja megfelelen az esemnyeket. Sajnos a Qt
4 .x verzija sajt szlkezelst alkalmaz, m a KDE-programok miatt a
helgrind tartalmaz egy ksrleti llapot tmogatst erre az esetre.
Kerljk a lefoglalt terletek jrahasznostst. Ha pldul egy vl-
tozt az egyik szlbl hasznltunk, majd egy ponttl mr egy msik
szl kezeli, akkor lehet, hogy nem kell szinkronizlnunk a vltoz
hasznlatt, de a helgrind ezt nem tudhatja.
Lehetleg kerljk a feltteles vltozk hasznlatt. A helgrind csak
akkor kezeli helyesen, ha a vrakozs megelzi a jelzs kldst.
A helgrind a glibc 2 .3-as vagy jabb verzijnak hasznlatt ignyli a
helyes mkdshez.
Minden szl befejezdst vrjuk meg a pthreadjoin0 fggvnnyel,
s kerljk a lekapcsolt (detached) szlak hasznlatt, mert a hel-
grind csak gy tudja rzkelni a szl vgt.
A helgrind hasznlata eltt memcheckkel ellenrizzk a programot,
mert a memriakezelsi hibk rossz hatssal lehetnek a helgrind-re.
A printf(), az fprintf(), az fwrite(), az freadO fggvnyek tves verseny-
helyzet-jelzseket eredmnyezhetnek.
581
B fggelk: Hibakeress
B.4. Rendszerhvsok monitorozsa: strace
Az strace hasznos diagnosztikai, hibakeres eszkz. ltalnossgban az strace
lefuttatja a paramterknt megadott programot, s monitorozza a folyamat
rendszerhvsait s azokat a jelzseket, amelyeket kap. Az sszes rendszerh-
vst a paramtereivel egytt a szabvnyos hibakimenetre vagy a megadott
kimeneti llomnyba rja. A fejleszti knyvtrak, hibakeres knyvtrak
mkdsnek vizsglathoz, megismershez is hasznlhat.
B.5. Knyvtrfggvnyhvsok
monitorozsa: ltrace
Az ltrace program az strace programhoz hasonl feladatot lt el azzal a klnb-
sggel, hogy a megosztott knyvtrak fggvnyeinek hasznlatt monitorozza.
Emellett kirja a rendszerhvsokat s a folyamat ltal kapott jelzseket is.
Az ltrace program is paramterknt vrja a futtatand program nevt, s
a futs ideje alatt kirja az rzkelt hvsokat a szabvnyos hibakimenetre.
B.6. Tovbbi hasznos segdeszkzk
A splint segdprogram a hibakeressben lehet segtsgnkre. Megkeresi a
veszlyes, nem ajnlott megoldsokat a program forrskdjban. A program
rsa kzben gyakran kvetnk el olyan szinte szrevehetetlen kis hibkat,
amelyek ksbb a hibakeress sorn slyos fejtrst okozhatnak. Ilyen a nem
inicializlt vltozk hasznlata, a tmbk tlindexelse, rtkads az egyen-
lsg vizsglata helyett stb.
Az splint az ilyen hibk elkerlsben segt. A C/C++-forrsllomnyokat
dolgozza fel s rtelmezi gy, mint egy fordt. Tbb szempontbl vizsglja
azonban a kd helyessgt, s keresi a tipikus programozi hibkat, a gyans
rszeket.
Hasznlata a kvetkez:
splintprogram.c
Az splint szolgltatsai kztt megemltjk a tpusellenrzst, a paramter-
tadst, a lehetsges memriahibk feldertst.
582
B.6. Tovbbi hasznos segdeszkzk
Az indent segdprogram olvashatv teszi a C-forrskdot szkz, tabu-
ltor s hasonl jelleg karakterek beiktatsval. Segtsgvel tkonvertl-
hatjuk a forrskdot az egyik programozsi stlusbl egy msikba is.
Hasznlata a kvetkez:
ndent fa j 1 c
A fejleszti krnyezetek gyakran beptve is tartalmazzk az indent funkciona-
litst, gy mr szerkeszts kzben is rendezik a kdunkat.
Binris fjlok analzisnl jl jhet, ha hexadecimlisan is meg tudunk jelen-
teni egy fjlt. Ezt a hexdump segdprogrammal tehetjk meg. A paramterknt
megadott llomnyt a kvnt formtumban jelenti meg. Oktlis, decimlis, he-
xadecimlis, karakteres rtk kirsa kzl vlaszthatunk, de tovbbi paramte-
rekkel ennl pontosabban is megadhatjuk a kvnt kimenetet.
Leggyakrabban azonban paramterek nlkl a kvetkezkppen hasznljuk:
fa0
583
T rgymutat
A,
ablakkezel, 4 4 0, 4 4 1
acceptO, 2 69, 2 70, 2 71, 2 99, 308, 311,
4 63, 4 74
access_ok0, 369
adatfolyam, 104 , 14 9, 151, 2 72 , 2 78, 4 4 0,
519
adatmegoszts, 165
Address Resolution Protocol, 2 83
AF_INET, 2 91, 2 92 , 2 95-2 98, 301, 305,
310, 313, 318, 32 4 , 32 5
AF_INET6, 2 91, 2 92 , 2 95-2 98, 305, 310,
313, 318, 32 4 , 32 5
AF_UNIX, 2 76, 2 77, 2 79, 2 81
AF_UNSPEC, 2 95, 2 97, 300, 307, 316,
32 0, 32 8, 32 9
AI_ADDRCONFIG, 2 96, 2 97
AI_ALL, 2 96
AI_CANONNAME, 2 96
AINUMERICHOST, 2 96
AI_NUMERICSERV, 2 96
Al_PASSIVE, 2 96, 305, 306, 318, 32 4
ALV4 MAPPED, 2 96, 2 97
akci, 4 69, 4 72 , 4 75, 4 76
alacsony szint llomnykezels, 95, 14 9
alkalmazs, 37, 14 0, 2 4 1, 2 72 , 2 75, 308,
315, 334 , 353, 357, 361, 382 , 395,
4 04 , 4 06, 4 4 4 , 4 4 6, 4 4 8, 4 56, 4 60,
4 67-4 72 , 4 76, 4 80, 4 81, 4 84 , 4 89-4 92 ,
508, 509, 510, 511, 518, 52 3, 52 5,
530, 562
alkalmazskomponens, 4 91, 509
llomnyler, 4 4 , 96, 106, 107, 12 9, 130,
133, 134 , 136, 139, 191, 197, 2 39,
2 60, 2 65, 372
llomnyzrols, 14 3
ARP Cache, 2 83
aszinkron 1/0, 37
aszinkron jelzskezels, 2 50
asztali krnyezetek, 4 4 1
thelyezsnek, 81
atomi mveletek, 387, 389
ATOMIC_INITO, 388
atomict, 2 56, 2 58, 388, 389
automatikus vltozk, 54 5, 54 8, 54 9
azonostk, 19, 110, 186, 199, 2 00, 2 02 ,
354
B
bash, 2 0, 93, 379, 562
batch, 2 4
bepl modulok, 4 7, 64 , 68
big endian, 2 90
bindO, 2 68, 2 69, 2 72 , 2 73, 2 75, 2 78, 2 80,
2 90, 2 96, 32 7
binding, 2 68
block device file, 38
blokkolt 1/0, 12 6, 12 7, 12 8
Bottom half, 2 6, 4 14
breakpoint, 559, 562
bss, 81, 82 , 86
buffer overrun, 557, 569
C
call_usermodehelperO, 4 2 1
catchpoint, 562 , 564
CDE, 4 4 1
character device file, 38
ciklikus zrols, 366, 377, 378, 389-394
cmtartomny kezelse, 83
cmtartomny-randomizls, 92
class_createO, 355, 356
class_destroyO, 356
cleanup_moduleO, 34 4
closeO, 99, 14 1, 2 65, 2 70, 2 71, 2 75, 361,
4 73, 4 93, 507, 518
CMake, 555, 556
compat_ioctl, 367
compile, 538
Completely Fair Scheduler, 2 4
CONFIG_DEBUG_DRIVER, 378
Trgymutat
CONFIG_DEBUG_INFO, 378
CONFIG_DEBUG_KERNEL, 377
CONFIG_DEBUG_PAGEALLOC, 378
CONFIG_DEBUG_SLAB, 377
CONFIG_DEBUG_SPINLOCK, 377, 378
CONFIG_DEBUG_SPINLOCK_SLEEP,
378
CONFIG_DEBUG_STACK_USAGE, 378
CONFIG_DEBUG_STACKOVERFLOW,
378
CONFIG_IKCONFIG, 378
CONFIG_IKCONFIG_PROC, 378
CONFIG_KALLSYMS, 378
CONFIG_KALLSYSMS, 378
CONFIG_MAGIC_SYSRQ, 377
CONFIG_PROFILING, 378
configure, 555
configure.ac, 555
connectO, 2 69, 2 74 , 2 75, 2 90, 2 96
copy on write, 34
copy_from_user(), 387
copy_to_user(), 361
core, 4 3, 159, 2 4 0, 2 4 1, 382 , 562
counter, 2 3, 2 31, 2 32 , 4 00, 4 01, 4 04 , 4 16,
4 19, 4 2 0
cpu_relax(), 4 2 4
crashdump, 381
ctors, 82
Cs
csoportazonost, 15, 18, 109, 160, 199,
2 01
csoportvezet, 191
csvezetk, 36, 4 0, 4 3, 97, 114 , 12 0-12 5,
12 7, 12 8, 198, 2 75
D
data, 4 1, 81, 179, 182 -184 , 2 2 3, 2 2 4 , 2 2 5,
2 2 6, 2 87, 2 89, 362 , 363, 4 05, 4 06,
4 2 1, 4 2 5, 4 2 8, 4 2 9, 4 33, 4 34 , 4 54 ,
501-503, 507, 508, 52 5
datagram, 2 66, 2 72 , 2 75, 2 80, 318
DDD, 566, 567
debug, 2 1, 537, 54 0, 54 9
demand paging, 32
dmonok, 189, 193, 197
depmod, 34 8
deserializing, 333
Desktop Environment, 4 4 1, 535
devfs, 355
device drivers, 39
device file, 38
device_create(), 355
device_destroy(), 356
dinamikus linker, 61, 66, 67, 83-91, 93
dinamikus programbetlt, 68
dinamikus szimblumtblzat, 86, 87
dinamikusan betlttt programknyvtr,
67, 68, 72
dinamikusan linkelt megosztott prog-
ramknyvtr, 68
dirty page, 32
dokumentum/nzet, 4 89, 4 90, 4 94 , 504 ,
509, 530
dtors, 82
dup(), 2 71
E,
EADDRINUSE, 2 75
EAGAIN, 12 7, 12 8, 133, 14 6, 173, 176,
2 34 , 302 , 303, 398, 4 02 , 4 06
Eclipse, 556, 567
effektv csoportazonost, 199
effektv felhasznli azonost, 199
egyszer kirtkels, 54 6
Electric Fence, 572 -576
eljrslinkelsi tblzat, 85
eljrsvezrelt, 4 51
eltrbeli processzcsoport, 192 , 193
elrendezsnek, 2 39, 2 57, 2 58, 4 64
elrendezskezel, 4 4 5, 4 59, 4 61, 4 62 , 4 64 ,
4 65, 4 87, 4 94 , 4 99, 504 , 514 , 515, 52 8
eltols, 2 8, 2 9, 31, 304 , 379, 4 05
lvezrelt, 133
Emacs, 533
EPIPE, 303
epoch, 2 3
epollO, 311, 315
errno, 96, 97, 99, 102 , 103, 119, 12 0, 12 3,
12 4 , 12 7, 12 8, 130, 136, 14 1, 14 2 ,
14 4 , 14 6, 14 9, 157, 173, 176, 2 14 ,
2 4 8, 2 62 , 303, 304 , 361
esemnyvezrelt programozs, 4 50, 4 51
everything is a file, 36
execO, 309, 4 4 4 , 4 65, 4 66, 4 74 , 4 79, 4 82 ,
4 89, 511, 513, 515, 52 5, 52 9
EXPORT_SYMBOLO, 34 9, 350
EXPORT_SYMBOL_GPLO, 350
EXPORT_SYMTAB, 34 9
eXternal Data Representation, 333
586
Trgymutat
F
fjlrendszer, 19, 99, 109
fenti, 14 5, 14 6, 2 69
feladatnak, 191, 534
feladatok, 15, 104 , 2 68, 4 14
feladatvezrls, 191, 192
felhasznli azonost, 198-2 00, 2 53
felhasznli azonostba, 199
felhasznli cmtartomny, 11, 2 4 7, 34 2 ,
362 , 372 , 375, 385, 4 05, 4 2 1
felhasznli csoportazonostnak, 198
feltteles rtkads, 54 6
feltteles vltozkat, 2 2 8, 2 2 9
file_operations, 354 , 356, 357, 360, 361,
362 , 364 , 365, 366, 370, 399, 4 01,
4 04 , 4 07
fini, 82
first in, first out, 4 0
fizikai cm, 2 8, 2 9, 31, 35, 36, 2 83, 2 84 ,
384 , 385, 4 05, 4 09
fizikai nv, 57
flockO, 14 5
folyamatkezel, 13
forkO, 12 1, 157, 158, 159, 161, 194 , 2 71,
308
fazonost, 114 , 354 , 355
freeaddrinfoO, 2 95
FSF, 2 , 3, 4 , 533
Fully Qualified Domain Name, 2 99
futsidej dinamikus linker, 83
futex, 2 2 1
fggben lv, 2 4 5, 2 4 6, 2 4 7, 2 54 , 2 69
G
g++, 70, 71, 2 10, 4 58, 536
gai_strerrorO, 2 95, 2 99
gcc, 4 5, 4 8, 4 9, 51, 54 , 55, 58, 59, 60, 62 ,
63, 67, 82 , 89, 91, 169, 2 05, 2 10, 2 17,
357, 536-54 4 , 54 9-551, 554 , 558, 569,
572 , 578
gdb, 79, 378, 379, 380, 382 , 383, 537,
557-563, 567, 570, 573-575
gdbserver, 562 , 567
getaddrinfoO, 2 94 , 2 95, 2 98, 306, 308
getnameinfoO, 2 98, 2 99
getsockoptO, 32 6
getty, 14 , 190
GFP_ATOMIC, 385, 387, 4 12
GFP_KERNEL, 358, 385
GFP_NOFS, 385
GFP_NOIO, 385
GFP_USER, 385
globlis eltolstblzat, 84
GNAT, 536
GNOME, 4 4 1, 535, 556
GNU, 3, 4 , 6, 8, 9, 533, 536, 54 0, 54 1,
555, 556, 558, 566, 573
GNU Autotools, 555
GNU Compiler Collection, 4 , 536, 54 0
GNU debugger, 556
GNU make, 54 1, 555
GPL, 3, 4 , 5, 34 4 , 34 5, 34 9, 350, 352 , 361,
372 , 374 , 4 00, 4 02 , 4 17, 4 2 0, 4 2 3,
4 37, 558
grafikus felhasznli fellet, 2 , 315, 330,
4 39, 4 4 2 , 4 4 3, 4 50, 4 59, 52 2 , 52 5, 530
Gy
gyermekfolyamat, 157, 161, 162 , 2 62
gyermekprocessz, 108, 12 2 , 157-160, 193,
198, 2 63, 308
H
hagyomnyos jelzseknek, 2 4 3
hard link, 4 2 , 114
httrbeli processzcsoport, 192 , 193
Helgrind, 577, 580
helyettest hivatkozs, 54 7, 54 8
hibaellenrz mutex, 2 2 1
hotplug, 355
htonlO, 2 94
I/O buffer, 103
I/O multiplexels, 12 8
I/O temez, 104
igny szerinti lapozs, 31, 32 , 139
in_addr, 2 91, 2 92 , 2 93, 32 3
in6_addr, 2 91, 2 93, 2 94 , 32 3
IN6ADD_ANY _INIT, 2 96
in6addr_any, 2 93, 310, 313
IN6ADDR_ANY _INIT, 2 93, 2 96, 306
in6addr_loopback, 2 94
IN6ADDR_LOOPBACK_INIT, 2 93, 2 96
INADDR_ANY, 2 93, 2 94 , 2 96
INADDR_LOOBACK, 2 93
INADDR_LOOPBACK, 2 93, 2 94 , 2 96
in-core inode, 4 3
indent, 583
inet_atonO, 2 91, 2 92
587
Trgymutat
inet_ntoa(), 2 91, 2 92
inet_ntopO, 2 92
inet_ptonO, 2 92 , 2 95
information node, 4 1
Mit, 14 , 15, 2 0, 82 , 157, 161, 190, 193,
2 10, 2 11, 2 15, 2 2 2 , 2 2 4 , 2 2 9, 2 33,
2 36, 2 37, 2 4 1, 2 4 6, 2 51, 2 52 , 34 4 ,
34 5, 34 9, 350, 352 , 356, 360, 361,
371-374 , 381, 390-396, 399, 4 00, 4 02 ,
4 16, 4 17, 4 2 0-4 2 5, 4 33, 4 34 , 4 37
init_module(), 34 4
inode, 4 1, 4 2 , 4 3, 104 , 105, 108-112 , 114 -
117, 119, 359, 360, 364 , 365, 399,
4 01
insmod, 34 7, 351, 353, 362
Integrated Development Environment,
533, 556
Interprocess Communication, 13, 165
interruptible_sleep_onO, 396
ioctl, 37, 366, 367, 368, 369, 377
IP_ADD_MEMBERSHIP, 32 2 , 32 5
IP_DROP_MEMBERSHIP, 32 2
IP_MULTICAST_IF, 32 2
IP_MULTICAST_LOOP, 32 1, 32 2
IP_MULTICAST_TTL, 32 2 , 32 3
ipcs, 165, 166, 169, 187
IPPOROTO _IGMP, 2 67
IPPROTO _ICMP, 2 67
IPPROTO _IP, 32 1, 32 2 , 32 3, 32 5, 32 6
IPPROTO JP6, 32 6
IPPROTO_IPV6, 32 1, 32 5
IPPROTO_RAW, 2 67
IPPROTO_TCP, 2 67, 32 6
IPPROTO_UDP, 2 67, 32 6, 32 8
IPv4 , 12 , 2 66, 2 67, 2 82 , 2 83, 2 85-2 96,
2 98, 300, 32 1, 32 3, 32 5, 32 6
IPv6, 12 , 2 66, 2 82 , 2 88-2 96, 304 , 32 1,
32 2 , 32 3, 32 5, 32 6
IPV6_JOIN_GROUP, 32 2 , 32 5
IPV6_LEAVE_GROUP, 32 2
IPV6_MULTICAST_HOPS, 32 2
IPV6_MULTICAST_IF, 32 2
IPV6_MULTICAST_LOOP, 32 2
rsi zrols, 14 5, 14 6, 394
IRQ_HANDLED, 4 11
IRQ_NONE, 4 11, 4 12 , 4 16, 4 17, 4 19
IRQF_DISABLED, 4 11
IRQF_SAMPLE_RANDOM, 4 11
IRQF_SHARED, 4 11, 4 12 , 4 16, 4 2 0
IRQF_TIMER, 4 11
J
jelzs, 16, 17, 18, 103, 156, 159-161, 193,
195, 2 2 8-2 30, 2 34 , 2 38-2 51, 2 53-2 62 ,
303, 360, 391, 396, 399, 4 00, 4 02 ,
4 52 , 560, 581
jelzs generlsnak, 2 4 5
jelzs kzbestse, 2 4 5
jelzsklds, 192 , 2 39, 2 4 5, 2 50
jelzsmaszk, 134 , 2 4 5, 2 50, 2 54 , 2 55, 2 58
jiffy, 2 6, 392 , 4 2 3, 4 2 4
joe, 534
K
kanonikus feldolgozs, 151, 154
karaktertpus eszkzvezrl, 353
KDE, 4 4 1, 4 4 3, 535, 556, 581
KDevelop, 556
KERN_ALERT, 376
KERN_CRIT, 376
KERN_DEBUG, 375, 376
KERN_EMERG, 376
KERN_ERR, 375
KERN_INFO, 375
KERN_NOTICE, 375
KERN_WARNING, 375, 4 16, 4 2 0
kernel cmtartomny, 34 3, 362 , 367, 4 2 1
Kernel Hacking, 377
kfree0, 362 , 385
kisfeladat, 2 6, 4 13, 4 14 , 4 15, 4 17, 4 18,
4 2 0
kizrlagos zrols, 14 5
kmallocO, 362 , 384 , 385, 386, 387, 4 12
klcsns kizrs, 14 4 , 166, 2 2 1, 362 ,
387, 392
knny sly processzek, 2 02
ktelez zrols, 14 3, 14 8, 14 9
kts, 2 68, 2 93
kzps lapknyvtr, 31
L
lapazonost, 2 8, 2 9
lapcserellomny, 33, 35
laphiba, 78
lapknyvtr, 2 9, 30, 31
laptr, 103, 104 , 139
Latency tracer, 2 6
ld, 59, 62 , 63, 68, 74 , 87, 178, 538
Least Recently Used, 33
lecsatolt, 2 07, 2 11, 2 18
588
Trgymutat
lefoglalhat, 79
Libtool, 555
link count, 4 3
linkernv, 62
listenO, 2 69
little endian, 2 90, 4 05
llseek, 37
login, 14 , 190, 199, 2 02
loklis hlzat, 2 82 , 2 83, 2 84
lokalizci, 4 79, 4 80, 4 81
loopback, 2 85
lsmod, 34 7
ltrace, 582
Ly
lyukak, 101, 110
M
magas szint llomnykezels, 95, 14 9
Magic SysRq, 377, 381
make, 338, 34 6, 4 4 6, 4 4 7, 4 4 8, 4 57, 54 1,
54 2 , 54 3, 54 4 , 54 9, 551, 552 , 553, 554
Makefile, 34 1, 34 6, 362 , 54 1, 54 2 , 54 3,
54 5, 54 7, 552 , 553, 554 , 555
Makefile.am, 555
Makefile.in, 555
msols rskor, 34 , 78, 79, 83, 164
Massif, 577
mc, 534
megnevezett csvezetkek, 4 0, 103, 113,
12 3, 2 75
megnevezett szemafor, 2 33, 2 35, 2 38
megosztott memria, 16, 34 , 37, 14 0, 185,
186, 187, 2 2 1, 2 33, 2 38
megosztott programknyvtr, 56, 59, 61,
62 , 64 , 68, 70, 72 , 83, 84 , 86, 90
megosztott zrols, 14 5, 393
mellkazonost, 114 , 354 , 362 , 363, 366
Memcheck, 577
Memriainformcik, 16, 381
memory leak, 557, 569
Memory Management Unit, 2 8
merev hivatkozs, 4 2 , 4 3, 111, 114 , 115,
116
minimum granularity, 2 4
minor number, 354 , 363
MINORO, 364
MKDEVO, 355
mknod, 113, 114 , 12 3, 354
mmapO, 139, 14 0, 14 1, 14 2 , 4 04 , 580
moc, 4 4 8, 4 58, 4 59, 555
modlis dialgusablak, 4 60, 4 72
modinfo, 352
modprobe, 34 7, 34 8, 34 9, 353
modprobe.conf, 34 8, 353
mdszertanok, 4 4 1
module_exitO, 34 5
module_initO, 34 5
module_paramO, 351
modulok, 2 56, 34 0, 34 1, 34 6, 34 7, 34 8,
350, 351, 357, 370, 377, 382 , 4 4 2
MSG_DONTROUTE, 302
MSG_DONTWAIT, 302 , 303
MSG_MORE, 302 , 32 9, 330
MSG_NOSIGNAL, 303
MSG_OOB, 303
MSG_PEEK, 303
MSG_WAITALL, 303
munkamenet, 192 , 193, 194 , 195
munkasor, 2 6, 4 17, 4 18, 4 2 1
309,
516
N
nano, 4 2 3, 534
nem blokkold, 12 7-12 9, 131, 136, 155,
2 38, 2 69
nem lefoglalhat, 79
nem modlis dialgusablak, 4 60, 4 66
netstat, 2 81, 330
network byte order, 2 90
nvtelen csvezetk, 4 0, 4 3, 12 1, 12 2 ,
198, 2 80
nvtelen szemafor, 2 33, 2 34
NI_DGRAM, 2 99
NI_NAMEREQD, 2 99, 301
NI_NOFQDN, 2 99
NI_NUMERICHOST, 2 99, 300, 316
NI_NUMERICSERV, 2 99
nice, 2 2 , 2 4
o,
olvassi zrols, 14 5, 14 6, 394
on-disk inode, 4 3, 109, 117
Oops, 34 2 , 355, 378, 379, 380, 381
openO, 97, 98, 113, 14 0, 14 4 , 2 66, 2 75,
361, 4 91, 4 92 , 506, 507, 517
out-of-band data, 303, 4 03
mutex, 166, 2 2 1-2 2 6,
310, 311, 392 , 393,
2 2 8-2 33, 2 36,
4 33, 4 34 , 4 4 9,
589
Trgymutat
P
page, 9, 2 8, 2 9, 31, 32 , 103, 386, 4 06
page directory, 2 9
page fault, 32
Page Frame Number, 2 8, 4 05
page middle directory, 31
PAGE_SHIFT, 4 05, 4 06
pending connection, 2 69
perifriakezel, 13
PF_APPLETALK, 2 66
PF_ATMPVC, 2 66
PF_AX2 5, 2 66
PF_INET, 2 66, 2 67, 310, 313
PF_INET6, 2 66, 310, 313
PF_IPX, 2 66
PF_NETLINK, 2 66
PF_PACKET, 2 66
PF_UNIX, PF_LOCAL, 2 66
PF_X2 5, 2 66
pgid, 18, 191
pid, 18, 2 0, 12 1, 12 2 , 14 4 , 14 6, 14 7, 157-
162 , 190, 191, 192 , 194 , 2 51, 2 61,
379, 562
pipe, 4 0, 113, 12 0, 12 1, 12 5, 12 6, 12 8,
133, 138
pkg-config, 555
po110, 134 , 136, 137, 2 69, 311, 314 , 315,
4 03
poll_table, 4 03, 4 04
poll_waitO, 4 03
POLLERR, 135-137, 314 , 4 03
POLLHUP, 135, 136, 138, 314 , 4 03
POLLIN, 135-138, 312 , 314 , 4 03, 4 04
POLLOUT, 135, 136, 4 03
POLLPRI, 135, 4 03
POLLRDBAND, 4 03
POLLRDNORM, 4 03, 4 04
POLLWRBAND, 135, 4 03
POLLWRNORM, 4 03
portmap, 2 89, 333, 334
pozcifggetlen futtathat llomny, 84
pozcifggetlen kd, 58, 84 , 85, 86
pozicionlhat llomnyok, 100
ppid, 2 0
preprocessor, 54 0
printkO, 34 5, 359, 375, 381
privt lekpezsnek, 79, 14 1
process group ID, 18
process ID, 18
process pool, 309
processzcsoport, 18, 191, 192 , 193, 2 51
processzek kztti kommunikci, 13,
165, 2 39
programbetlt, 59, 79, 80, 82
pstree, 15
pthread, 2 03, 2 04 , 2 06-2 2 0, 2 2 2 -2 2 6, 2 2 9-
2 32 , 2 36, 2 37, 2 50, 2 52 , 2 54 , 309,
310, 311, 580, 581
Q
qmake, 4 4 6, 4 4 7, 4 4 8, 4 57, 4 58, 555
Qt Creator, 556
R
ragozsi szably, 551-553
readO, 2 2 , 99, 12 7, 12 8, 151, 154 , 2 65,
2 70, 2 73, 2 74 , 302 , 303, 361
readdirO, 119, 12 0
real time priority, 2 2
real-time, 2 2 , 2 4 3
recv0, 2 73, 303, 306, 315
recvfromO, 2 73, 2 74 , 2 99
rekordzrols, 14 3, 14 5, 14 6, 2 02
Remote Procedure Call, 2 65, 331
rszleges olvass, 102
round-robin, 2 3, 2 11
router, 2 , 2 82 , 2 84 , 2 87, 2 88
rpcgen, 334 , 336, 338
rpcinfo, 334
s
sajt vezrl, 4 83, 4 99, 530
schedule(), 2 2 , 4 2 4
scheduler, 18, 104
SCons, 556
segmentation fault, 78, 34 2 , 570
selectO, 12 9, 130, 132 , 134 , 135, 2 69, 311,
315, 4 03
semaphore, 166, 174 , 177, 2 33, 2 34 , 366,
391, 392 , 393, 394
sendO, 2 74 , 302 , 303, 315, 32 7, 32 9
sendfile0, 303, 304
sendto(), 2 73, 2 96, 32 7, 32 9, 330
session, 18, 192 , 561
sessionid, 18
setgid, 111, 14 8, 14 9, 198, 199, 2 00
setsockoptO, 306, 32 1, 32 6
setuid, 111, 198, 199, 2 00, 2 52
SGCheck, 578
sh, 2 0
590
Trgymutat
shell, 2 0, 4 4 , 108, 12 2 , 12 3, 190-193, 197,
198, 2 01, 2 53, 562
SHUT_RD, 2 71
SHUT_RDWR, 2 71
SHUT_WR, 2 71
shutdownO, 2 71
SIGPIPE, 12 3, 2 4 0, 2 50, 303
sin6_flowinfo, 2 91
sin6_scope_id, 2 91
slab, 385
sleep(), 387, 390, 391, 4 12 , 4 15, 4 17
sleep_onO, 396
sleep_on_interruptible(), 4 00
SO_KEEPALIVE, 32 7
SO_REUSEADDR, 305, 310, 313, 32 7
SOCK_DGRAM, 2 66, 2 95, 318, 32 0, 32 4 ,
32 8, 32 9
SOCK_PACKET, 2 66
SOCK_RAW, 2 66, 2 67
SOCK_RDM, 2 66
SOCK_SEQPACKET, 2 66
SOCK_STREAM, 2 66, 2 77, 2 79, 2 95, 2 97,
300, 305, 307, 310, 313, 316
sockaddr_in, 2 90, 2 91, 2 95, 2 98, 2 99, 301,
305,306, 310, 313, 318, 32 4
sockaddr_in6, 2 91, 2 95, 2 98, 2 99, 305,
306,310, 313, 318, 32 4
socket, 2 65-2 80, 2 93-2 95, 2 99, 302 -305,
307-32 4 , 32 6-330, 52 3, 52 4 , 52 6, 52 8
socket(), 2 65, 2 66, 2 72 , 2 80, 2 95
socketpairO, 2 80
software interrupt, 4 13
SOL_SOCKET, 305, 310, 313, 32 6
so-nv, 57, 58, 59, 60, 61, 64 , 87
spin_lock_irqsave0, 390
spinlock, 2 37, 366, 389, 390, 393
splice0, 304
splint, 582
SQL programozi interfsz, 516
ssh, 2 89
ssleepO, 4 2 3, 4 2 4
start_kerne10, 14
statO, 109, 2 00, 2 75
statikus programknyvtr, 50, 51, 55, 56,
63, 89, 34 1, 537
statikus szimblumtblzat, 81, 90
statikusan linkelt megosztott program-
knyvtr, 62
stdin, 14 9, 315
strace, 61, 582
stream, 14 9, 2 68, 2 75, 519
stream socket, 2 68
struct addrinfo, 2 94 , 2 95, 2 97, 300, 305,
307,315, 316, 318, 319, 32 4 , 32 7, 32 9
swap file, 33
symbolic link, symlink, soft link, 4 0
sync, 37, 104 , 105, 397, 4 2 6
sysfs, 351, 353, 355, 366, 382 , 4 2 9, 4 30,
4 34 , 4 36
sysfs jogok, 351
$z
szlanknti trol, 2 16, 2 17
szlbiztos fggvnyek, 2 14
szlspecifikus adatok, 2 14 , 2 15, 2 2 0
szmtott vltoznevek, 54 8
szekcik, 79, 81, 82
szekvencilis llomnyok, 100
szemafor, 16, 166-173, 177, 179, 2 2 1,
2 33-2 36, 366, 389, 391-394 , 4 4 9
szignl, 2 60, 391, 4 4 5, 4 4 6, 4 4 8, 4 51-4 59,
4 76, 4 83, 4 84 , 503, 509, 510, 511,
512 , 515, 518, 52 2 , 52 7, 52 8, 530
szimbolikus hivatkozs, 4 0, 4 2 , 98, 109,
110, 113, 115, 116, 118
szimblumfelolds, 56, 66, 83, 86, 89
szinkron jelzskezelsnek, 2 51
Szinkronizcis osztly, 516
szinkronizlt I/O, 105
szintvezrelt, 133, 138
szlot, 4 4 5, 4 4 6, 4 4 8, 4 51-4 53, 4 56-4 59,
4 83, 4 84 , 503, 504 , 508-512 , 515,
518, 52 2 , 52 9
szolgltatsokat, 3, 11, 12 , 4 13, 4 4 1, 515
szlfolyamat, 18, 19, 34 , 157
szlprocessz, 15, 19, 12 2 , 157, 2 62
T
tjkoztat zrols, 14 3, 14 8
trgykd llomny, 50, 51, 54 , 55, 57,
70, 81-83, 86, 87, 89, 34 6, 538, 552
task, 15, 379, 4 19, 4 2 1, 4 2 2
tasklet, 4 13, 4 14 , 4 15, 4 16
tasklet_schedule(), 4 15
tvoli eljrshvs, 2 65, 331, 332 , 337
TCP_CORK, 32 7
tcpdump, 330
tcsh, 2 0
tee0, 304
teljes olvass, 101, 102 , 2 4 8
telnet, 2 89, 311, 315
text, 54 , 74 , 81, 82 , 83, 84 , 92 , 4 53, 4 54 ,
4 63, 4 70, 4 74 , 4 75, 4 79, 52 8
591
Trgymutat
tgid, 18
THIS_MODULE, 356-360, 364 , 365, 366,
399, 4 01, 4 02 , 4 04 , 4 07, 4 31, 4 37
thread pool, 309
threshold, 32 2
timeout, 12 9, 130, 135, 154 , 2 31, 2 59,
392 , 396, 397, 4 2 4 , 4 2 5, 504
tiszttszlak, 104
tisztogat kezelfggvny, 2 19, 2 2 0
Top half, 2 5, 4 14
tbbfeladatos, 13, 15, 4 39
tbbfelhasznls, 1, 4 39
trlsi pontok, 2 17
Translation Look-aside Buffer, 35
Transmission Control Protocol, 2 67
U
H
U
udev, 355, 356, 360, 399, 4 00, 4 02 , 4 34
UDP_CORK, 32 7, 32 8
uic, 555
uid, gid, 18
umask, 98, 114 , 118, 194 , 2 75
Unix domain socket, 4 1, 2 65, 2 66, 2 75,
2 76, 2 78, 2 80, 2 81, 2 82
unlinkO, 115, 116, 2 78
unlocked_ioctl, 367, 370
user space, 4 05, 4 12
U
H
U
temez, 13, 18, 2 1-2 6, 167, 397
zenetsor, 16, 178, 180, 181, 2 2 1, 2 38
V
Valgrind, 576, 577, 578, 580
vals idej jelzsek, 2 4 3, 2 52 , 2 53
vrakozsi sor, 2 4 2 , 2 4 3, 2 4 6, 2 50, 2 54 ,
2 59, 2 60, 32 7, 32 9, 396, 4 03, 4 17,
4 2 4 , 4 51, 4 56
vrakozsisor-alap sszekttets, 4 52 ,
509, 512
VERIFY_READ, 369, 370
VERIFY_WRITE, 369, 370
vezrlterminl, 192 , 193, 197, 2 02
vfree0, 386
vi, 380, 534
vim, 534
virtulismemria-kezels, 2 7, 2 8, 34 , 78,
139
vmalloc(), 386
vmlinux, 379, 380, 382 , 383
vmsplice(), 304
vonalrend, 151, 154
w
wait queue, 396
wait_eventO, 397
wait_event_interruptible(), 4 00
wake_up(), 398
wake_up_interruptible0, 398
widgetknyvtr, 4 4 0, 4 4 1
wireshark, 330, 331
work_struct, 4 18, 4 19
working set, 33
workqueue, 4 14 , 4 18, 4 19, 4 2 0
write, 99, 2 65, 2 70, 2 73, 2 74 , 302 , 303
X
X szerver, 4 39, 4 4 0
X Window, 5, 2 75, 4 39, 4 4 0, 4 4 2 , 4 4 4
X.Org, 4 39
XFree86, 4 39
z
zrolllomny, 14 3, 14 4 , 14 5
zombie, 17, 160
592
Irodalomjegyzk
[1] Kerninghan, Brian W. Ritchie, Dennis M.: A C programozsi nyelv.
Mszaki Knyvkiad, 1994 .
[2 ] Benedek Zoltn Levendovszky Tihamr: Szoftverfejleszts C++ nyel-
ven. SZAK Kiad, 2 007.
[3] Stroustrup, Bjarne: A C++ programozsi nyelv. Kiskapu Kft., 2 001.
[4 ] Wheeler, David A.: Program Library HOWTO. Linux Documentation
Project, October 2 000.
[5] Barlow, Daniel: GCC-HOWTO. Linux Documentation Project, 1999.
[6] Rusling, David A.: The Linux Kernel. Linux Documentation Project,
1996-1999.
[7] Volkerding, Patrick Foster-Johnson, Eric Reichard, Kevin: Linux
Programming. MIS:Press, 1997.
[8] Tannenbaum, Andrew S. et al.: Opercis rendszerek. Panem Knyvki-
ad Kft., 1999.
[9] Fitzpatrick, Richard: Introduction to Computational Physics.
http:// farside.ph.utexas.edu/teaching/32 9/lectures/lectures.html, 2 002 .
[10] Sweet, David et. al.: KDE 2.0 Development. Macmillan/SAMS,
http:// www.andamooka.org/reader.pl?section=kde2 0devel, 2 000.
[11] Tannenbaum, Andrew S.: Szmtgp Hlzatok. 3. kiads, Panem
Knyvkiad Kft. 1999.
[12 ] Marshall, A. D.: Programming in C UNIX System Calls and Subrou-
tines using C. http://www.cs.cf.ac.uk/Dave/C/CE.html, 1994 -1999.
[13] Goldt, Sven et al.: The Linux Programmer's Guide. http://oopweb.com/
OS/Documents/LinuxProgrammersGuide/VolumeFrames.html, 1995.
[17] de Goyeneche, Juan-Mariano: Multicast over TCP/ IP HOWTO.
http://jungla.dit.upm.esk-jmseyas/linux/mcast.howto/multic.html, 1998.
[18] Frerking, Gary Baumann, Peter: Serial Programming HOWTO.
Linux Documentation Project, 1998-2 001.
Iroda lomjegyzk
[19] Johnson, Michael K. Troan, Erik W.: Linux Application Development.
Addison-Wesley, 1998.
[2 0] Szebernyi Imre: Bevezets a UNIX opercis rendszerbe. BME Irny-
tstechnika s Informatika Tanszk, Oktatsi segdlet, 1998.
[2 2 ] Rubini, Alessandro: Linux Device Drivers. O'Reilly. 1998.
[2 3] Manrique, Daniel: X Window System Architecture Overview HOWTO.
Linux Documentation Project, 2 001.
[2 5] Sarwar, Badrul et al.: Linux & Unix Programming Tools: A Primer for
Software Developers. Addison-Wesley, 2 003.
[2 6] Hollabaugh, Craig: Embedded Linux: Hardware, Software, and Inter-
facing. Addison-Wesley, 2 002 .
[2 7] Kerrisk, Michael: The Linux Programming Interface: A Linux and
UNIX System Programming Handbook. October 2 010, No Starch Press.
[2 8] Stevens, W. Richard Rago, Stephen A.: Advanced Programming in the
UNIX Environment. 2 nd edition, Addison-Wesley Professional, 2 005.
[2 9] Love, Robert: Linux System Programming: Talking Directly to the Ker-
nel and C Library. lst edition, O'Reilly Media, 2 007.
[30] Mauerer, Wolfgang: Professional Linux Kernel Architecture.
Wrox, 2 008.
[31] Jelnek, Jakub: Prelink. Red Hat, Inc., 2 004 .
[32] GCC Manual. http://gcc.gnu.org/onlinedocs/, 2 010.
[33] GNU Make Manual. http://www.gnu.org/software/make/manual/, 2 010.
[34] GDB Manual. http://sourceware.org/gdb/current/onlinedocs/gdb/, 2 012 .
[35] Valgrind User Manual.
http://valgrind.org/docs/manual/manual.html, 2 012 .
[36] Linux Kernel forrs. http.//www.kernel.org/,
[37] Bovet, Daniel P. Cesati, Marco: Understanding the Linux Kernel. 3rd
Edition, O'Reilly Media, 2 005.
594
Ekler Peter
Fehr Marcell
Forstner Bertalan
Kelenyi Imre
N L) R. C3 I FIALAP
SZOFTVEFEJLESZ FS
Az Android rendszer programozsanak bemutatsa
Ekler Pter, Fehr Marcell,
Forstner Bertalan, Kelnyi
Imre
Android-alap
szoftver-
fejleszts
Kartonlt, B5
ISBN 978-963-9863-2 7-9
4 00 oldal, 6 000 Ft fval
A Budapesti Mszaki s
Gazdasgtudomnyi Egyetem
Automatizlsi s Alkalmazott
Informatikai Tanszkn mkd
Alkalmazott Mobil Kutatcso-
port (Amorg) kiemelt figyelmet
fordt a hazai mobiltechnolgia-
oktats folyamatos fejlesztsre. Munkjuknak ksznheten lehetv
vlt, hogy szlesebb rtegek ismerkedjenek meg a legnpszerbb mobil-
platformokkal, s napraksz tudsuk legyen a legjabb technolgikat il-
leten. vente csak az egyetemrl tbb mint 500 hallgat vesz rszt a
kurzusaikon. Az Amorg tagjai a tanszk npszer Alkalmazott informati-
ka sorozatnak keretben ezttal egy hinyptl mvel lepik meg az
okostelefonok fejlesztse irnt rdekldket. Btran llthatjuk, hogy
Android platform vilgszinten az egyik legnpszerbb s legelterjedtebb
mobilplatformm ntte ki magt, ppen ezrt a knyv elolvassval meg-
szerezhet ismeretek hossz tv tudst jelentenek a felhasznlk sz-
mra. A knyv szerzi az Android platformmal mr a legels SDK megje-
lense ta foglalkoznak, szaktudsukat llandan szinten tartjk, s fo-
lyamatos rsztvevi a hazai s nemzetkzi ipari kutatsoknak s fejlesz-
tseknek, gy szles kr tapasztalattal rendelkeznek. A knyv gondosan
vlogatott tmakrei, szakszer szerkesztse s a vlogatott pldk lehe-
tv teszik, hogy a mindennapi munka sorn is alkalmazhassuk, s a
rszletes magyarzatok segtsgvel a technolgia mkdst is knnyen
megrthessk. A szerzk trekedtek arra, hogy a knyvben szerepl kd-
rszek hasznlatt lehetsg szerint nll alkalmazsokon keresztl is
bemutassk, ezek a pldk az elszban tallhat hivatkozson keresztl
rhetk el.
Az Alkalmazott informatika sorozat
kaphat ktetei
Charaf Hassan, Cscs Gergely, Forstner Bertalan, Marossy Klmn:
Symbian alap szoftverfejleszts
2 4 0 oldal + CD, 4 .500 Ft fval, ISBN 978-963-9131-66-0, 2 004 .
Benedek Zoltn, Levendovszky Tihamr: Szoftverfejleszts C++
nyelven
52 8 oldal + CD, 6.800 Ft fval, ISBN 978-963-9131-94 -1, 2 007.
Imre Gbor, Balogh Pter, Bernyi Zsolt, Dvai Istvn, Imre Gbor,
Sos Istvn, Tthfalussy Balzs: Szoftverfejleszts Java EE plat-
formon
4 60 oldal, 6 500 Ft fval, ISBN 978-963-9131-97-2 , 2 007.
Gl Tibor: Interfsztechnikk
4 4 0 oldal, 6 800 Ft fval, ISBN 978-963-9863-13-2 , 2 010.
Forstner Bertalan, Ekler Pter, Kelnyi Imre: Bevezets a mobil-
programozsba. Gyors prototpus-fejleszts Python s Java nyelven
2 88 oldal, 4 800 Ft fval, ISBN 978-963-9863-01-9, 2 011.
Ekler Pter, Fehr Marcell, Forstner Bertalan, Kelnyi Imre:
Android-alap szoftverfejleszts
4 00 oldal, 6 000 Ft fval, ISBN 978-963-9863-2 7-9, 2 012 .
Asztalos Mrk, Bnysz Gbor, Levendovszky Tihamr: Linux
programozs, msodik, tdolgozott kiads
616 oldal, 7800 Ft fval, ISBN 978-963-9863-2 9-3, 2 012 .
Felels kiad: a SZAK Kiad Kft. gyvezetje
Felels szerkeszt: Kis dm
Olvasszerkeszt: Laczk Krisztina
Trdel: Mamira Gyrgy
Bortterv: Szilvsi Sndor
Grafikai munka kivitelezje: Flrin Gbor (Typozis Kft.)
Terjedelem 38,5 (B5) v.
Kszlt az OOK Press Nyomdban (Veszprm)
Felels vezet: Szathmry Attila
Ara: 7800 Ft fval
ISBN 978-963-9863-29-3
9 789639 863293
A SZAK Kiad a weben
http://www.szak.hu
LINUX
Msodik, tdolgozott kiads
A Linux a kzelmltban volt hszves. Ez a hsz v egyben sikertrtnet is: a
Linux-alap szerverek npszersge tretlen, nagyon sok begyazott eszkz fut-
tat Linuxot, kztk a legnpszerbb okostelefonok. A Linux-disztribcik egyre
kzelebb kerlnek a felhasznlkhoz, hasznlatuk egyre egyszerbb vlik.
Jllehet szmos magas szint programozsi nyelv s krnyezet ll rendelkezsre,
sok olyan feladat ltezik, amelyet az opercis rendszer programozsi felletn
elrhet funkcikkal lehet csak megoldani. Ilyenkor szksg van az opercis
rendszer mkdsnek mlyebb ismeretre, ez begyazott krnyezetben egye-
nesen elengedhetetlenn vlik. Ezekhez a feladatokhoz kvn segtsget nyjtani
a knyv. Az opercis rendszer C/C++-ban elrhet programozsi felletnek
ismertetse sorn rszletesen bemutatjuk a megvalstsi alapelveket, ennek
tkrben rthetv vlik az egyes funkcik hasznlata is. Egy sokkal teljesebb
kp birtokban a magas szint krnyezetek felhasznli is hatkonyabban tudjk
kihasznlni krnyezetk lehetsgeit. Mivel a Linux a Unix opercis rendszerek
csaldjnak tagja, ezrt a Linuxrl elmondottak nagy rsze igaz a Unixra is. Mind-
ezek alapjn ajnljuk a knyvet mindenkinek, aki Linux/Unix krnyezetben ter-
vezi, illetve programozi munkt vgez, valamint azoknak, akik el szeretnl<
sajttani az ehhez szksges ismereteket.
A szerzk knyvket annak els kiadsa ta szinte teljesen tdolgoztk, s sz-
mos j fejezettel bvtettk. A fbb tmakrk a kvetkezk:
Bevezets a Linux-kernel mkdsbe
Programknyvtrak fejlesztse
Prhuzamos programozs
llomnykezels
Hlzati alkalmazsok
Programozs Qt-krnyezetben
Adatbzis-kezels Qt-alapokon
Fejleszteszkzk, hibakeress