msgbartop
Just another blog of mine
msgbarbottom

17 Jan 11 จับลอกการบ้านแบบพื้นๆ

เทอมนี้ผมได้รับมอบหมายให้สอนวิชา Introduction to Computers and Programming ซึ่งเป็นวิชาพื้นฐานสำหรับนักศึกษาชั้นปีที่ 1 ทุกโปรแกรม มีนักศึกษาลงทะเบียนจำนวนมาก อย่างเทอมนี้ก็มีเกือบ 300 คน เนื้อหาหลักก็คือสอนการเขียนโปรแกรมภาษา C กับอัลกอริทึมพื้นฐาน (อย่างเช่น searching และ sorting) แต่การเขียนโปรแกรมเป็นทักษะที่ต้องฝึกฝนบ่อยๆ จึงทำเข้าใจและทำได้ วิชาก็เลยมีทั้งบรรยาย ปฏิบัติการ และการบ้าน (ปีนี้ดีหน่อยที่สามารถหาคนมาช่วยตรวจการบ้านได้)

เมื่อมีการบ้านให้คะแนนแล้ว ผมก็อยากจะให้ทำการบ้านกันจริงๆ (อย่างน้อยก็ควรจะได้สัมผัสและฝึกฝนด้วยตนเอง) เลยจะต้องหาทางตรวจว่าลอกการบ้านกันบ้างหรือเปล่า แต่การบ้านแรกคำถามจะค่อนข้างง่ายมาก ไม่สามารถพลิกแพลงหรือเขียนโปรแกรมแบบที่แตกต่างกันมากนัก (ส่วนใหญ่จะฝึกการเขียน expression ตามสูตรที่กำหนดให้) ก็เลยตรวจการลอกข้อสอบแบบง่ายๆ ก่อน (การบ้านครั้งต่อไปค่อยขยับขยายความซับซ้อนในการตรวจจับให้เพิ่มขึ้น) คือ ตรวจแค่ว่าส่งไฟล์เดียวกันมาหรือเปล่า ในที่นี้แปลว่าเอาไฟล์มาจากเพื่อนแล้วก็ upload ส่งมาให้เลยโดยไม่แตะต้องใดๆ ทั้งสิ้น

เมื่อจะตรวจแบบพื้นๆ ผมก็แค่ใช้ hash function มาสร้าง message digest จากไฟล์ที่นักศึกษาส่งมา ถ้าไฟล์ไหนมี message digest เหมือนกัน ก็แปลว่าลอกกันมาทั้งไฟล์ จะไปได้หักคะแนนถูก การหาค่า message digest ของไฟล์การบ้านทั้งหมด ก็ใช้คำสั่ง find ของ unix

$ cd assignment1
$ find . -name "*" -not -type d -exec shasum '{}' \; | sort > digest_list.txt

คำสั่ง find ใช้หาชื่อไฟล์ตามเงื่อนไขที่กำหนด ในที่นี้คือเอาทุกไฟล์ ยกเว้นไดเรคทอรี เมื่อได้ไฟล์แล้ว เราก็สามารถสั่งให้รันโปรแกรม shasum โดย ‘{}’ จะถูกแทนด้วยชื่อไฟล์ที่ค้นเจอแต่ละไฟล์ จากนั้นก็เอาไปเรียงลำดับเพื่อให้ไฟล์ที่มี digest เหมือนกันอยู่ติดกัน เก็บลงไฟล์​ digest_list.txt ที่เหลือก็แค่เขียนโปรแกรมจับกลุ่มว่าไฟล์ที่เหมือนกันมีใครบ้าง จัดเป็นกลุ่มก็เรียบร้อย

Tags: , ,

19 May 09 สำรองข้อมูลด้วย dirsplit

