1 / 22

דוגמא ל Daemon ב Java

דוגמא ל Daemon ב Java. תכנות מתקדם 2 89-211 תרגול מספר 10 תש"ע 2009-2010. אליהו חלסצ'י. בשיעור שעבר ראינו כיצד ניתן להריץ תוכנית java כ service תחת windows . השתמשנו ב tomcat כתוכנית native שהריצה JVM ובתוכה התוכנית שלנו.

helia
Download Presentation

דוגמא ל Daemon ב Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. דוגמא ל Daemon ב Java תכנות מתקדם 2 89-211תרגול מספר 10 תש"ע 2009-2010 אליהו חלסצ'י

  2. בשיעור שעבר ראינו כיצד ניתן להריץ תוכנית java כ service תחת windows. השתמשנו ב tomcat כתוכנית native שהריצה JVM ובתוכה התוכנית שלנו. בשיעור זה נלמד כיצד לייצר Daemon עבור תוכנית ה java שלנו – תחת Unix (לינוקס) התוכניות בתרגול נכתבו תחת ubuntu 9.04 גם הפעם ברצוננו ליצור תהליך מנותק שרץ ברקע ללא התערבותנו הישירה. הקדמה

  3. תחילה נעשה שימוש ב fork() ה fork יוצר העתק (הילד) של התהליך שלנו (ההורה). ניתן להורה לסיים, והילד יעבור להיות תחת Init (אב כל התהליכים). התוצאה: תהליך הילד מנותק לחלוטין מתהליך האב וממשיך לרוץ ברקע כעצמאי. נאתחל את הרשאות התהליך ע"פ הצורך ע"י umask() (user mask) התהליך שלנו עדיין יכול לקבל signals מההורה המקורי או מהחברים באותה קבוצת תהליכים, לכן נרצה לנתק אותו ע"י setsid(). כיצד נוצר Daemon

  4. נרצה לשנות את ה directory ע"י chdir() כדי שנפעל מתוך אחת מוכרת (ההפך עלול לגרום לבעיות) או אחת המתאימה לריצת התהליך שלנו (לדוג' chdir(“/servers/”)) נרצה לסגור Descriptors שאולי ירשנו ובהם stdin, stdout, stderr נפנה אותם ל I/O device בלתי מזיק כמו /dev/null כעת, לאחר כל הניתוקים, נוכל להריץ כל תוכניתכ daemon ע"י קריאת מערכת system() למשל "java –jar MyDaemon.jar” כיצד נוצר Daemon

  5. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. זה אומר שאנחנוכבר daemon... מה זה אומר אםהpid שלנו שווה 1?

  6. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. מה ה fork עושה? יוצר העתק חדש שלתהליך ההורה ומחזירprocess id תהליך הילד ימשיךמאותה השורה בקוד.

  7. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. pid<0 אומר שתהליךה fork נכשל. pid>0 אומר שאנונמצאים בתהליך ההורהולכן נסיים אותו בהצלחה. pid=0 אומר שאנו נמצאיםבתהליך הילד ולכן נמשיךעם הניתוקים שנותרו. מהו pid<0? pid>0? מה קורה אםpid==0?

  8. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. מגדיר את הרשאות התהליך (כמו הפקודה chmod) למשל umask(027) תקביל ל chmod 750 (המשלים של 027) מה מגדיר umask?

  9. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. את כל ערוצי ה signals שתהליך זה אולי ירש ועשויים להפריע לו. מה אנו רוצים לנתקכעת ?

  10. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. את הפקודה cd. כדי להחליף ל directory המתאים לשירות שלנו. מה הפקודה chdir מבצעת?

  11. #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<string.h> #defineEXIT_SUCCESS0 #defineEXIT_FAILURE1 staticvoiddaemonize(void) { pid_tpid,sid; if(getppid()==1)return; pid=fork(); if(pid<0){ exit(EXIT_FAILURE); } if(pid>0){ exit(EXIT_SUCCESS); } umask(0); sid=setsid(); if(sid<0){ exit(EXIT_FAILURE); } if((chdir("/"))<0){ exit(EXIT_FAILURE); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } נכתוב תוכנית ב C שתריץ עבורנו כלתוכנית java כ daemon נגדיר את הפונקציה daemonizeכך שתבצע את הניתוקים ההכרחיםותשאיר אותנו בתהליך הילד אחריהם. סגירה של ה descriptors הסטנדרטיים. ב unix גם ה stdin ודומיו מצביעים ל"קובץ". בפקודות כאן אמרנו להם להצביע מחדש ל"קובצי" device אחרים – לnull מה מתבצע כעת וכיצד?

  12. כעת ב main נוכל לקרוא ל daemonize() שאחריו נהיה למעשה בתהליך הילד שכעת מנותק מהכל ומהווה למעשה daemon. בדוגמא לקחנו את כל הארגומנטים וצירפנו לפקודה java תחת המחרוזת command. (יותר כללי היה לו לא היינו מקבעים את java) את command נריץ ב shell ע"י system(). לתוכנית המקומפלת נקרא Daemon. ריצה למשל ע"י: # ./Daemon –jar /home/eli/MyDaemon.jar מה יקרה כשנריץ? intmain(intargc,char*argv[]){ daemonize(); charcommand[80]="java"; inti; for(i=1;i<argc;i++){ strcat(command," "); strcat(command,argv[i]); } system(command); return0; } Init Daemon ההורה Daemon הילד java

  13. כעת ב main נוכל לקרוא ל daemonize() שאחריו נהיה למעשה בתהליך הילד שכעת מנותק מהכל ומהווה למעשה daemon. בדוגמא לקחנו את כל הארגומנטים וצירפנו לפקודה java תחת המחרוזת command. (יותר כללי היה לו לא היינו מקבעים את java) את command נריץ ב shell ע"י system(). לתוכנית המקומפלת נקרא Daemon. ריצה למשל ע"י: # ./Daemon –jar /home/eli/MyDaemon.jar מה יקרה כשנעשה kill ל java? intmain(intargc,char*argv[]){ daemonize(); charcommand[80]="java"; inti; for(i=1;i<argc;i++){ strcat(command," "); strcat(command,argv[i]); } system(command); return0; } Init Daemon הילד java

  14. כמו שראינו יכולנו להפוך את התוכנית שלנו לכלי גנרי להרצת כל תוכנית שאינה יכולה לעשות daemonize. כלי אחד כבר קיים תחת השםstart-stop-daemon דוגמא לשימוש: חשוב לייצר pidחדש ולשמור את תוכנו בקובץ כדי שהמע' לא תטעה עם תהליך אחר של java, וכדי שמאוחר יותר נוכל לבצע --stop ל pid השמור. שימוש בכלים קיימים # sudo start-stop-daemon --start --quiet --background --make-pidfile --pidfile /var/run/eli.txt --startas java -- -jar /home/eli/MyDaemon.jar

  15. הריגת התהליך בצורה "ברוטאלית" שכזו, כפי שראינו בדוגמאות עד כה, לא מאפשרת לנו לבצע סגירות אחרונות מתוך תוכנית ה java שלנו. התהליך עצמו נסגר, ואין קריאה לאיזושהי מתודת stop שמימשנו בתוך ה java. אז מה ניתן לעשות כדי לסגור תוכנית כמו שצריך? בעיה • ניתן למשל לפתוח socket על port כלשהו ולהאזין. • כשתינתן הפקודה “stop me” למשל, נבצע סגירה. • נבנה תוכנית נוספת השולחת ל port הזה “stop me”ופשוט נריץ אותה רגע לפני שנהרוג את התהליך בברוטאליות.

  16. אפשרות נוספת תהיה להשתמש בכלים אחרים כגון jsvc של apache. (הכלי המקובל ל java) מספק ממשק Daemon עם מתודות לאתחול, הפעלה, עצירה והריסה. הפקודה jsvc תפעיל את אותן המתודות ע"פ הפרמטרים שתקבל כשתופעל. לדוגמא: שימוש בכלים קיימים # jsvc -cp /usr/share/java/commons-daemon.jar:/home/eli/MyService.jar Main

  17. התקנה: הורידו את ה source מתוך: http://commons.apache.org/downloads/download_daemon.cgi קמפלו את הקוד: כעת ניתן להעתיק את תיקיות ה package שתחת java אל כל פרויקט java רגיל ואז לממש את הממשק Daemon. שימוש בכלים קיימים JAVA_HOME=/usr/bin/java export JAVA_HOME cd daemon-1.0.1/src/native/unix ./configure make

  18. שימוש בכלים קיימים importorg.apache.commons.daemon.*; publicclassMainimplementsDaemon{ @Override publicvoiddestroy(){ // TODO Auto-generated method stub } @Override publicvoidinit(DaemonContextcontext)throwsException{ // TODO Auto-generated method stub } @Override publicvoidstart()throwsException{ // TODO Auto-generated method stub } @Override publicvoidstop()throwsException{ // TODO Auto-generated method stub } }

  19. איך jsvc עובד? שימוש בכלים קיימים יוצר מפעיל ע"י signals את ה controlled process יוצר

  20. בד"כ נרצה שה daemon שבנינו יופעל עם אתחול המערכת. התיקייה /etc/init.d מכילה סקריפטים שטוענים daemons בעת אתחול המערכת. כדי להפעיל את ה daemon שלנו עם האתחול, נצטרך ליצור סקריפט הפעלה עבורו בתיקייה זו. סקריפט בד"כ נכתב ב bash אם כי אין זו חובה. נראה כעת שתי דוגמאות של סקריפטים מוכנים. הפעלה בעת אתחול

  21. /etc/init.d/skeleton סקריפט שלדי עבור הרצת daemons. ניתן להעתיק ולהתאים ל daemon שלנו. משתמש ב start-stop-daemon /etc/init.d/tomcat6 סקריפט להרצת שרת ה tomcat כ daemon. משתמש ב jsvc. הפעלה בעת אתחול

  22. מדוע היינו צריכים לעשות fork ולא להריץ ישר באותו התהליך? מה הבעיה בשיטות שראינו בתחילת השיעור וכיצד ניתן לפתור אותן? למה משמשת התיקייה /etc/init.d ? חישבו אילו התאמות תצטרכו לעשות בפרויקט הקורס כדי להריצו כשירות גם ב Windows וגם ב Linux. הטמעה

More Related