|
|
Bu makalenin farkl� dillerde bulundu�u adresler: English Castellano Deutsch Francais Russian Turkce |
Leonardo Giordani <leo.giordani(at)libero.it> Yazar hakk�nda: Milan Politecnico Telekom�nikasyon M�hendisli�i fak�ltesinde yeni diploma ald�m.Programlama ile ilgileniyorum (�o�unlukla Assembly ve C/C++).1999'dan beri neredeyse sadece Linux/Unix ile �al��t�m. T�rk�e'ye �eviri: �zcan G�ng�r <ozcangungor(at)netscape.net> ��erik: |
E�zamanl� Programlama - �leti Kuyruklar� (3)�zet: Bu makale, e�zamanl� programlama hakk�ndaki son makaledir: Burada, protokol�m�z�n ikinci ve son katman�n� uygulaca��z. Bu katman, �nceki makalede geli�tirdi�imiz ilk katman�n �zerinde kullan�c� davran��lar�n� uygulayan fonksiyonlar� yarat�r. Bu serinin �nceki makalelerini okumak faydal� olacakt�r:
|
Katman 2, servis isteyen, servise cevap veren ve ba�lang�� i�lemlerini yapan y�ksek seviyeli fonksiyonlar� i�erir. Bu fonksiyonlar Katman 1'deki fonksiyonlar kullan�larak olu�turulmu�tur ve bu y�zden anlamas� �ok kolayd�r. Sadece �una dikkat edin: layer2.h dosyas�nda, ileti tiplerini g�steren (kullan�c� iletisi veya servis iletisi) ve farkl� servisleri g�steren (�rne�in deneyler i�in iki kullan�c�-tan�ml� servis) isimleri tan�mlad�m.
ipcdemo, sadece tan�t�m kodudur: optimize edilmemi�tir ve farkedece�iniz gibi, bir�ok k�resel de�i�ken kulland�m. Ama bunu okuyucunun koda de�il IPC k�sm�na dikkatini �ekmek i�in yapt�m. Herneyse, e�er �ok garip bir�ey bulursan�z, bana hemen yaz�n ve tart��al�m.
Bir kullan�c� hayata geldi�inde, yapt��� ilk i� bir kuyruk yaratmak ve anahtar�n ona nas�l ula�aca��n� bildirmektir. Bunu yapmak i�in kullan�c�, iki servis iletisi g�nderir: SERV_BIRTH ve SERV_QID.
/* Kuyru�u ba�lat*/ qid = init_queue(i); /* Anahtara hayatta oldu�umuzu bildir*/ child_send_birth(i, sw); /* Anahtara bize nas�l ula�abilece�ini bildir*/ child_send_qid(i, qid, sw);Sonra as�l d�ng�ye girer: Burada kullan�c� bir ileti g�nderir, di�re kullan�calardan gelen iletileri kontrol eder ve anahtar�n bir servis isteyip istemedi�ini kontrol eder.
�leti g�nderme hakk�ndaki karar, olas�l�k temeline dayanmaktad�r: myrand() fonksiyonu, verilen arg�mana g�re normalle�tirilmi� bir rastgele say� �retir, bizim durumumuzda 100. Biz , sadece bu say� belirlenen olas�l�ktan b�y�k ise iletiyi g�ndeririz. ��nk� kullan�c�, iki d�ng� aras�nda 1 saniye uyumaktad�r. Bu �u demektir: Kullan�c� az ya da �ok her y�z saniyede g�nderme olas�l��� kadar ileti g�nderir. 100'�n, olas�l��� ger�e�e �evirmek i�in yeterli oldu�unu varsay�yoruz.Asl�nda �ok azd�r. Sadece �ok k���k olas�l�k kullanmamaya dikkat edin yoksa sim�lasyonunuz y�llarca �al���r.
if(myrand(100) < send_prob){ dest = 0; /* Anahtara, kendine ve �nceki iletinin al�c�s�na*/ /* ileti g�nderme*/ while((dest == 0) || (dest == i) || (dest == olddest)){ dest = myrand(childs + 1); } olddest = dest; printf("%d -- U %d kullan�c�s�na ileti\n", (int) time(NULL), i, dest); child_send_msg(i, dest, 0, sw); }Di�er kullan�c�lardan gelen iletiler asl�nda, di�er kullan�c�lar�n anahtara ve onunda bize g�nderdi�i iletilerdir ve TYPE_CONN (ba�lant� olarak) i�retlenmi�lerdir.
/* Basit iletiler i�in gelen kutusunu kontrol et*/ if(child_get_msg(TYPE_CONN, &in)){ msg_sender = get_sender(&in); msg_data = get_data(&in); printf("%d -- U %d kullan�c�s�ndan ileti: %d\n", (int) time(NULL), i, msg_sender, msg_data); }E�er anahtar bir servis isterse, TYPE_SERV i�aretli bir ileti g�ndeririz ve cevap vermek zorunday�z. Ba�lant� kesme servisi durumda, anahtara bir bilgi iletisi g�ndeririz. B�ylece anahtar bizi ula��lamaz yapar ve bize ileti g�ndermeyi denemez. Sonra bir kalan b�t�n iletileri okuruz (nazik olmak i�in s�yledim, bu k�sm� atlayabiliriz), kuyru�u sileriz ve sim�lasyona "G�leg�le" deriz. Anahtara servis iste�i g�nderdi�imiz andaki zaman, o anki zaman� i�eren bir iletidir: Anahtar bu zaman� iletinin g�nderildi�i zamandan ��kar�r ve iletinin ne kadar s�redir kuyrukta bekledi�ini �eteleye yazar. G�rd���n�z gibi burada Qos(Quality of Service- Servis Kalitesi) yap�yoruz, sim�lasyonumuz var olan bir telefon sisteminden daha iyidir.
/* Anahtar�n servis isteyip istemedi�ini kontrol et*/ if(child_get_msg(TYPE_SERV, &in)){ msg_service = get_service(&in); switch(msg_service){ case SERV_TERM: /* �zg�n�z, kapatmak zorunday�z*/ /* ANahtara bilgi g�nder*/ child_send_death(i, getpid(), sw); /* Kuyruktaki son iletileri oku*/ while(child_get_msg(TYPE_CONN, &in)){ msg_sender = get_sender(&in); msg_data = get_data(&in); printf("%d -- U %d kullan�c�s�ndan ileti: %d\n", (int) time(NULL), i, msg_sender, msg_data); } /* Kuyru�u sil*/ close_queue(qid); printf("%d -- U %d -- Kapatma\n", (int) time(NULL), i); exit(0); break; case SERV_TIME: /* ��imiz i�in s�re tutmal�y�z*/ child_send_time(i, sw); printf("%d -- U %d -- S�re\n", (int) time(NULL), i); break; } }
�kinci k�s�mda, ana s�re� bir anahtar olarak g�rev yapar. Kullan�c�n� yapt��� bir d�ng� i�inde b�t�n kullan�c�lar ba�lant�y� kesinceye kadar �al���r. Anahtar, kullan�c�lardan gelen iletileri kontrol eder ve gitmesi gereken yerlere y�nlendirir.
/* Kullan�c�n�n ba�lan�p ba�lanmad���n� kontrol et*/ if(switch_get_msg(TYPE_CONN, &in)){ msg_receiver = get_receiver(&in); msg_sender = get_sender(&in); msg_data = get_data(&in); /* E�er iletinin g�nderilece�i yer ba�l� ise*/ if(queues[msg_receiver] != sw){ /* �letinin g�nderildi�i yere ileti g�nder (gelecek cevab� bekle)*/ switch_send_msg(msg_sender, msg_data, queues[msg_receiver]); printf("%d -- S -- G�nderen: %d -- G�nderilen yer: %d\n", (int) time(NULL), msg_sender, msg_receiver); } else{ /* E�er iletinin gidece�i yer ba�l� de�ilse*/ printf("%d -- S -- G�nderilen yere ula��lam�yor (Kullan�c�: %d - G�nderilen yer: %d)\n", (int) time(NULL), msg_sender, msg_receiver); }E�er kullan�c�, ahatar arac�l��� ile bir ileti g�nderiyorsa, bu olas�l�k temeline dayanan (daha �nce �al���yor oldu�u gibi) bir servis iste�i nesnesi olabilir. �lk durumda, kullan�c�n�n ba�lant�y� kesmesi i�in zorlar�z, ikincisinde ise bir zaman tutma i�lemine ba�lar�z: �u anki zaman� kaydederiz ve kullan�c�y� i�aretleriz, b�ylece zaten bu i�i yapan kullan�c� i�in zaman tutmu� olmay�z. E�er ileti almazsak, b�y�k ihtimalle b�t�n kullan�c�lar ba�lant�y� kesmi�tir: Bu durumda o�ul s�re�lerin ger�ekten bitmesini bekleriz (belki son o�ul s�re� son iletilerini kontrol ediyordur), kuyru�umuzu sileriz ve ��kar�z.
/* Son iletiyi g�nderene rastlant�sal olarak servis g�nder*/ if((myrand(100) < death_prob) && (queues[msg_sender] != sw)){ switch(myrand(2)) { case 0: /* Kullan�c� ba�lant�y� kesmeli*/ printf("%d -- S -- %d Ba�lant�y� kesmesi i�in se�ilen kullan�c�\n", (int) time(NULL), msg_sender); switch_send_term(i, queues[msg_sender]); break; case 1: /* Bu kullan�c� i�in zaman tutup tutmad���m�z� kontrol et*/ if(!timing[msg_sender][0]){ timing[msg_sender][0] = 1; timing[msg_sender][1] = (int) time(NULL); printf("%d -- S -- %d kullan�c� zaman tutmak i�in se�ildi\n", timing[msg_sender][1], msg_sender); switch_send_time(queues[msg_sender]); } break; } } } else{ if(deadproc == childs){ /* B�t�n o�ul s�re�ler sonland�, son ikisini son i�lerini bitirmeleri i�in bekle*/ waitpid(pid, &status, 0); /* Anahtar�n kuyru�unu sil*/ remove_queue(sw); /* Program� bitir*/ exit(0); } }�imdi servis iletilerini bekleriz: kullan�c�n�n do�umu, kullan�c�n�n ba�lant�y� kesmesi ve zaman tutma servisi hakk�nda iletiler alabiliriz.
if(switch_get_msg(TYPE_SERV, &in)){ msg_service = get_service(&in); msg_sender = get_sender(&in); switch(msg_service) { case SERV_BIRTH: /* Yeni bir kullan�c� ba�land�*/ printf("%d -- S -- Kullan�c� %d'nin etkinle�tirilmesi\n", (int) time(NULL), msg_sender); break; case SERV_DEATH: /* Kullan�c� ba�lant�y� kesiyor*/ printf("%d -- S -- %d kullan�c�s� ba�lant�y� kesiyor\n", (int) time(NULL), msg_sender); /* Listeden onun kuyru�unu sil*/ queues[msg_sender] = sw; /* Ka� kullan�c�n�n ba�lant�y� kesti�ini bil*/ deadproc++; break; case SERV_QID: /* Kullan�c� bize kendi kuyruk kimli�ini g�nderiyor*/ msg_data = get_data(&in); printf("%d -- S -- Kullan�c�s�n�n kuyurk kimli�i : %d\n", (int) time(NULL), msg_sender, msg_data); queues[msg_sender] = msg_data; break; case SERV_TIME: msg_data = get_data(&in); /* Zaman tutma bilgileri*/ timing[msg_sender][1] = msg_data - timing[msg_sender][1]; printf("%d -- S -- %d kullan�c�s�n�n zaman tutma i�lemi: %d saniye\n", (int) time(NULL), msg_sender, timing[msg_sender][1]); /* Kullan�c� art�k zaman tutma i�leminde de�il*/ timing[msg_sender][0] = 0; break; } }
IPC deneyileri hakk�nda k���k bir �neri. �o�u zaman porgramlar sizin istedi�iniz gibi �al��mayacakt�r ( yukar�daki program� defalarca �al��t� ). Ama programlar� b�ld���n�zde (forking) ctrl-C'ye basmak b�t�n i�elmleri �ld�rmez. Daha �nce kill komutundan bahsetmedim ama kullanma klavuzundan (man page) kolayca anlayabilirsiniz. Program�n�z �ld�r�ld�kten sonra arkas�nda b�rakaca�� birka� �ey var: IPC yap�lar�. Yukar�daki �rnekte, �al��an s�re�leri �ld�r�rseniz, ileti kuyruklar�n� kesinlikle ay�rmalar�n� kald�rmaz (deallocation). B�t�n �ekirdek belle�ini temizlemek i�in ipcs ve ipcrm komutlar�n� kullan�r�z: ipcs o anki b�t�n ayr�lm�� IPC kaynaklar�n� (sadece sizinkini de�il, hepsini. Dikkatli olun) g�sterir. ipcrm bunlardan istediklerinizi kald�rman�za yard�mc� olur. E�er ipcrm komutunu hi�bir arg�man vermeden �al��t�r�rsan�z ihtiyac�n�z olan b�t�n bilgileri size g�sterir: ilk denemede �nerilen say�laer "5 70 70".
Projeyi a�mak i�in "tar xvzf ipcdemo-0.1.tar.gz" komutunu �al��t�r�n. ipcdemo program�n� derlemek i�in sadece "make" komutunu projenin dizini i�inde �al��t�r�n. "make clean" yedekleme dosyalar�n�, "make cleanall" hem yedekleme hem de nesne dosyalar�n� siler.
Hata ay�klay�c�lar (debuggers), geli�tiricinin en iyi arkada�lar�d�r, en az�ndan geli�tirme s�ras�nda. ddd'den �nce gdb'nin nas�l kullan�ld���n� ��renin. ��nk� grafiksel ara�lar g�zeldir ama gerekli de�ildir.
"Segmentation fault" iletisi ald�n�z ve nerede hata yapt���n�z� m� merak ediyorsunuz. At�lm�� bir �ekirdek (core) dosyas�n� gdb ile okumaya ek olarak, valgrind ile program� �al��t�r�p onun bellek sim�lasyonu �er�evei�i (framework) �zelli�inden faydalanabilirsiniz.
Farketti�iniz gibi C'de IPC program� yazmank e�lencelidir ama karma��kt�r. Python bir ��z�md�r: S�re� b�lme (forking) ve di�er i�ler i�in tam deste�i vard�r ve C geni�lemesi vard�r. Bir bak�n, buna de�er.
|
G�rsely�re sayfalar�n�n bak�m�, LinuxFocus Edit�rleri taraf�ndan yap�lmaktad�r
© Leonardo Giordani, FDL LinuxFocus.org |
�eviri bilgisi:
|
2003-12-22, generated by lfparser version 2.43