ผมมักจะมีปัญหากับการแบ็คอัพข้อมูลบ่อยๆ ถึงแม้ว่าจะมีอุปกรณ์ต่างๆ ที่ครบถ้วนอยู่แล้ว เนื่องจากเวลาเก็บไฟล์ไว้เยอะ ถ้าจะเก็บลงแผ่น CD หรือ DVD จะมีปัญหาที่จะต้องมานั่งจัดแบ่งไฟล์ออกเป็นแผ่นๆ บางไฟล์ก็ใหญ่เกินไปเขียนลงบนแผ่นเดียวกัน ก็จะต้องจำไฟล์นี้ไว้ก่อน แล้วไปหาไฟล์อื่นมาแทนถ้าจะทิ้งให้เหลือไว้อย่างนั้นก็รู้สึกว่าเปลือง ทำไปทำมาก็จะงงไปหมด เสียเวลาในการจัดการนานมาก จนกระทั่งขี้เกียจแบ็คอัพในที่สุด

วันนี้ลงค้นๆใน apt-get ของ Ubuntu ดู พบว่ามีคนทำเครื่องมือช่วยจัดการปัญหานี้ คือเป็นสคริปต์เล็กๆ ที่ชื่อว่า dirsplit ที่มาพร้อมกับแพคเกจ genisoimage โปรแกรมนี้ทำหน้าที่สร้างลิสต์ของไฟล์ เพื่อเขียนไดเรคทอรีใหญ่ๆ ลงแผ่น CD/DVD โดยโปรแกรมจะจัดไฟล์ให้เราตามขนาดไฟล์ เราสามารถกำหนดได้ว่าจะสร้าง catalog แต่ละแผ่นใหญ่แค่ไหน (default คือขนาด DVD) วิธีใช้ก็คือ

$ dirsplit -e2 --prefix mybackup ./mydir1 ./mydir2

ตัวเลือก -e2 ใช้กำหนดวิธีการคำนวณและรวมขนาดไฟล์ มีอยู่หลายวิธี ผมเห็นตัวอย่างใช้วิธีนี้ก็เลยใช้ตาม ส่วน –prefix ใช้กำหนดชื่อไฟล์ catalog ที่สร้างขึ้น อย่างกรณีนี้ ก็จะได้ mybackup1.list mybackup2.list … ไปเรื่อยๆ ตามไฟล์ที่เรามี

เมื่อสร้าง catalog เสร็จ ก็ต้องนำมาสร้าง ISO image ซึ่งจะเป็นการไปดึงไฟล์จริงมารวมไว้ วิธีใช้ของ dirsplit ก็มีวิธีสร้าง ISO มาให้ด้วย คือ

$ mkisofs -D -r --joliet-long -graft-points -path-list mybackup1.list -o mybackup1.iso

เพียงเท่านี้ก็จะได้ image สำหรับเขียนลงแผ่น ก็สามารถใช้โปรแกรมที่ชื่นชอบเขียนได้ ผมขี้เกียจใช้ GUI ก็ใช้โปรแกรม wodim โดยตรง

$ wodim -v dev=/dev/scd0 speed=8 mybackup1.iso

ก็จะได้แผ่นสำรองข้อมูล (ที่มีค่าหรือเปล่าก็ไม่รู้) ของเราไว้ได้ ข้อเสียของวิธีนี้ก็คือ ถ้าต้องการค้นหาไฟล์บางอย่างในภายหลังอาจจะยุ่งยากพอควร เพราะเราจะไม่รู้ว่าไฟล์นั้นเก็บไว้ที่ไหน ถ้าให้ดีก็เก็บไฟล์ catalog เอาไว้ด้วย จะได้ค้นหาได้เร็วขึ้น

Tags: , , , ,

19 Oct 08 จัดการการบ้าน (1)

เวลาผมให้นักศึกษาทำการบ้านเขียนโปรแกรม ผมมักจะให้ส่งการบ้านทางเมล เพราะคิดว่าสะดวกที่จะตรวจทางเมลมากกว่า จะทดสอบด้วยการรันโปรแกรมที่ส่งมาก็ได้ รวมทั้งยังสามารถใช้เครื่องมือต่างๆ ในการตรวจจับความคล้ายของโปรแกรมในกรณีที่ลอกกันมาได้อีกด้วย แต่ประสบการณ์ที่ผ่านมา จะพบปัญหาต่างๆ ที่ทำให้ผมไม่อยากตรวจการบ้าน ก็คือ เมลที่แต่ละคนส่งมา จะมีรูปแบบหลากหลาย ไม่ค่อยตรงกับที่กำหนดให้ เช่น ไม่ตั้งชื่อไฟล์ตามที่กำหนด บางคนก็ใช้โปรแกรมบีบอัดแบบแปลกๆ มาให้ บางทีบอกให้ส่งเป็น plain text ก็จะมีคนเขียนใน MS Word แล้วเปลี่ยน extension เป็น .txt จนอ่านไม่ออก หรือกำหนดให้ส่งเป็น .jar แต่ไม่รู้ยังไงใช้ WinRAR ทำเป็น .rar แล้วเปลี่ยน extension เป็น .jar เฉยเลย สุดท้ายผมจะต้องมานั่งไล่เช็คไล่เก็บไฟล์ทีละฉบับ บางคนยังส่งมาหลายที แถมยังมีการใช้แอดเดรสเดียวกัน ส่งการบ้านหลายชุดแทนเพื่อนอีก ทำให้สับสนได้ง่ายมาก และเนื่องจากผมจะต้องสอนนักศึกษาไม่น้อยกว่า 70-80 คน จึงเสียเวลาไปกับเรื่องนี้เยอะมาก จนพาลไม่ค่อยจะอยากตรวจสักเท่าไหร่

เมื่อวานเลยนั่งคิดว่าจะทำยังไงกับการบ้านในเทอมที่จะถึงนี้ดี จะทำเป็นเว็บให้อัพโหลดไฟล์ ก็ขี้เกียจเขียนเว็บ สุดท้ายจึงตัดสินใจจะใช้เมลเหมือนเดิม แล้วไปเขียนสคริปต์ด้วย fetchmail กับ procmail หรือไม่ก็ maildrop เพื่อคัดแยกเมลที่ส่งมา ไปไว้ในไดเรคทอรีที่กำหนด แยก attachment ออกจากเมล โดยอาจจะใช้ Perl หรือไม่ก็โปรแกรม ripMime พร้อมทั้งตอบเมลกลับแบบอัตโนมัติว่าได้รับการบ้านแล้ว (ในกรณีที่ส่งมาถูกตามที่กำหนด) สุดท้ายหวังว่าจะช่วยให้จัดการกับการบ้านทางเมลได้สบายขึ้น แต่วิธีการทั้งหมดก็จะยังไม่สามารถจัดการกับกรณีที่ส่งไฟล์มาผิดประเภทได้ แต่ไม่เป็นไรเพราะมีคนแนะนำวิธีจัดการมาให้แล้ว ก็คือไม่ต้องตรวจให้ 0 ไปเลย คนแนะนำรับรองว่าแค่ทำเพียงครั้งเดียวก็จะส่งถูกต้องทุกคน จริงๆ แล้วยังไม่ได้เขียนสคริปต์ทั้งหมดหรอก แต่จะเอามาเล่าเรื่อยๆ วันนี้เล่าถึง fetchmail ก่อนล่ะกัน

โปรแกรม fetchmail เป็นโปรแกรมสำหรับดึงเมลจากเซิร์ฟเวอร์ (จะเป็นแบบ POP3 หรือ IMAP ก็ได้) มาไว้ที่เครื่องของเรา การทำงานของมัน ก็จะคล้ายๆ โปรแกรมอ่านเมลทั่วไป เพียงแต่ว่าเป็นแบบ command line ที่ให้โหลดเป็นครั้งๆ ไป และอาจจะกำหนดให้ทำงานเป็น daemon คอยเช็คและโหลดอยู่ตลอดเวลาได้ด้วย การใช้งานก็ง่ายมาก แค่กำหนดข้อมูลเซิร์ฟเวอร์ที่จะไปโหลดไว้ในไฟล์ .fetchmailrc เช่น

set daemon 300
poll mail.mydomain.com protocol pop3 user "myname" password "mypassword"
mimedecode
mda "/usr/bin/maildrop"
no keep
fetchall

จะเป็นกำหนดให้อ่านเมลทั้งหมดจากเซิร์ฟเวอร์ด้วยโปรโตคอล pop3 ตามที่กำหนด จากนั้นส่งเมลที่ได้ทีละฉบับไปยังโปรแกรม maildrop ซึ่งเราจะสามารถกำหนด regular expression สำหรับคัดแยกเมลได้ ทีนี้จะเขียนวิธีการคัดแยกทำยังไงเอาไว้ต่อคราวหน้าล่ะกัน

Tags: , , , ,

07 Aug 08 Screen, NoHUP, SIGHUP

ในระบบเชลล์ของยูนิกซ์เวลาที่เราต้องการจะสั่งให้โปรแกรมทำงานแบบแบ็คกราวน์ จะทำโดยเรียกโปรแกรมนั้นพร้อมกับระบุเครื่องหมาย &
ต่อท้าย เช่น

$ firefox &

แต่เราจะพบปัญหาเวลาที่ต้องการให้โปรแกรมที่สั่งให้ทำงานแบบแบ็คกราวน์นั้นทำงานต่อไปแม้ว่าเราจะออกจากระบบไปแล้ว เนื่องจากเวลาเราออกจากระบบ (logout) จะมีการส่งสัญญาณ SIGHUP (hangup) ไปยังโปรเซสทั้งหมดของเราที่กำลังทำงานอยู่ ซึ่งพฤติกรรมโดยปกติของโปรเซสเมื่อได้รับสัญญาณก็คือ หยุดการทำงานแบบไม่ปกติ (abnormal termination) จึงทำให้โปรแกรมที่เราหมายมั่นปั้นมือว่าจะให้ทำงานไปตลอดคืนนี้ หยุดทำงานไปโดยไม่รู้ตัว (กว่าจะรู้อีกทีก็อาจจะเช้าแล้ว ต้องเสียเวลารออีก)

วิธีการแก้ปัญหานี้มีหลายวิธี วิธีที่ยุ่งยากหน่อยก็คือแก้โปรแกรมโดยเรียกใช้ system call เพื่อดัก SIGHUP ไว้ โปรแกรมของเราจะได้ไม่ทำตามพฤติกรรมปกติซึ่งก็ดูจะยุ่งยากไปหน่อย และไม่สามารถใช้กับโปรแกรมที่ไม่เปิดเผยโค้ดได้ อีกวิธีหนึ่งก็คือการใช้โปรแกรม nohup ซึ่งจะทำตัวเป็นเหมือนเชลล์ห่อโปรแกรมของเราไว้อีกชั้นหนึ่ง โดยจะดักสัญญาณ SIGHUP ไว้ ทำให้โปรแกรมทำงานต่อไปหลังจากออกจากระบบ เช่น

$ nohup myprogram &

แต่ข้อเสียของโปรแกรม nohup ก็คือแม้ว่าเราจะกลับเข้ามาในระบบใหม่ เราก็จะไม่สามารถติดต่อหรือดูผลการทำงานของโปรแกรมได้ ผลลัพธ์ทั้งหมดจะต้องเก็บลงไฟล์ไว้ก่อนเท่านั้น ทำให้ไม่สะดวกเท่าที่ควร

screen เป็นโปรแกรมบนยูนิกซ์อีกโปรแกรมหนึ่งที่ช่วยอำนวยความสะดวกในการรันโปรแกรมแบบนี้

$ screen myprogram

screen จะทำงานคล้าย nohup เพียงแต่ว่าเมื่อเริ่มทำงาน screen จะทำให้ดูเหมือนว่าโปรแกรมของเราทำงานเป็นแบบฟอร์กราวน์ตามปกติทั่วไป เราสามารถสั่งให้ทำงานเบื้องหลังได้ โดยกด CTRL-A CTRL-D ต่อกัน โปรแกรมก็จะไม่เชื่อมต่อกับเทอร์มินัล แต่จะทำงานในแบบแบ็คกราวน์ แต่เราสามารถกำหนดให้ screen เรียกโปรแกรมของเราที่ทำงานอยู่ให้กลับมาอยู่เบื้องหน้าอีกครั้งได้ แม้ว่าเราจะออกจากระบบไป และกลับมาใหม่แล้วก็ตาม

$ screen -r

ในกรณีที่เรียกใช้ screen พร้อมกันหลายๆ โปรเซส ก็อาจจะต้องระบุรหัสโปรเซสที่ต้องการเรียกกลับมาบนเทอร์มินัล โดยอาจจะใช้ออปชัน -ls เพื่อแสดงโปรเซสของ screen ทั้งหมดก็ได้ นอกจากนี้ screen ยังมีออปชันให้เกิดสิ่งที่เป็นผลลัพธ์ทั้งหมดลงไฟล์ไว้ให้ด้วยก็ได้ ทำให้สะดวกในการเรียกดูผลลัพธ์ภายหลัง ผมเองก็ต้องพึ่งโปรแกรม screen เยอะเลยทีเดียวกว่าจะเรียนจบมาได้

รายละเอียดเพิ่มเติม: http://www.gnu.org/software/screen/

Tags: , , , , ,

29 Jul 08 SSH Tunneling

ผมมักจะมีปัญหาเสมอในการใช้งานโปรแกรมต่างๆ ผ่านเน็ตเวิร์ค เนื่องจากที่ทำงานผมติดตั้งไฟร์วอลล์ที่อนุญาตให้ใช้งานหลักๆ ได้แค่ “เว็บ” กับ “ssh” อย่างเช่น ผมไม่สามารถอัพเดตข้อมูลแพคเกจของ MacPorts ได้ เพราะว่ามันใช้วิธี rsync ผ่านพอร์ต 783 ที่ไม่ได้รับอนุญาต ครั้นจะไปขอให้เขาเปิดพอร์ตเพิ่มก็ดูกระไรอยู่ ส่วนใหญ่ผมจึงมักจะอัพเดตข้อมูลแพคเกจที่บ้านก่อนมาทำงาน

จริงๆ แล้ว ถ้าหากเรามีเซิร์ฟเวอร์ที่ใช้งาน ssh ได้อยู่ภายนอก และเซิร์ฟเวอร์เครื่องนั้นไม่มีไฟร์วอลล์ เราจะสามารถใช้วิธี ssh tunneling เพื่อติดต่อจากเครื่องของเราผ่านเซิร์ฟเวอร์ออกไปโลกภายนอกได้

$ ssh xxx.myserver.net -L 1783:rsync.somewhere.com:783

จะเป็นการติดต่อผ่าน ssh ไปยังเครื่อง xxx.myserver.net ตัวเลือก -L ใช้กำหนด ssh tunneling โดยโปรแกรม ssh จะจับข้อมูลที่ส่งไปยังพอร์ท 1783 ของเครื่องเราทั้งหมด ส่งต่อผ่านไปยังเครื่อง xxx.myserver.net และส่งต่อไปยังพอร์ต 783 ของเครื่อง rsync.somewhere.com ทำให้เราสามารถใช้งานเครื่อง rsync.somewhere.com ที่อยู่ข้างนอกได้ โดย ssh ทำตัวเสมือนเป็นอุโมงค์ให้ข้อมูลของเราลอดผ่านไฟร์วอลล์ออกไป

ในทำนองเดียวกัน ผมก็มักจะใช้ ssh tunneling เพื่อต่อเข้ามาใช้งานเน็ตเวิร์คภายในหน่วยงาน เวลาผมอยู่ข้างนอก อย่างเช่น ถ้าผมอยากจะโหลดเปเปอร์จากฐานข้อมูลที่สถาบันเป็นสมาชิก ซึ่งปรกติเขาจะตรวจสอบบุคคลด้วยไอพีแอดเดรส เวลาผมอยู่บ้านผมก็จะแค่ ssh เข้ามาที่เซิร์ฟเวอร์ภายในสถาบันก่อนแล้ว โดยกำหนดให้ forward ข้อมูลไปยังเครื่อง proxy ที่สามารถใช้งานได้ จากนั้นผมก็แค่เซ็ต proxy บนเครื่องผมให้เป็น localhost และใช้พอร์ตที่กำหนด ก็จะดูเหมือนว่าผมใช้งานจากภายในหน่วยงาน ผมสามารถเข้าไปใช้งานฐานข้อมูลได้ตามปกติ

$ ssh xxx.myinternal.net -L 8080:proxy.myinternal.net:8080

โปรแกรม ssh ส่วนใหญ่จะสนับสนุน tunneling หรือบางทีเรียกว่า port forwarding อย่างเช่น บน Windows คนที่ใช้ putty ก็จะมีตัวเลือกให้กำหนดพอร์ตต้นทางและปลายทางได้ ดังรูป

Tags: ,