วันเสาร์ที่ 29 พฤศจิกายน พ.ศ. 2551

สร้างรายได้ 100 บาท/โฆษณา/เดือน

สร้างรายได้ 100 บาท/โฆษณา/เดือน

รายละเอียดการสร้างรายได้

      ปัจจุบันนี้การลงโฆษณาผ่านทางเว็บไซต์เป็นทางเลือกหนึ่งที่มาแรงที่สุด เนื่องจากต้นทุนที่ต่ำและปัจจัยหลาย ๆ อย่างของชีวิตประจำวัน โดยการลงโฆษณาเราควรเลือกลงโฆษณากับเว็บไซต์ที่ได้รับการยอมรับทางบุคคลทั่วไป ในเว็บไซต์ที่เราจะแนะนำคือ Google.com ซึ่งมีจำนวนผู้ใช้ มากกว่า 57% ของคนใช้อินเตอร์เน็ต
      ในขณะนี้มีผู้ให้บริการอยู่หลายที่ซึ่งมีอัตราค่าบริการที่แตกต่างกันไป ซึ่งราคาดูแลโฆษณาโดยประมาณ 1,000 บาท/เดือน
      เนื่องจาก เรามีประสบการณ์การโฆษณาผ่านทางเว็บไซต์มากกว่า 3 ปี จึงทราบวิธีที่จะลงโฆษณาใน ราคาประหยัดกว่า เริ่มต้นเพียง 499 บาท/เดือน

จุดเด่น

1. ราคาของเราถูกกว่าที่อื่นครึ่งหนึ่ง ในขณะที่ประสิทธิภาพเท่ากัน
2. ท่านจะได้รับส่วนแบ่งในเดือนแรกและในเดือนต่อ ๆ ไป ในขณะที่ลูกค้าได้ลงโฆษณาอยู่

เริ่มต้นสร้างรายได้

หากว่ามีคนเข้ามาคลิก Link: http://service.pyayam.com/promoteweb.php?u=email@website.com แล้วทำการกรอกข้อมูลและโอนให้แล้ว จะได้ค่าแนะนำคนละ 100 บาท
(ตรง email@website.com นั้น สามารถเปลี่ยนเป็น Email ของแต่ละท่าน เพื่อจะได้ check รายได้จากส่วนนี้)

การคำนวณรายได้

- หากท่านแนะนำให้มีคนลงโฆษณา 1 โฆษณา ท่านจะได้รับ 100 บาท/เดือน
- หากท่านแนะนำให้มีคนลงโฆษณา 10 โฆษณา ท่านจะได้รับ 1,000 บาท/เดือน
- หากท่านแนะนำให้มีคนลงโฆษณา 1,000 โฆษณา ท่านจะได้รับ 100,000 บาท/เดือน
- โดยท่านสามารถแนะนำได้ไม่จำกัด ยิ่งแนะนำมากท่านยิ่งได้มาก

ตัวอย่างการโปรโมท

สามารถทำการโฆษณาจากข้อความด้านล่าง ไว้ที่ webboard หรือ ส่งเป็น forward mail หรือ post ตาม hi5 หรืออะไรก็ได้

เมื่อไหร่จะได้โอนเงินให้กับ Reseller

- ต้องมียอดรายได้อย่างน้อย 1,000 บาท (ท่านสามารถแจ้งรับเงิน ผ่านทาง Email หรือ โทรศัพท์ติดต่อ ตามรายละเอียดด้านล่าง)
- หากบัญชีของธนาคารท่านอยู่นอกกรุงเทพฯ หรือปริมณฑล ทางเราจะหักค่าธรรมเนียมในส่วนนี้

ท่านสามารถตรวจสอบยอดผู้กรอกข้อมูลได้โดย

- ทุกครั้งที่มีคนกรอกรายละเอียดการลงโฆษณา จะมี Email แจ้งท่านทาง Email ทุกครั้ง (ดังนั้น ตรง email@website.com ท่านควรตรวจสอบให้ดี)
- เมื่อผู้กรอกได้ทำการโอนเงินค่าลงโฆษณาให้กับทางเราแล้ว ทางเราจะมี Email แจ้งท่านทุกครั้ง (ให้ท่านเก็บ Email นั้นไว้เป็นหลักฐาน)

 

โปรโมทเว็บไซต์ที่หน้าแรก Google

โปรโมทเว็บไซต์ที่หน้าแรก Google
เพียง 499 บาท ภายใน 15 นาที

Promotion ส่งท้ายปี 2008

            Google Adwords คือ วิธีการโฆษณารูปแบบหนึ่งของการทำการตลาดผ่าน Search Engine โดยเป็นรูปแบบ Pay Per Click (PPC) คือคุณจะจ่ายค่าโฆษณาก็ต่อเมื่อมีคนคลิกที่ Ad โฆษณาของคุณ และ Ad โฆษณาของคุณจะปรากฏให้ผู้ชมเห็นตามคีย์เวิร์ด (Keyword) หรือกลุ่มคำที่คุณเลือกไว้และเป็นคำที่เกี่ยวข้องกับธุรกิจของคุณ เมื่อคุณทำการลงโฆษณากับ Google Adwords แล้ว Ad โฆษณาของคุณจะไปปรากฏอยู่ใน Search Engine และเว็บไซต์ชั้นนำของโลก เช่น

            และอื่นๆอีกมากมาย ซึ่งเว็บไซต์เหล่านี้สามารถเข้าถึงกลุ่มผู้ใช้อินเตอร์เน็ตทั่วโลกมากกว่า 90% ของผู้ใช้อินเตอร์เน็ตทั้งหมด

ทำไมต้องถูกกว่าที่อื่น ๆ มากขนาดนี้

- เนื่องจากเรามีประสบการณ์ทางการลงโฆษณามาหลายปี จึงทราบวิธีที่ทำให้ประหยัดงบการโฆษณาและประสิทธิภาพเท่ากับโฆษณาทั่ว ๆ ไป

แล้วแบบนี้กำไรก็ได้น้อยกว่าคนอื่น ๆ ใช่ไหม

- ในช่วงแรกเราอาจจะได้กำไรน้อย แต่ถ้าลูกค้าที่ใจดีได้แนะนำบอกต่อก็จะทำให้เรามีกำไรเพิ่มขึ้นเรื่อย ๆ

ข้อดีของการลงโฆษณากับเรา

- ไม่มีค่าธรรมเนียมแรกเข้า (เหมือนกับเว็บอื่น ๆ)
- สามารถเพิ่มโฆษณาของท่าน ในเวลาเพียง 15 นาที
- เลือกกลุ่มเป้าหมายลูกค้าได้ชัดเจน
- ไม่จำกัดจำนวน Keywords
- ปรากฏในทุกหน้าของ Google (ไม่เฉพาะหน้าแรก)
- ทำให้ท่านเหนือกว่าคู่แข่งในประเภทธุรกิจเดียวกัน ทั้งยังเพิ่มความน่าเชื่อถือให้กับบริษัทของท่าน
- จะเสียค่าใข้จ่ายต่อเมื่อมีผู้ชมคลิคเข้ามาที่ลิงค์ของท่านเท่านั้น
- มีรายงานผลการเข้าชมส่งตรงถึง Email ของท่านทุก ๆ วัน / สัปดาห์ / เดือน
- หากใช้งบไม่หมดในเดือนนั้น ๆ สามารถยกยอดไปยังเดือนถัดไปได้
- โฆษณาของเราให้บริการ ตลอด 24 ชั่วโมง
- หากท่านไม่พอใจ เราสามารถโอนเงินจากงบที่เหลือ คืนให้ท่านทันทีทุกเวลา

ขั้นตอนและระยะเวลาในการทำงาน

หลังจากท่านได้กรอกรายละเอียดด้านล่างและโอนเงินให้กับเรา หลังจากนั้นจะปรากฏเว็บไซต์ของท่านในส่วนผู้สนับสนุนของ Google ภายในเวลา 15 นาที

ค่าใช้จ่ายของลูกค้าใหม่

1. ค่าดูแลโฆษณา จาก ปกติ 999 บาท พิเศษ เดือนละ 499 บาท
2. ค่างบประมาณโฆษณา (ตามที่ท่านกำหนด)

พิเศษ! สำหรับลูกค้าเดิม (รายละเอียดเพิ่มเติม >>)

แนะนำเพื่อน หรือ ลงโฆษณามากกว่า 1 โฆษณา คิดค่าดูแลโฆษณา เดือนละ 399 บาท
การคำนวณรายได้
- หากท่านแนะนำให้มีคนลงโฆษณา 1 โฆษณา ท่านจะได้รับ 100 บาท/
เดือน
- หากท่านแนะนำให้มีคนลงโฆษณา 10 โฆษณา ท่านจะได้รับ 1,000 บาท/เดือน

- หากท่านแนะนำให้มีคนลงโฆษณา 100 โฆษณา ท่านจะได้รับ 10,000 บาท/เดือน
- โดยท่านสามารถแนะนำได้ไม่จำกัด ยิ่งแนะนำมากท่านยิ่งได้มาก

ตัวอย่างการคำนวณค่าใช้จ่าย

หากท่านกำหนด งบประมาณไว้ 2,500 บาท/เดือน จำนวนที่ท่านต้องโอนมาคือ 2,500 + 499 = 2,999 บาท/เดือน

โฆษณาถูกที่สุดในไทย เรากล้าพูด

ข้อมูลจาก: http://service.pyayam.com/promoteweb.php

Hiren's BootCD 9.5 : เครื่องมืออัจฉริยะสำหรับนักคอมพิวเตอร์

Hiren's BootCD 9.5 : เครื่องมืออัจฉริยะสำหรับนักคอมพิวเตอร์

 ฉลองครบรอบ 6 ปี รับไปเลย แผ่นบูตซีดีเอนกประสงค์สารพัดประโยชน์ ใช้แก้ไขปัญหาต่างๆ ในลักษณะ "All in one"ซึ่งรวบรวมเครื่องมือต่างๆ สำหรับใช้ในการจัดการบำรุงรักษา แก้ไขปัญหาไวรัสและสปายแวร์ แก้ไขปัญหาคอมพิวเตอร์ทั้งด้านฮาร์ดแวร์และซอฟต์แวร์ และการใช้ในงานอื่นๆ ไว้ในซีดีแผ่นเดียว เช่น สแกนไวรัส, แบ่งพาติชั่น ฮาร์ดดิส,สำรองข้อมู,อื่นๆอีกมากมาย...

 รายละเอียด : คลิกที่นี่ดาวน์โหลด : คลิกที่นี่ ฟรี!!!


 

 
ประกอบด้วย :

1.Partition Tools : เครื่องมือตัดและแบ่งพาร์ติชัน 
2.Disk Clone Tools : เครื่องมือสำหรับโคลนดิสก์ทุกสื่อบันทึกข้อมูล
3.Antivirus Tools : เครื่องมือสำหรับฆ่าไวรัสบนระบบ DoS
4.Recovery Tools : เครื่องมือสำหรับกู้มูลที่เผลอ Format หรือลบทิ้งโดยบังเอิญ
5.Testing Tools : เครื่องมือตรวจสอบและวินิจฉัยอาการเสียของฮาร์ดแวร์
6.RAM (Memory) Testing Tools : เครื่องมือตรวจสอบอาการเสียของแรม
7.Hard Disk Tools : เครื่องมือวินิจฉัยอาการตายของฮาร์ดไดรว์ และกู้ชีวิตฮาร์ดดิสก์ให้กลับคืน
8.System Information Tools : เครื่องมือสำหรับแจ้งรายละเอียดเกี่ยวกับตัวอุปกรณ์
9.MBR (Master Boot Record) Tools : เครื่องมือสำหรับกู้ ซ่อมและมาร์กตำแหน่ง MBR ฮาร์ดไดรว์
10.BIOS / CMOS Tools : เครื่องมือสำหรับปลดรหัสผ่านไบออส และกู้การ Flash ไบออสผิดเวอร์ชัน
11.MultiMedia Tools : เครื่องมือสำหรับเปิดดูไฟล์หนังและภาพ ผ่าน DoS โดยไม่เปิดเข้า Windows
12.Password Tools : เครื่องมือสำหรับรหัสผ่าน Admin (XP/Vista) และกู้ระบบรีจิสทรี
13.NTFS (FileSystems) Tools : เครื่องมือสำหรับเข้าถึงระบบไฟล์แบบ NTFS ผ่าน DoS
14.Dos File Managers : เครื่องมือจัดการลบ ก็อปปี้ไฟล์ใน DoS 
15. DOS Tools : รวมเครื่องมือบน DOS
16. Windows Tools : รวมเครื่องมือบน Windows
17. Other Tools : รวมเครื่องมืออื่นๆ
*อ่านรายละเอียดทั้งหมดได้จากเว็บไซต์ผู้พัฒนา Hiren's BootCD www.hiren.info
http://www.hiren.info/pages/bootcd

ตัวอย่างการใช้งาน 
แก้ปัญหาลืมพาสเวิร์ดเข้า Windows XP
(ส่วนผมส่วนใหญ่จะใช้ข้อ 2.Disk Clone Tools : เครื่องมือสำหรับโคลนดิสก์ทุกสื่อบันทึกข้อมูล โดยใช้โปรแกรม Ghost 

วันเสาร์ที่ 22 พฤศจิกายน พ.ศ. 2551

ความแตกต่างระหว่าง Netbook และ Notebook

ความแตกต่างระหว่าง Netbook และ Notebookการออกแบบ
Netbookการออกแบบเน็ตบุ๊กตั้งอยู่บนหลักการที่ต้องการสร้างคอมพิวเตอร์ราคาไม่แพงและมีความสามารถที่เพียงพอต่อการใช้เล่นอินเตอร์เน็ตและทำงานพื้นฐานง่ายๆ ดังนั้นจึงออกแบบให้มีขนาดที่เล็กกะทัดรัดสามารถพกพาไปใช้งานในที่ต่างๆ ได้อย่างสะดวกด้วยตัวเครื่องที่มีขนาดเพียง 10”x7.5” นิ้ว (แล้วแต่รุ่น) และมีความหนาเพียง 1 นิ้ว ซึ่งช่วยให้สามารถพกพาไปใช้งานที่ต่างๆ ได้ง่าย แต่อาจะรำคาญกับขนาดของหน้าจอและปุ่มกดที่เล็กไปหน่อยตามขนาดของตัวเครื่อง แต่เมื่อใช้ไปซักระยะจะรู้สึกคุ้นชินไปเอง
Notebookในส่วนของโน้ตบุ๊กถึงจะเป็นอุปกรณ์ที่ออกแบบมาสำหรับการใช้งานนอกสถานที่เช่นเดียวกัน แต่โน้ตบุ๊กถูกสร้างขึ้นภายใต้แนวคิดที่แตกต่างกัน โดยโน้ตบุ๊กจะเน้นไปที่ประสิทธิภาพการทำงาน มากกว่าขนาด ทำให้โน้ตบุ๊กมีขนาดที่ใหญ่กว่าอย่างเห็นได้ชัด (มาตรฐานคือหน้าจอขนาด 14 นิ้ว) ซึ่งในจุดนี้ยังส่งผลให้อุปกรณ์ภายในอย่างจอภาพและคีย์บอร์ดในโน้ตบุ๊กมีขนาดที่ใหญ่มากขึ้น ช่วยให้สามารถใช้งานได้ถนัดมือมากยิ่งขึ้น
สเปกเครื่อง
Netbookเรื่องของสเปกเน็ตบุ๊กให้ความสำคัญกับอุปกรณ์ที่เน้นการประหยัดพลังงานเป็นหลัก ไม่ว่าจะเป็นซีพียู เช่น ซีพียูรุ่น ‘อะตอม’ ของอินเทล ฮาร์ดดิสก์ หรืออุปกรณ์ต่างๆ ล้วนแล้วแต่เป็นอุปกรณ์ที่กินไฟน้อยแทบทั้งสิ้น ซึ่งข้อดีคือสามารถช่วยยืดเวลาในการทำงานของเน็ตบุ๊กให้นานยิ่งขึ้น (อย่างต่ำก็ 3 ชั่วโมง) แต่ข้อเสียคือประสิทธิภาพในการทำงานที่ได้ค่อนข้างต่ำ สามารถทำงานได้เฉพาะงานในระดับพื้นฐานทั่วไปเท่านั้น อุปกรณ์บางอย่างที่มักจะมีในโน้ตบุ๊ก เช่น ออพติคอลไดร์ฟ จะไม่มีในเน็ตบุ๊ก ฮาร์ดดิสก์ในเน็ตบุ๊กก็จะมีความจุที่จำกัด
Notebookในเรื่องของสเปกโน้ตบุ๊กค่อนข้างให้ความสำคัญกับประสิทธิภาพในการทำงานค่อนข้างมาก อุปกรณ์ต่างๆ ภายในจึงเน้นไปที่การทำงานเป็นหลัก ทำให้โน้ตบุ๊กสามารถรองรับงานได้ทุกรูปแบบไม่ว่าจะงานเบาหรืองานหนักก็ไม่มีปัญหา มีอุปกรณ์อำนวยความสะดวกสำหรับการทำงานและความบันเทิงที่ครบครัน ซึ่งอาจกินไฟมากกว่า แต่เทคโนโลยีของแพลตฟอร์มโน้ตบุ๊กรุ่นใหม่่ๆ อย่าง เซนทริโน 2 จากค่ายอินเทล ก็สามารถให้ทั้งประสิทธิภาพการทำงานที่สูงและยังประหยัดไฟแบตเตอรี่อีกด้วย (โน้ตบุ๊กรุ่นใหม่ๆ หลายรุ่นสามารถใช้งานด้วยแบตเตอรี่ได้สูงสุดถึง 4-5 ชั่วโมง)

ประสิทธิภาพและความสามารถ
Netbookประสิทธิภาพและความสามารถของเน็ตบุ๊ก เน้นไปที่ความสามารถในการทำงานผ่านระบบเครือข่ายแบบไร้สาย สำหรับใช้ในการติดต่อสื่อสาร โดยเฉพาะกับการใช้งานด้านอินเทอร์เน็ต ที่สามารถใช้งานได้สะดวกและง่ายมากยิ่งขึ้น พร้อมทั้งยังสามารถทำงานพื้นฐานด้านอื่นๆ ได้ แต่อาจมีความเร็วที่ไม่สูงมากนัก
Notebookความสามารถของโน้ตบุ๊กโดยภาพรวมแล้วสามารถทำงานได้ค่อนข้างที่จะหลากหลาย มีประสิทธิภาพในการทำงานที่ดี กว่าเน็ตบุ๊กค่อนข้างมาก ไม่ว่าจะเป็นการทำงานพื้นฐานทั่วไปหรือการทำงานที่ต้องใช้ความสามารถที่สูง โน้ตบุ๊กก็สามารถทำงานได้อย่างมีประสิทธิภาพ บางรุ่นนั้นออกแบบมาให้เล่นเกม 3 มิติ หรือ ตัดต่อวิดีโอ ทำกราฟิกได้ ก็ยังมี

ลักษณะการใช้งาน
Netbookลักษณะการใช้งานของเน็ตบุ๊ก จะเน้นการใช้งานบนอินเทอร์เน็ต (อย่างที่ชื่อก็บอกแล้วว่าเป็น ‘เน็ตบุ๊ก’) แอพลิเคชั่นขั้นพื้นฐานที่ใช้ทรัพยากรของเครื่องไม่สูงนัก เช่น การดูหนัง ฟังเพลงจากเว็บ เล่นอินเทอร์เน็ต พิมพ์งาน ดูเอกสาร และเล่นเกมส์แฟลชเล็กๆ น้อยๆ เท่านั้น และไม่เหมาะกับการทำงานแบบ multitasking หรือการเปิดงานหลายๆ แอพลิเคชั่นในเวลาเดียวกัน
Notebookโน้ตบุ๊กค่อนข้างได้เปรียบในเรื่องของการทำงานที่สามารถทำงานได้ค่อนข้างที่จะหลากหลายกว่าไม่ว่าจะเป็นการทำงานทั่วๆ ไปเช่นดูหนัง ฟังเพลงทั้งจากอินเทอร์เน็ตและซีดีหรือดีวีดีแบบความละเอียดสูง เล่นอินเทอร์เน็ต ไปจนถึงการทำงานเฉพาะด้านที่ต้องอาศัยประสิทธิภาพการทำงานที่สูงขึ้น เช่นการตัดต่อภาพยนตร์ หรือทำงานด้านกราฟิก รวมถึงเล่นเกมส์สามมิติ เป็นต้น และยังสามารถทำงานแบบ multitasking แบบไม่มีปัญหา
น้ำหนัก
Netbookเน็ตบุ๊กถูกออกแบบมาเพื่อการใช้งานนอกสถานที่เป็นหลัก เน้นให้ผู้ใช้สามารถพกพาไปในที่ต่างๆ ได้อย่างสะดวก จึงมีการตัดทอนอุปกรณ์บางส่วนออกไปบ้างเพื่อลดปริมาณการใช้พลังงาน (เช่นออพติดคอลไดรฟ์) และยังช่วยลดขนาดและน้ำหนักของเน็ตบุ๊กลงไปได้มากโดยส่วนใหญ่แล้วเน็ตบุ๊กทั่วๆ ไปจะมีน้ำหนักอยู่ที่ประมาณ 1-1.5 กิโลกรัมเท่านั้น ซึ่งจะเบากว่าโน้ตบุ๊กทั่วไปเกือบครึ่งหนึ่งเลยทีเดียว
Notebookในด้านของโน้ตบุ๊กถึงแม้จะออกแบบมาเพื่อการใช้งานนอกสถานที่เช่นกัน จุดเด่นของโน้ตบุ๊กอยู่ที่ประสิทธิภาพและความเร็วในการทำงานมากกว่า จึงไม่แปลกที่โน้ตบุ๊กจะมีขนาดที่ใหญ่กว่าและหนักกว่าเน็ตบุ๊กเกือบเท่าตัว ทั้งยังมีอุปกรณ์ที่จำเป็นครบครันกว่า โดยน้ำหนักของโน้ตบุ๊กทั่วๆ ไปจะมีน้ำหนักอยู่ที่ประมาณ 2.5 กิโลกรัมสำหรับโน้ตบุ๊กขนาดจอ 14 นิ้ว
ราคา
Netbookด้วยวัสดุและอุปกรณ์ต่างๆ ในเน็ตบุ๊กที่ไม่เน้นประสิทธิภาพหรือความเร็วที่สูงมาก ทำให้ราคาของเน็ตบุ๊ก มีราคาที่ค่อนข้างต่ำในท้องตลาด เหมาะสำหรับผู้ใช้ทั่วไปที่ต้องการคอมพิวเตอร์แบบพกพา (อาจเป็นเครื่องที่สองหรือเครื่องที่สาม) ในราคาที่ประหยัดสำหรับการทำงานในระดับพื้นฐานโดยเฉพาะกับการเล่นอินเทอร์เน็ต หรือบางคนอาจจะซื้อเป็นเครื่องคอมพิวเตอร์เครื่องแรกให้บุตรหลานหรือคนใกล้ชิด
Notebookเรื่องของราคาโน้ตบุ๊กขึ้นอยู่กับสเปก และความสามารถของโน้ตบุ๊กเป็นหลักยิ่งโน้ตบุ๊กที่สามารถทำงานต่างๆ ได้อย่างรวดเร็ว หรือมีลูกเล่นเด่นๆ ในการทำงาน โน้ตบุ๊กรุ่นนั้นก็จะยิ่งมีราคาแพงมากขึ้นเป็นเงาตามตัว
หวังว่าข้อเปรียบเทียบข้างบน จะช่วยให้เพื่อนๆ เลือกซื้อ Netbook กับ Notebook ให้ถูกใจ ตรงความต้องการมากขึ้นนะครับ

วันจันทร์ที่ 17 พฤศจิกายน พ.ศ. 2551

โปรโมทเว็บไซต์ที่หน้าแรก Google

โปรโมทเว็บไซต์ที่หน้าแรก Googleเพียง 499 บาท ภายใน 15 นาที
Promotion ส่งท้ายปี 2008

Google Adwords คือ วิธีการโฆษณารูปแบบหนึ่งของการทำการตลาดผ่าน Search Engine โดยเป็นรูปแบบ Pay Per Click (PPC) คือคุณจะจ่ายค่าโฆษณาก็ต่อเมื่อมีคนคลิกที่ Ad โฆษณาของคุณ และ Ad โฆษณาของคุณจะปรากฏให้ผู้ชมเห็นตามคีย์เวิร์ด (Keyword) หรือกลุ่มคำที่คุณเลือกไว้และเป็นคำที่เกี่ยวข้องกับธุรกิจของคุณ เมื่อคุณทำการลงโฆษณากับ Google Adwords แล้ว Ad โฆษณาของคุณจะไปปรากฏอยู่ใน Search Engine และเว็บไซต์ชั้นนำของโลก เช่น
Google
AOL
AskJeeves
Lycos
Netscape
Excite
Dogpile
Yahoo! Japan
Earthlink
The New York Times
Amazon
The Washington Post
BT Openworld



และอื่นๆอีกมากมาย ซึ่งเว็บไซต์เหล่านี้สามารถเข้าถึงกลุ่มผู้ใช้อินเตอร์เน็ตทั่วโลกมากกว่า 90% ของผู้ใช้อินเตอร์เน็ตทั้งหมด
ทำไมต้องถูกกว่าที่อื่น ๆ มากขนาดนี้
- เนื่องจากเรามีประสบการณ์ทางการลงโฆษณามาหลายปี จึงทราบวิธีที่ทำให้ประหยัดงบการโฆษณาและประสิทธิภาพเท่ากับโฆษณาทั่ว ๆ ไป
แล้วแบบนี้กำไรก็ได้น้อยกว่าคนอื่น ๆ ใช่ไหม
- ในช่วงแรกเราอาจจะได้กำไรน้อย แต่ถ้าลูกค้าที่ใจดีได้แนะนำบอกต่อก็จะทำให้เรามีกำไรเพิ่มขึ้นเรื่อย ๆ
ข้อดีของการลงโฆษณากับเรา
- ไม่มีค่าธรรมเนียมแรกเข้า (เหมือนกับเว็บอื่น ๆ)- สามารถเพิ่มโฆษณาของท่าน ในเวลาเพียง 15 นาที - เลือกกลุ่มเป้าหมายลูกค้าได้ชัดเจน- ไม่จำกัดจำนวน Keywords - ปรากฏในทุกหน้าของ Google (ไม่เฉพาะหน้าแรก) - ทำให้ท่านเหนือกว่าคู่แข่งในประเภทธุรกิจเดียวกัน ทั้งยังเพิ่มความน่าเชื่อถือให้กับบริษัทของท่าน - จะเสียค่าใข้จ่ายต่อเมื่อมีผู้ชมคลิคเข้ามาที่ลิงค์ของท่านเท่านั้น - มีรายงานผลการเข้าชมส่งตรงถึง Email ของท่านทุก ๆ วัน / สัปดาห์ / เดือน- หากใช้งบไม่หมดในเดือนนั้น ๆ สามารถยกยอดไปยังเดือนถัดไปได้- โฆษณาของเราให้บริการ ตลอด 24 ชั่วโมง- หากท่านไม่พอใจ เราสามารถโอนเงินจากงบที่เหลือ คืนให้ท่านทันทีทุกเวลา
ขั้นตอนและระยะเวลาในการทำงาน
หลังจากท่านได้กรอกรายละเอียดด้านล่างและโอนเงินให้กับเรา หลังจากนั้นจะปรากฏเว็บไซต์ของท่านในส่วนผู้สนับสนุนของ Google ภายในเวลา 15 นาที
ค่าใช้จ่ายของลูกค้าใหม่
1. ค่าดูแลโฆษณา จาก ปกติ 999 บาท พิเศษ เดือนละ 499 บาท2. ค่างบประมาณโฆษณา (ตามที่ท่านกำหนด)
พิเศษ! สำหรับลูกค้าเดิม (รายละเอียดเพิ่มเติม >>)
แนะนำเพื่อน หรือ ลงโฆษณามากกว่า 1 โฆษณา คิดค่าดูแลโฆษณา เดือนละ 399 บาทการคำนวณรายได้- หากท่านแนะนำให้มีคนลงโฆษณา 1 โฆษณา ท่านจะได้รับ 100 บาท/เดือน- หากท่านแนะนำให้มีคนลงโฆษณา 10 โฆษณา ท่านจะได้รับ 1,000 บาท/เดือน- หากท่านแนะนำให้มีคนลงโฆษณา 100 โฆษณา ท่านจะได้รับ 10,000 บาท/เดือน- โดยท่านสามารถแนะนำได้ไม่จำกัด ยิ่งแนะนำมากท่านยิ่งได้มาก
ตัวอย่างการคำนวณค่าใช้จ่าย
หากท่านกำหนด งบประมาณไว้ 2,500 บาท/เดือน จำนวนที่ท่านต้องโอนมาคือ 2,500 + 499 = 2,999 บาท/เดือน
โฆษณาถูกที่สุดในไทย เรากล้าพูด
ข้อมูลจาก: http://service.pyayam.com/promoteweb.php

วันอาทิตย์ที่ 9 พฤศจิกายน พ.ศ. 2551

XHTML 2.0

XHTML 2.0
อะไรคือ XHTML 2.0XHTML 2.0 เป็น markup language ที่ถูกออกแบบเพื่อการแสดงผลเอกสารซึ่งใช้อย่างแพร่หลายบน World Wide Web ลักษณะการออกแบบจะเน้นให้ markup tag สามารถใช้ได้อย่างกว้างขวางและให้สามารถขยายการใช้งานได้ง่าย เช่นขยายการใช้ class, role, span, และ div ให้สามารถทำงานร่วมกับ style sheet ได้

จุดประสงค์การออกแบบ
1. พยายามรักษาคุณสมบัติของ XML ให้มากที่สุด (As generic XML as possible)
2. ลดการแสดงผลโดยหันไปให้ style sheet แทนและเพิ่มโครงสร้างภาษาแทน (Less presentation, more structure)
3. กำจัดให้อยู่ภายใต้ข้อกำหนด XML(Well form) ทำให้การใช้งานง่ายขึ้น (More usability)
4. การเข้าถึงข้อมูลง่ายขึ้น (More accessibility)
5. มีมาตรฐานทางภาษา (Better Internationalization)
6. ลดข้อจำกัดทางอุปกรณ์ลง ทำให้ไม่ต้องสร้างภาษาสำหรับแต่ละอุปกรณ์ (More device independence)
7. ลดการใช้งาน script โดยเพิ่มความสามารถที่ตัว XHTML (Less scripting)
8. สามารถใช้งานร่วมกับ semantic web (Integration with the Semantic Web)

Backward compatibilityเนื่องจาก HTML เวอร์ชั่นแรกๆมีจุดประสงค์ที่เฉพาะเกินไปทำให้ เอกสารเวอร์ชั่นใหม่ยังคงทำงานกับเว็บบราวเซอร์เก่าๆได้ ซึ่งงานในส่วนนี้สามารถสามารถใช้ XML + style sheet ซึ่ง 95% ของเว็บบราวเซอร์ในปัจจุบันมีการสนับสนุนอยู่แล้ว งานที่เหลือจึงตกอยู่ที่ว่าเว็บบราวเซอร์รุ่นใหม่จะให้การแสดงผล XHTML เป็นที่น่าพอใจหรือไม่ สำหรับ XForm และ XML Event ซึ่งเป็นคุณสมบัติใหม่ใน XHTML 2.0

XHTML 2 และการแสดงผล

เอกสาร HTML เวอร์ชั่นแรกๆถูกออกแบบเพื่อแสดงโครงสร้างของเอกสารไม่ใช่เพื่อการแสดงผล ซึ่งโครงสร้างเพื่อการแสดงผลถูกเพิ่มเข้ามาในภายหลังโดยผู้ผลิตเว็บบราวเซอร์ XHTML จึงถอดคุณสมบัติการแสดงผลออกโดยไปใช้ style sheet แทน ซึ่งเพิ่มความยืดหยุ่น ความสามารถในการเข้าถึงข้อมูล สามารถทำงานบนอุปกรณ์ใดๆก็ได้ และเพิ่มความสามารถในการแสดงผลเพราะ style sheet สามารถแสดงผลได้ละเอียดดีกว่า HTML element

XHTML 2 และการเชื่อมโยง (Linking)

เอกสาร HTML เวอร์ชั่นแรกๆถูกออกแบบโดยมีการอาศัยความสัมพันธ์ระหว่างเอกสารหลายๆตัวซึ่งเรียกว่า linking ในปัจจุบัน W3C ได้ออกมาตรฐานใหม่คือ XLINK เพื่อสร้างโครงสร้างภาษาในการระบุคุณลักษณะในการเชื่อมโยงเอกสารโดยจะมีการใช้ XLINK ในบางคุณสมบัติที่สำคัญๆ

Chat Server

10.3. Chat Server



The daytime server example from the last section demonstrated the
nuts and bolts of using each of the three communication techniques
for applet-servlet communication. It
didn't take advantage, though, of the persistence gains when
using socket communication. Nor did it show off the simplicity of RMI
communication or the elegance of RMI callbacks (where the servlet can
invoke methods of the applet). It also didn't provide a
compelling reason for why one servlet should support all the
communication techniques--there was no state to maintain or
complicated code base to collect in one location. So, before we end
our discussion of applet-servlet communication, let's look at a
more sophisticated
example: a chat server, implemented as a servlet, that supports
clients connecting via HTTP, non-HTTP sockets, and RMI.



We'll build this chat server using all three communication
techniques so that it can take advantage of the best, most efficient
solution for each client. For example, when the client supports RMI,
the servlet can be treated as a remote object, and (where possible)
it can treat the applet as a remote object, too. When the client
doesn't support RMI but can support direct socket
communication, the chat server can utilize socket persistence and
communicate with the client using a non-HTTP socket protocol. And, of
course, when all else fails, the chat server can fall back to using
HTTP. It would rather not fall back because HTTP, being stateless,
requires that the client poll for updates. But for many clients, HTTP
is the only choice.



The chat server is implemented as a single class with a single
instantiation because it has a large amount of associated state and a
fair amount of code that would otherwise have to be repeated. To
separate it into three classes, one for each protocol, would demand
excessive interserver communication and replicate the core chat
server code three times. Implementing the chat server as a servlet
provides a simple way for one object to make itself available via all
three communication techniques. By being an HTTP servlet, it has
built-in HTTP support. And by extending the
RemoteDaemonHttpServlet
class, it can also easily gain support for non-HTTP socket and RMI
communication.



Note that although you'll see the code in its entirety, we
won't be fully explaining each and every line. To do so would
extend this chapter beyond a reasonable length, assuming we
aren't there already. Therefore, we'll explain the issues
as they concern applet-servlet communication and rely on you to
examine the code to understand all the details.




10.3.1. The Design




Figure 10-3 shows the chat applet in action. Notice
that it uses a large TextArea component to display
the running conversation, with a small TextInput
component underneath where the user can post a new single-line
message. As each contributor composes a message, it's sent to
the chat server and distributed to the other chat clients in various
ways.





figure

Figure 10-3. The chat applet in action



HTTP chat clients post their messages to the server using the HTTP
POST method. The applet takes the new
message from the TextInput component when the user
hits Enter, URL-encodes the message,
and posts it to the servlet as a message
parameter. It's all very straightforward. What is a bit more
complicated is how an HTTP chat client manages to get the other
clients' messages. It uses the HTTP GET method to receive each message,
but it has a problem: it doesn't know when exactly
there's a new message to get. This is the problem with a
unidirectional request/response communication paradigm. The client
has to either periodically poll for updates or simulate bidirectional
communication by making a series of blocking GET requests. By that we
mean the chat client initiates a GET request that blocks until the
server decides it's time to return something. For our example,
we implement this simulated bidirectional communication.



Socket chat clients, for the sake of convenience, post their messages
to the server the same way HTTP chat clients do, with the HTTP POST
method. They could post their messages using
raw socket connections, but only
with a marginal gain in efficiency that, at least in this case,
doesn't outweigh the increased complexity. These socket
clients, however, do use raw sockets to get messages from the other
clients, replacing the simulated bidirectional communication with
actual bidirectional communication. As each new message comes in to
the servlet, it's sent right away from the servlet to the
socket chat clients across plain-text socket connections.



RMI chat clients perform their POSTs and their GETs using method
invocations. To post each new message, the applet simply calls the
remote servlet's broadcastMessage(String)
method. To get new messages, it has two options. It can call the
servlet's blocking getNextMessage() method
or, through the use of callbacks, it can ask the servlet to
call its own setNextMessage(String) method every
time there's a new message broadcast. We've chosen to use
the callback option in our example.



In front of all these applets is a dispatch servlet. It lets the user
choose the applet-servlet communication technique (HTTP, socket, or
RMI) he wants to use and, based on his choice, generates a page that
contains the appropriate applet. It's true that a single applet
could be written to support all three techniques and auto-select
between them based on its runtime environment, but to do that here
would unnecessarily complicate our example. The dispatch servlet also
tells the applet the name of its user, but more on that later.





10.3.2. The Servlet



The full listings for the ChatServer interface and
the ChatServlet class that implements it are given
in Example 10-15 and Example 10-16.





Example 10-15. The ChatServer interface, implemented by ChatServlet



import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ChatServer extends Remote {
public String getNextMessage() throws RemoteException;
public void broadcastMessage(String message) throws RemoteException;

public void addClient(ChatClient client) throws RemoteException;
public void deleteClient(ChatClient client) throws RemoteException;
}






Example 10-16. A full-service chat server/servlet



import java.io.*;
import java.net.*;
import java.rmi.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import com.oreilly.servlet.RemoteDaemonHttpServlet;

public class ChatServlet extends RemoteDaemonHttpServlet
implements ChatServer {

// source acts as the distributor of new messages
MessageSource source = new MessageSource();

// socketClients holds references to all the socket-connected clients
Vector socketClients = new Vector();

// rmiClients holds references to all the RMI clients
Vector rmiClients = new Vector();

// doGet() returns the next message. It blocks until there is one.
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/plain");
PrintWriter out = res.getWriter();

// Return the next message (blocking)
out.println(getNextMessage());
}

// doPost() accepts a new message and broadcasts it to all
// the currently listening HTTP and socket clients.
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// Accept the new message as the "message" parameter
String message = req.getParameter("message");

// Broadcast it to all listening clients
if (message != null) broadcastMessage(message);

// Set the status code to indicate there will be no response
res.setStatus(res.SC_NO_CONTENT);
}

// getNextMessage() returns the next new message.
// It blocks until there is one.
public String getNextMessage() {
// Create a message sink to wait for a new message from the
// message source.
return new MessageSink().getNextMessage(source);
}

// broadcastMessage() informs all currently listening clients that there
// is a new message. Causes all calls to getNextMessage() to unblock.
public void broadcastMessage(String message) {
// Send the message to all the HTTP-connected clients by giving the
// message to the message source
source.sendMessage(message);

// Directly send the message to all the socket-connected clients
Enumeration enum = socketClients.elements();
while (enum.hasMoreElements()) {
Socket client = null;
try {
client = (Socket)enum.nextElement();
PrintStream out = new PrintStream(client.getOutputStream());
out.println(message);
}
catch (IOException e) {
// Problem with a client, close and remote it
try {
if (client != null) client.close();
}
catch (IOException ignored) { }
socketClients.removeElement(client);
}
}

// Directly send the message to all RMI clients
enum = rmiClients.elements();
while (enum.hasMoreElements()) {
ChatClient chatClient = null;
try {
chatClient = (ChatClient)enum.nextElement();
chatClient.setNextMessage(message);
}
catch (RemoteException e) {
// Problem communicating with a client, remove it
deleteClient(chatClient);
}
}
}

protected int getSocketPort() {
// We listen on port 2428 (look at a phone to see why)
return 2428;
}

public void handleClient(Socket client) {
// We have a new socket client. Add it to our list.
socketClients.addElement(client);
}

public void addClient(ChatClient client) {
// We have a new RMI client. Add it to our list.
rmiClients.addElement(client);
}

public void deleteClient(ChatClient client) {
// Remote the specified client from our list.
rmiClients.removeElement(client);
}
}

// MessageSource acts as the source for new messages.
// Clients interested in receiving new messages can
// observe this object.
class MessageSource extends Observable {
public void sendMessage(String message) {
setChanged();
notifyObservers(message);
}
}

// MessageSink acts as the receiver of new messages.
// It listens to the source.
class MessageSink implements Observer {

String message = null; // set by update() and read by getNextMessage()

// Called by the message source when it gets a new message
synchronized public void update(Observable o, Object arg) {
// Get the new message
message = (String)arg;

// Wake up our waiting thread
notify();
}

// Gets the next message sent out from the message source
synchronized public String getNextMessage(MessageSource source) {
// Tell source we want to be told about new messages
source.addObserver(this);

// Wait until our update() method receives a message
while (message == null) {
try { wait(); } catch (Exception ignored) { }
}

// Tell source to stop telling us about new messages
source.deleteObserver(this);

// Now return the message we received
// But first set the message instance variable to null
// so update() and getNextMessage() can be called again.
String messageCopy = message;
message = null;
return messageCopy;
}
}




The getNextMessage() and
broadcastMessage(String message) methods are most
interesting portions of ChatServlet. The
getNextMessage() method returns the next new
message as it comes in, blocking until there is one. To enable this
blocking, it uses the MessageSource and
MessageSink classes. Without getting too deep into
the details of these two classes, we'll just say this: the
servlet constructs a new MessageSink and asks this
sink to get the next message from the source. To accomplish this, the
sink registers itself as an observer of source and calls
wait() to block. When the source receives a new
message, the sink (being an observer) is notified of the change with
a call to its update() method. The sink's
update() method saves the source's latest
message in its message variable and then calls
notify(). This causes its
getNextMessage() method to unblock and return the
message.



The broadcastMessage() method tells all listening
clients when there's a new message. It notifies HTTP clients by
sending the message to the MessageSource; other
clients it notifies directly by looping through its client list. For
each of its socket-connected clients, it prints the message to the
client's socket. For each of its RMI clients, it calls the
client's setNextMessage(String) method. This
is the callback we've been talking about. If, at any point,
there's a problem with a socket or RMI client, it removes that
client from its list.



The two lists, socketClients and
rmiClients, are populated as the servlet hears
from clients. When a socket client connects, the servlet's
handleClient(Socket) method is called and the new
client is added to the socketClientsVector. RMI clients have to add themselves to the
list by invoking the servlet's
addClient(ChatClient) method.



The doGet()
and doPost()
methods of ChatServlet are essentially thin
wrappers around the getNextMessage() and
broadcastMessage() methods. The
doGet() wrapper is so thin you can almost see
through it: doGet() sends as its response whatever
String is returned by
getNextMessage(). The doPost()
wrapper is a bit less transparent. It extracts the posted message
from the POST form data's
"message" parameter, broadcasts the message by
passing it to the broadcastMessage() method, and
sets its response's status code to
SC_NO_CONTENT to indicate there is no content in
the response. In a sense, making a GET request is equivalent to
calling getNextMessage(), and making a POST
request is equivalent to calling
broadcastMessage().



Did you notice which socket port ChatServlet
listens on? It's 2428. Overriding the
getSocketPort() method as
ChatServlet does is an easy way to set the socket
port when you don't want to use an init parameter.





10.3.3. The HTTP Applet



The code for our first applet, the
HTTP chat applet, is shown in Example 10-17.





Example 10-17. A chat client using HTTP communication



import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;

import com.oreilly.servlet.HttpMessage;

public class HttpChatApplet extends Applet implements Runnable {

TextArea text;
Label label;
TextField input;
Thread thread;
String user;

public void init() {
// Check if this applet was loaded directly from the filesystem.
// If so, explain to the user that this applet needs to be loaded
// from a server in order to communicate with that server's servlets.
URL codebase = getCodeBase();
if (!"http".equals(codebase.getProtocol())) {
System.out.println();
System.out.println("*** Whoops! ***");
System.out.println("This applet must be loaded from a web server.");
System.out.println("Please try again, this time fetching the HTML");
System.out.println("file containing this servlet as");
System.out.println("\"http://server:port/file.html\".");
System.out.println();
System.exit(1); // Works only from appletviewer
// Browsers throw an exception and muddle on
}

// Get this user's name from an applet parameter set by the servlet
// We could just ask the user, but this demonstrates a
// form of servlet->applet communication.
user = getParameter("user");
if (user == null) user = "anonymous";

// Set up the user interface...
// On top, a large TextArea showing what everyone's saying.
// Underneath, a labeled TextField to accept this user's input.
text = new TextArea();
text.setEditable(false);
label = new Label("Say something: ");
input = new TextField();
input.setEditable(true);

setLayout(new BorderLayout());
Panel panel = new Panel();
panel.setLayout(new BorderLayout());

add("Center", text);
add("South", panel);

panel.add("West", label);
panel.add("Center", input);
}

public void start() {
thread = new Thread(this);
thread.start();
}

String getNextMessage() {
String nextMessage = null;
while (nextMessage == null) {
try {
URL url = new URL(getCodeBase(), "/servlet/ChatServlet");
HttpMessage msg = new HttpMessage(url);
InputStream in = msg.sendGetMessage();
DataInputStream data = new DataInputStream(
new BufferedInputStream(in));
nextMessage = data.readLine();
}
catch (SocketException e) {
// Can't connect to host, report it and wait before trying again
System.out.println("Can't connect to host: " + e.getMessage());
try { Thread.sleep(5000); } catch (InterruptedException ignored) { }
}
catch (FileNotFoundException e) {
// Servlet doesn't exist, report it and wait before trying again
System.out.println("Resource not found: " + e.getMessage());
try { Thread.sleep(5000); } catch (InterruptedException ignored) { }
}
catch (Exception e) {
// Some other problem, report it and wait before trying again
System.out.println("General exception: " +
e.getClass().getName() + ": " + e.getMessage());
try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
}
}
return nextMessage + "\n";
}

public void run() {
while (true) {
text.appendText(getNextMessage());
}
}

public void stop() {
thread.stop();
thread = null;
}

void broadcastMessage(String message) {
message = user + ": " + message; // Pre-pend the speaker's name
try {
URL url = new URL(getCodeBase(), "/servlet/ChatServlet");
HttpMessage msg = new HttpMessage(url);
Properties props = new Properties();
props.put("message", message);
msg.sendPostMessage(props);
}
catch (SocketException e) {
// Can't connect to host, report it and abandon the broadcast
System.out.println("Can't connect to host: " + e.getMessage());
}
catch (FileNotFoundException e) {
// Servlet doesn't exist, report it and abandon the broadcast
System.out.println("Resource not found: " + e.getMessage());
}
catch (Exception e) {
// Some other problem, report it and abandon the broadcast
System.out.println("General exception: " +
e.getClass().getName() + ": " + e.getMessage());
}
}

public boolean handleEvent(Event event) {
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == input) {
broadcastMessage(input.getText());
input.setText("");
return true;
}
}
return false;
}
}




This applet has the same two workhorse methods as
ChatServlet: getNextMessage()
and broadcastMessage(). Its
getNextMessage() method gets the next message from
the servlet. It's called repeatedly to update the
TextArea. It operates using an
HttpMessage to make a GET request to the servlet,
then interprets the first line of the response as the next new
message. Its broadcastMessage() method sends a
message to the servlet for distribution to the other clients. This
method is called in the applet's
handleEvent() method every time the user hits
Enter in the
TextInput component. It works similarly to
getNextMessage(). It uses an
HttpMessage to perform a POST request, passing the
TextInput's text as the
"message" parameter, and it doesn't bother
to read the response.





10.3.4. The Socket-Connecting Applet



The only difference between the socket-based
SocketChatApplet and the HTTP-based
HttpChatApplet is a redesigned
getNextMessage() method. This method is shown in
Example 10-18.





Example 10-18. A chat client using a raw socket connection



static final int PORT = 2428;
DataInputStream serverStream;

String getNextMessage() {
String nextMessage = null;
while (nextMessage == null) {
try {
// Connect to the server if we haven't before
if (serverStream == null) {
Socket s = new Socket(getCodeBase().getHost(), PORT);
serverStream = new DataInputStream(
new BufferedInputStream(
s.getInputStream()));
}

// Read a line
nextMessage = serverStream.readLine();
}
catch (SocketException e) {
// Can't connect to host, report it and wait before trying again
System.out.println("Can't connect to host: " + e.getMessage());
serverStream = null;
try { Thread.sleep(5000); } catch (InterruptedException ignored) { }
}
catch (Exception e) {
// Some other problem, report it and wait before trying again
System.out.println("General exception: " +
e.getClass().getName() + ": " + e.getMessage());
try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
}
}
return nextMessage + "\n";
}




This method reads broadcast messages from a socket that's
connected to the chat servlet. It uses a simple socket protocol: all
content is plain text, one message per line. The first time this
method is called, it establishes the socket connection and then uses
the connection to get a DataInputStream, where it
can read from the socket one line at a time. It reads the first line
from this stream and returns the text as the next message. For each
subsequent invocation, it reuses the same stream and simply returns
the next line it reads. If there's ever a
SocketException, it reestablishes the connection.





10.3.5. The RMI Applet



The code for the ChatClient interface is shown in
Example 10-19; the RMI-based chat applet that
implements it is shown in Example 10-20.





Example 10-19. The ChatClient interface, implemented by RMIChatApplet



import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ChatClient extends Remote {
public void setNextMessage(String message) throws RemoteException;
}






Example 10-20. A chat client using RMI communication



import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.*;

public class RMIChatApplet extends Applet implements ChatClient {

TextArea text;
Label label;
TextField input;
Thread thread;
String user;

ChatServer chatServer;

private int getRegistryPort() {
try { return Integer.parseInt(getParameter("port")); }
catch (NumberFormatException ignored) { return Registry.REGISTRY_PORT; }
}

private String getRegistryName() {
String name = getParameter("name");
return (name == null ? "ChatServlet" : name);
}

// Returns a reference to the remote chat server/servlet
// Tries to exit if there's a problem.
private ChatServer getChatServer() {
try {
Registry registry =
LocateRegistry.getRegistry(getCodeBase().getHost(), getRegistryPort());
Object obj = registry.lookup(getRegistryName());
return (ChatServer)obj;
}
catch (java.rmi.UnknownHostException e) {
// Don't know the registry host, try to exit
System.out.println("Host unknown in url: " + e.getMessage());
System.exit(1);
}
catch (NotBoundException e) {
// Can't find our object, try to exit
System.out.println("Name not bound: " + e.getMessage());
System.exit(1);
}
catch (ClassCastException e) {
// The object wasn't a ChatServer, try to exit
System.out.println(getRegistryName() + " was not a ChatServer:" +
e.getMessage());
System.exit(1);
}
catch (RemoteException e) {
// General RMI problem, try to exit
System.out.println("Remote exception: " + e.getMessage());
System.exit(1);
}
catch (Exception e) {
// Some other problem, try to exit
System.out.println("General exception: " +
e.getClass().getName() + ": " + e.getMessage());
System.exit(1);
}
return null; // return null if the exit() doesn't work
}

// Add ourselves as a client of the chat server
// Notice there's no need for an RMI registry
private void registerWithChatServer(ChatServer server) {
try {
UnicastRemoteObject.exportObject(this);
server.addClient(this);
}
catch (RemoteException e) {
// General RMI problem, try to exit
System.out.println("Remote exception: " + e.getMessage());
System.exit(1);
}
catch (Exception e) {
// Some other problem, try to exit
System.out.println("General exception: " +
e.getClass().getName() + ": " + e.getMessage());
System.exit(1);
}
}

public void init() {
// Check if this applet was loaded directly from the filesystem.
// If so, explain to the user that this applet needs to be loaded
// from a server in order to communicate with that server's servlets.
URL codebase = getCodeBase();
if (!"http".equals(codebase.getProtocol())) {
System.out.println();
System.out.println("*** Whoops! ***");
System.out.println("This applet must be loaded from a web server.");
System.out.println("Please try again, this time fetching the HTML");
System.out.println("file containing this servlet as");
System.out.println("\"http://server:port/file.html\".");
System.out.println();
System.exit(1); // Works only from appletviewer
// Browsers throw an exception and muddle on
}

// Get the remote chat server
chatServer = getChatServer();

// Register ourselves as one of its clients
registerWithChatServer(chatServer);

// Get this user's name from an applet parameter set by the dispatch servlet
// We could just ask the user, but this demonstrates a
// form of servlet->applet communication.
user = getParameter("user");
if (user == null) user = "anonymous";

// Set up the user interface...
// On top, a large TextArea showing what everyone's saying.
// Underneath, a labeled TextField to accept this user's input.
text = new TextArea();
text.setEditable(false);
label = new Label("Say something: ");
input = new TextField();
input.setEditable(true);

setLayout(new BorderLayout());
Panel panel = new Panel();
panel.setLayout(new BorderLayout());

add("Center", text);
add("South", panel);

panel.add("West", label);
panel.add("Center", input);
}

String getNextMessage() {
String nextMessage = null;
while (nextMessage == null) {
try {
nextMessage = chatServer.getNextMessage();
}
catch (RemoteException e) {
// Remote exception, report and wait before trying again
System.out.println("Remote Exception:" + e.getMessage());
try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
}
}
return nextMessage + "\n";
}

public void setNextMessage(String message) {
text.appendText(message + "\n");
}

void broadcastMessage(String message) {
message = user + ": " + message; // Pre-pend the speaker's name
try {
chatServer.broadcastMessage(message);
}
catch (RemoteException e) {
// Remote exception, report it and abandon the broadcast
System.out.println("Remote exception: " + e.getMessage());
}
catch (Exception e) {
// Some other exception, report it and abandon the broadcast
System.out.println("General exception: " +
e.getClass().getName() + ": " + e.getMessage());
}
}

public boolean handleEvent(Event event) {
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == input) {
broadcastMessage(input.getText());
input.setText("");
return true;
}
}
return false;
}
}




This applet's getNextMessage() and
broadcastMessage() implementations are as simple
as any we've seen. They need only call the remote
servlet's methods of the same name. But their simplicity comes
with a cost: more complicated set-up code. Specifically, the
init() method now has to call the lengthy (but by
now understandable) getChatServer() method to
obtain a reference to the remote chat servlet.



If you look closely at RMIChatApplet, you'll
notice that it doesn't actually use its
getNextMessage() method. Instead, it asks the
servlet to call its setNextMessage() method each
time there's a new message being broadcast. It makes this
request in its init() method when it calls
registerWithChatSer-ver(ChatServer). This method
exports the applet as a remote object, then invokes the
servlet's addClient() method passing a
reference to itself. After this, the servlet's
broadcastMessage() method sends a callback to the
applet each time there's a new message.



If you try using callbacks on your own, don't
forget the basics we covered earlier. You need to run the
rmic RMI compiler on
your remote applet to generate its stub and skeleton classes. And you
need to be sure your server has the
RMIChatApplet_Stub.class and
ChatClient.class files somewhere in its
classpath.





10.3.6. The Dispatcher



Now, for this chapter's last code example, the
ChatDispatch servlet is shown in Example 10-21. This servlet performs two duties. First, when
this servlet is accessed without any request parameters, it prints a
friendly welcome page asking the user which applet version he is
interested in using, as shown in Figure 10-4.
Second, when it's accessed with a request parameter, it prints
a page that contains the appropriate applet, as you saw in Figure 10-3. Be aware that the URL used to access this
dispatch servlet should contain the server's true name, not
localhost, so as to avoid RMI security problems.





figure

Figure 10-4. The chat dispatch welcome page





Example 10-21. The front door dispatch servlet



import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ChatDispatch extends HttpServlet {

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
res.setContentType("text/html");

if (!req.getParameterNames().hasMoreElements()) {
// There were no request parameters. Print a welcome page.
printWelcomePage(req, res);
}
else {
// There was at least one request parameter.
// Print a page containing the applet.
printAppletPage(req, res);
}
}

// The welcome page greets the reader and has a form where the user
// can choose an applet-servlet communication method.
private void printWelcomePage(HttpServletRequest req,
HttpServletResponse res)
throws IOException {
PrintWriter out = res.getWriter();
String me = req.getServletPath();

out.println("<HTML>");
out.println("<HEAD><TITLE>");
out.println("Welcome to an Absurdly Simple Chat");
out.println("</TITLE></HEAD>");
out.println();
out.println("<BODY>");
out.println("<H1>Welcome to an Absurdly Simple Chat</H1>");
out.println();
out.println("Would you like to communicate via:");
out.println("<UL>");
out.println(" <LI><A HREF=\"" + me + "?method=http\">http</A>");
out.println(" <LI><A HREF=\"" + me + "?method=socket\">socket</A>");
out.println(" <LI><A HREF=\"" + me + "?method=rmi\">rmi</A>");
out.println("</UL>");
out.println("</BODY></HTML>");
}

// The applet page displays the chat applet.
private void printAppletPage(HttpServletRequest req,
HttpServletResponse res)
throws IOException {
PrintWriter out = res.getWriter();

out.println("<HTML>");
out.println("<HEAD><TITLE>An Absurdly Simple Chat</TITLE></HEAD>");
out.println("<BODY>");
out.println("<H1>An Absurdly Simple Chat</H1>");

String method = req.getParameter("method");
String user = req.getRemoteUser();
String applet = null;

if ("http".equals(method)) {
applet = "HttpChatApplet";
}
else if ("socket".equals(method)) {
applet = "SocketChatApplet";
}
else if ("rmi".equals(method)) {
applet = "RMIChatApplet";
}
else {
// No method given, or an invalid method given.
// Explain to the user what we expect.
out.println("Sorry, this servlet requires a <TT>method</TT> " +
"parameter with one of these values: " +
"http, socket, rmi");
return;
}

// Print the HTML code to generate the applet.
// Choose the applet code based on the method parameter.
// Provide a user parameter if we know the remote user.
out.println("<APPLET CODE=" + applet + " CODEBASE=/ " +
"WIDTH=500 HEIGHT=170>");
if (user != null)
out.println("<PARAM NAME=user VALUE=\"" + user + "\">");
out.println("</APPLET>");

out.println("</BODY></HTML>");
}
}






Nothing here should surprise you. In fact, we expect this code to
appear refreshingly simple after the ChatServlet
example. Still, this example does demonstrate one last form of

applet-servlet communication: servlet-generated applet
parameters. Using this technique, a servlet generates a page that
contains an applet and passes information to the applet by
manipulating the applet's <PARAM>
tags. Any information the servlet wants to send to a new applet can be
sent this way. In this example, the servlet sends the name returned by
req.getRemoteUser(). In another example, a servlet
could tell the applet its browser type by sending it the string
returned by req.getHeader("User-Agent"). Or, to be
more helpful, the servlet could use a database to determine the
capabilities of the browser and tell the applet exactly what it needs
to know. It could even tell the applet whether the browser supports
RMI communication.


refer: http://www.unix.com.ua/orelly/java-ent/servlet/ch10_03.htm#ch10-34482

วันเสาร์ที่ 8 พฤศจิกายน พ.ศ. 2551

webservice กับ web application ต่างกันอย่างไร??

ต่างกัน อันเนื่องจากจุดกำเนิด และ จุดประสงค์ของทั้งสองอย่างนั้น ต่างกัน Web Services นั้นเกิดมาจากการที่ Web Application ถูกพัฒนาได้จากหลาย ภาษา เช่น asp jsp php perl .... ทำให้การที่จะนำมารวมเพื่อร่วมทำงานด้วยกันนั้นเป็นเรื่องที่ยากลำบาก (เหมือนคุยกันคนละภาษา) Web Services จึงเหมือนกับภาษาสากล ที่ทำให้แต่ละ Web Application ทำงานร่วมกันได้ โดยผ่าน SOAP ที่มี รูปแบบเป็น XML ซึ่งเป็นเหมือนภาษาอังกฤษ เครื่องมือที่ใช้ในการสร้าง Web Services นั้น มีหลายตัว อาทิ เช่น AXIS วิธีทำนั้นก้อไม่ยาก ยิ่งถ้าใช้ IDE จะง่ายมากแค่ คลิ้กๆ ไม่กี่ทีก้อเสร็จแล้ว ความท้าทายไม่ได้อยู่ที่การสร้าง แต่กลับอยู่ที่การนำไปใช้มากกว่า

จากประสบการณ์ ณ ขณะนี้ ที่ใช้อยู่ พบปัญหาอยู่บ้าง เนื่องจากว่า SOAP นั้น จะวิ่งอยู่บน HTTP .... ทำให้ต้องเสีย overhead ในการ encode และ decode ข้อมูล (ถึงแม้ จะไม่กี่ millisecond ก้อตาม แต่เมื่อรวมกันเยอะๆ ก้อเป็น วินาที เหมือนกัน) ยิ่งถ้า บน HTTPS ละก้อไม่ต้องพูดถึงเลย จึงอยากจะบอกไว้ว่า ถ้าต้องการพัฒนา application ที่ต้องการความเร็วแล้ว ขอให้คิดมากๆ ก่อนที่จะใช้ Web Services ครับ

เทคโนโลยีพื้นฐานของ Web Service

เทคโนโลยีพื้นฐานของ Web Service ก็คือ XML กับ HTTP ซึ่งจะพบว่า HTTP ก็เป็นที่รู้จักกันดี และไปได้ทั่วทุกแห่งที่มี internet ส่วน XML คือภาษาสากลที่คุณสามารถปรับแต่งได้ตามใจชอบ เพื่อให้เกิดกิจกรรมระว่าง client และบริการ หรือระหว่างส่วนประกอบต่างๆ เบื้องหลัง Web server ก็คือ ข้อความ XML จะถูกแปลงให้การขอบริการจาก Middle ware และผลที่ได้ก็จะแปลงกลับมาในรูป XML ยกตัวอย่างให้เห็นง่ายๆ คุณต้องการให้เครื่อง PC อ่านค่าจาก serial port แล้วส่งไปประมวลผลบนเครื่อง UNIX แล้วส่งผลกลับมาแสดงบนจอ PC ถ้าเป็นเมื่อก่อน คุณก็คงต้องแปลงข้อมูลที่ได้ให้อยู่ในรูปของ ASCII แล้วส่งไปยัง UNIX พร้อมคำสั่งว่าให้ทำอะไร ในฝั่ง UNIX คุณก็ต้องมาแยกว่าอันไหนคือคำสั่ง อันไหนคือข้อมูล เมื่อประมวลผลแล้ว จะส่งกลับมาในรูปแบบไหน แล้วถ้าหากจะส่งไปหาเครื่องที่เป็น MAC ท่านจะต้องเขียนโปรแกรมเพิ่มในส่วนไหนบ้าง จะพบว่าเราต้องพัฒนากันเป็นคู่ๆ ไป และต้องนิยามในแต่ละฝั่งให้ชัดเจน แต่หากเป็น Web Service คุณจะพบว่า เราแปลงข้อมูลให้อยู่ในรูป XML แต่ละคุณก็ต้องการรู้แค่ มาตรฐาน XML ก็พอ แล้วต่างคนต่างก็เขียน Service ของตัวเอง ไม่ต้องกังวลเรื่องของการเชื่อมโยงอีกต่อไป และ Protocol ที่ส่งก็คือ HTTP นั่นเอง ถ้าท่านเชื่อมโยงกับ HTTP (หรือเว็บ) ได้ ท่านก็ใช้บริการทุกอย่างได แต่การเข้าถึงและการสั่งงานนั้นยังเป็นเพียงโครงสร้างพื้นฐาน แต่ในความเป็นจริงยังมีอะไรมากกว่านั้น เช่น การค้นหา การทำธุรกรรม ความปลอดภัย การพิสูจน์ตัวตน และอื่นๆ อันเป็นบริการที่ทำให้เป็นบริการพื้นฐานจริงๆ ระบบเพิ่มเติมที่ต้องมีและต้องรักษาความสะดวกและใช้งานง่ายไว้ด้วย พื้นฐานของ Web Service เต็มรูปแบบคือ XML + HTTP + SOAP + WSDL + UDDI หรือในระดับสูงกว่านั้น แต่ไม่ได้ถือเป็นสิ่งจำเป็นเสมอไปคือต้องเพิ่มเทคโนโลยี XAML, XLANG, XKMS, XFS เป็นต้น ต่อไปนี้คือรายละเอียดคร่าวๆ ของแต่ละส่วน แต่ควรตระหนักว่าแต่ละส่วนอาจจะยังเป็นเทคโนโลยี ที่กำลังอยู่ระหว่างพัฒนา ดังนั้นในแต่ละปัญหาอาจจะแก้ได้หลายวิธีด้วยกัน SOAP (Remote Invocation) สั่งงานจากระยะไกลUDDI บริการ DirectoryWSDL ระบุคุณสมบัติของแต่ละบริการXLANG/XAML กรณีของการเชื่อมโยงที่ซับซ้อน หลายๆ เว็บXKMS (XML Key Management Specification) ระหว่างการพัฒนา (Microsoft + Verisign)

วันอังคารที่ 4 พฤศจิกายน พ.ศ. 2551

เว็บเซอร์วิส และพื้นฐานการสร้างเว็บเซอร์วิส web service

เว็บเซอร์วิส และพื้นฐานการสร้างเว็บเซอร์วิส


สารบัญ


ส่วนที่ 1 สำหรับบุคคลทั่วไปและผู้พัฒนาเว็บ


อะไรคือเว็บเซอร์วิส

  1. เว็บเซอร์วิส คือสิ่งทำให้แอพพลิเคชั่นของคุณ กลายเป็นเว็บแอพพลิเคชั่น


  2. เว็บเซอร์วิส ทำให้แอพพลิเคชั่นอื่น บนคอมพิวเตอร์เครื่องอื่น เรียกใช้งาน
    แอพพลิเคชั่นของคุณได้ แม้ว่าจะอยู่บนเครื่องคอมพิวเตอร์ คนละแพลตฟอร์ม หรือใช้ภาษาที่ใช้พัฒนาแอพพลิเคชั่นต่างกันก็ตาม

แล้วเว็บเซอร์วิสคืออะไรล่ะ ?



เว็บเซอร์วิส คือแอพพลิเคชั่น ที่ถูกสร้างให้รอรับการเรียกใช้งานจากแอพพลิเคชั่นอื่นบนอินเตอร์เน็ต
โดยสื่อสารกันด้วยข้อมูลที่อยู่ในรูปแบบ XML ซึ่งรูปแบบ XML ที่ใช้นี้ ถูกกำหนดเป็นมาตรฐานชื่อว่า
SOAP โดยข้อมูลอาจถูกส่งผ่านทางโปรโตคอล HTTP ,SMTP หรือ FTP แต่ที่นิยมใช้มาก
คือ HTTP

เว็บเซอร์วิส ประกอบด้วยอะไรบ้าง ?



  • แอพพลิเคชั่น - โปรแกรมที่ทำหน้าที่ให้บริการ
  • SOAP - โปรโตคอลที่ใช้ในการสื่อสารระหว่างแอพพลิเคชั่น
  • WSDL - ไฟล์ที่เก็บวิธีการเรียกใช้งาน
    Web Service
  • UDDI - ไดเรกทอรีที่รวบรวม WSDL จำนวนมากเข้าไว้ด้วยกัน

ส่วนประกอบของเว็บเซอร์วิส

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

ตัวอย่างของภาษาที่มีโมดูลสำหรับจัดการกับ SOAP ให้ใช้งาน ได้แก่


SOAP คืออะไร


SOAP(Simple Object Access Protocol) - คือโปรโตคอลหรือระเบียบวิธีในการสื่อสารระหว่างเว็บเซอร์วิส
โดยใช้ข้อมูลที่กำหนดรูปแบบด้วยภาษา XML ทำให้เว็บเซอร์วิสสามารถสื่อสารกันได้แม้ว่า
จะอยู่บนเครื่องคอมพิวเตอร์คนละเพลตฟอร์ม หรือพัฒนาด้วยภาษาโปรแกรมที่ต่างกันก็ตาม

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

ตัวอย่างของ SOAP messages

จากตัวอย่างข้างล่าง เป็น SOAP message ที่จะไปเรียกใช้เว็บเซอร์วิส ของห้องสมุด
เพื่อถามข้อมูลเกี่ยวกับหนังสือที่มีรหัสตรงกับ 954839

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<getProductDetails xmlns="http://library.example.com/ws">

<bookID>954839</bookID>

</getProductDetails>

</soap:Body>

</soap:Envelope>

</code>

และตัวอย่างต่อไปนี้คือ SOAP message ที่ถูกส่งกลับมาจากเว็บเซอร์วิสของห้องสมุด
ซึ่งมีข้อมูลเกี่ยวกับชื่อหนังสือ คำอธิบาย ชื่อผู้แต่ง และสถานะของหนังสือ

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<getBookDetailsResponse xmlns="http://library.example.com/ws">

<getBookDetailsResult>

<bookName>Web Service by Truehits</bookName>

<bookID>954839</bookID>

<description>Web Service Quick Guide
for Developer.
</description>


<author>Sorrawut Korsuwansiri</author>

<inStock>true</inStock>

</getBookDetailsResult>

</getBookDetailsResponse>

</soap:Body>

</soap:Envelope>

</code>

WSDL คืออะไร ?




Web Services Description Language (WSDL) คือ เอกสาร XML ที่อธิบายรายละเอียดในการติดต่อกับเว็บเซอร์วิส
เพื่อให้ แอพพลิเคชั่นที่ต้องการเรียกใช้เว็บเซอร์วิสรู้ว่าเซอร์วิสนั้นให้บริการอะไรบ้าง
และจะติดต่อได้อย่างไร

เพื่อให้เข้าใจบทบาทของ WSDL ได้เร็วขึ้น ผมขอยกตัวอย่างการเรียกใช้เว็บเซอร์วิส
แบบไม่ใช้ WSDL เปรียบเทียบกับแบบที่เรียกใช้เว็บเซอร์วิสผ่าน WSDL

แบบที่ 1 เรียกใช้เว็บเซอร์วิส โดยไม่ใช้ WSDL

<?php




$client
= new SoapClient(NULL,


array(

"location"
=> "http://64.124.140.30:9090/soap",


"uri" =>
"urn:xmethods-delayed-quotes",


"style" =>
SOAP_RPC,

"use" =>
SOAP_ENCODED

));




print(
$client->__call(


/*
SOAP Method Name */

"getQuote",


/*
Parameters */

array(


new
SoapParam(

/*
Parameter Value */

"ibm",


/*
Parameter Name */

"symbol"


)),


/*
Options */

array(


/*
SOAP Method Namespace */

"uri"
=> "urn:xmethods-delayed-quotes",


/*
SOAPAction HTTP Header for SOAP Method */

"soapaction"
=> "urn:xmethods-delayed-quotes#getQuote"


)).
"\n");

?>


จากตัวอย่างข้างต้น ผู้ที่จะเรียกใช้งานเว็บเซอร์วิสจะต้องกำหนด ค่าต่างๆเกี่ยวกับการใช้งานเว็บเซอร์วิสเข้าไปเอง
เช่น



  • ชื่อฟังก์ชั่น (getQuote)
  • URL ของเว็บเซอร์วิส (http://64.124.140.30:9090/soap)
  • SOAPAction header (urn:xmethods-delayed-quotes#getQuote)
  • namespace URI (urn:xmethods-delayed-quotes)
  • ชื่อของ Input และ output ของข้อมูล (symbol)

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

ทีนี้ลองมาดูการเรียกใช้งาน Web Service โดยใช้ wsdl กันบ้าง

แบบที่ 2 เรียกใช้เว็บเซอร์วิส โดยใช้ WSDL

<?php


$client
= new

SoapClient(


"http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl"


);



print(
$client->getQuote("ibm"));


?>


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

จากการเปรียบเทียบตัวอย่างทั้งสองที่ยกมาข้างต้น จะเห็นว่า WSDL ช่วยให้การเรียกใช้งานเว็บเซอร์วิส
สะดวกขึ้นมากทีเดียว ส่วนเนื้อหาภายในไฟล์ WSDL นั้น ผู้อ่านสามารถเข้าไปดูได้ที่
URL

http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl

ซึ่งรายละเอียดโครงสร้างภายในไฟล์ WSDL จะเป็นอย่างไรนั้น จะขอยกไปอธิบายในเรื่องการสร้างบริการเว็บเซอร์วิส
ในภายหลัง

UDDI คืออะไร


UDDI (Universal Description, Discovery and Integration) เป็นไดเรกทอรี ที่เก็บรวบรวม
Web Service ที่มีการลงทะเบียนไว้ ซึ่งอาจรวมไปถึงบริการอื่นๆที่เป็นอิเลคทรอนิกส์
และไม่เป็นอิเลคทรอนิกส์ด้วย UDDI จะเก็บรวบรวมข้อมูลของ Web Service ต่างๆไว้ในรูปแบบ
WSDL

หน้าที่ของ UDDI จะคล้ายกับ เว็บไดเรกทอรี กล่าวคือ UDDI ช่วยให้ผู้พัฒนา Web
Service ได้ประกาศหรือประชาสัมพันธ์บริการของตนเองสู่สาธารณะ และช่วยให้ผู้ใช้
Web Service ค้นพบ Web Service ที่ต้องการใช้งาน


ส่วนที่ 2 สำหรับผู้สนใจการพัฒนาบริการเว็บเซอร์วิส


การพัฒนาบริการเป็นเว็บเซอร์วิสด้วย PHP 5.0


ความจริงแล้วมีหลายภาษาที่สามารถนำมาพัฒนาเป็นเว็บเซอร์วิสได้ แต่ในบทความนี้จะขอแนะนำการพัฒนาด้วยภาษา
php เวอร์ชั่น 5.0 ขึ้นไป เนื่องจาก PHP 5.0 เป็นของฟรี และมีการใช้งานเป็นที่แพร่หลายอยู่แล้ว

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

ฟังก์ชั่นบวกเลข แอพพลิเคชั่นแรกที่จะทำให้เป็นเว็บเซอร์วิส

plus_server.php

<?php



function plus($num1,&num2)
{


return $num1+$num2;


}

?>

จากโค้ดข้างต้นเป็นฟังก์ชั่นบวกเลขง่ายๆ ที่เขียนด้วยภาษา php
ที่รับพารามิเตอร์เป็นตัวแปรสองตัว เอามาบวกกันแล้วส่งค่ากลับเป็นเอาต์พุต

ในขั้นต่อไปเราจะเอาฟังก์ชั่นนี้มาทำให้มันรับและส่งข้อมูลด้วย SOAP

plus_server.php

<?php



function plus($num1,$num2)
{


return $num1+$num2;


}




$server = new SoapServer("plus.wsdl");


$server->addFunction("plus");


$server->handle();


?>


คำสั่ง new SoapServer()
เป็นการสร้างออบเจ็กต์ SoapServer โดยระบุ wsdl ไปที่ไฟล์ plus.wsdl

addFunction("plus") เป็นการเพิ่มฟังก์ชั่น
plus() ลงในอ็อบเจกต์ SoapServer ซึ่งชื่อของฟังก์ชั่นและพารามิเตอร์ของฟังก์ชั่น
(num1 และ num2) จะต้องตรงกับที่จะระบุใน plus.wsdl

handle() เป็นคำสั่งที่ใช้ควบคุมเว็บเซอร์วิส คือควบคุมให้ออบเจ็กต์
SoapServer รอรับ SoapRequest เมื่อประมวลผลเสร็จก็ส่ง SoapResponse กลับไป

การสร้างไฟล์ wsdl

ต่อไปคือการสร้างไฟล์ plus.wsdl ไฟล์ wsdl มีหน้าที่ในการประกาศ ว่าเว็บเซอร์วิสนั้นให้บริการอะไรบ้าง
และจะติดต่อได้อย่างไร มีพารามิเตอร์อะไรบ้าง ซึ่ง plus.wsdl มีรายละเอียดดังนี้

ไฟล์ plus.wsdl

จากไฟล์ wsdl ข้างต้น จะเห็นว่าไฟล์ wsdl มีโครงสร้างดังนี้

------- <message>-------

<message name='plusRequest'>

<part name='num1' type='xsd:float'/>

<part name='num2' type='xsd:float'/>

</message>

<message name='plusResponse'>

<part name='Result' type='xsd:float'/>

</message>

เป็นส่วนที่กำหนด messages ที่ใช้ในการติดต่อระหว่าง Client กับเว็บเซอร์วิส
ในตัวอย่างนี้ มี 2 messages คือ


  1. plusRequest เป็น messege ที่ประกอบด้วยข้อมูลชนิด float 2 ตัวคือ num1 และ
    num2
  2. plusResponse เป็น messege ที่ประกอบด้วยข้อมูลชนิด float 1 ตัวคือ Result

------- <portType>-------

<portType name='plusPortType'>

<operation name='plus'>

<input message='tns:plusRequest'/>

<output message='tns:plusResponse'/>

</operation>

</portType>

เป็นส่วนกำหนดโอเปอร์เรชั่น (ฟังก์ชั่นที่เรียกใช้งานได้) และประกาศ messages
ที่ ใช้เป็นอินพุตและเอาต์พุตของโอเปอร์เรชั่น ในตัวอย่างนี้คือการประกาศโอเปอร์เรชั่น
plus โดยมี plusRequest messages เป็นอินพุต และ plusResponse เป็น เอาต์พุต

------- <binding>-------

<binding name='plusBinding' type='tns:plusPortType'>

<soap:binding style='rpc'

transport='http://schemas.xmlsoap.org/soap/http'/>

<operation name='plus'>

<soap:operation soapAction='urn:xmethods-delayed-quotes#plus'/>

<input>

<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'

encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>

</input>

<output>

<soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'

encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>

</output>

</operation>

</binding>

ส่วน binding เป็นการกำหนดว่า messages จะถูกส่งและเข้ารหัสอย่างไร ในที่นี้เรากำหนดให้ส่ง
RPC (Remote Procedure Call) โดยใช้ SOAP บน HTTP นอกจากนี้ยังมีการ กำหนด namespace
และ SOAPAction header สำหรับเมธอด plus() อีกด้วย


------- <service>-------

<service name='plusService'>

<port name='plusPort' binding='plusBinding'>

<soap:address location='http://truehits.net/faq/webmaster/webservice/plus_server.php'/>

</port>

</service>

ส่วน service เป็นส่วนที่กำหนด URL ของเว็บเซอร์วิส

------- <Type>-------

บางครั้งท่านอาจพบ wsdl บางตัวมีการใช้ message สำหรับส่งตัวแปร ที่นอกเหนือไปจากชนิดตัวแปรทั่วไป
wsdl จะใช้ xml schema ในการประกาศชนิดตัวแปรด้วย <Type>

ทดลองสร้าง Client สำหรับติดต่อกับเว็บเซอร์วิส

เมื่อเราสร้างเว็บเซอร์วิสฝั่งผู้ให้บริการเสร็จแล้ว ต่อไปคือการ ทดลองสร้างแอพพลิเคชั่น
ที่เรียกใช้งาน WebService ซึ่งจะเรียกใช้งานผ่านทาง plus.wsdl

plus.php

<?php

$client = new SoapClient("plus.wsdl");

print($client->plus(5,6));

?>


ผลการรัน plus.php

ไฟล์นี้จะไปติดต่อกับ plus.wsdl เพื่อสร้างออบเจ็กต์ $client ขึ้นมาสำหรับเรียกใช้งานเว็บเซอร์วิส
จากนั้นก็ใช้เมธอด plus() ในการบวกเลข ซึ่ง 5 และ 6 จะถูกส่งไปประมวลผลที่เซิฟเวอร์
เมื่อเซิฟเวอร์ประมวลผลเสร็จ ก็จะส่งกลับมาให้ออบเจ็กต์ $client ซึ่งออบเจ็กต์
$client จะเป็นคนจัดการการรับ-ส่งข้อมูลผ่าน SOAP ให้เรา

แอบดู SOAP message

ถึงตรงนี้บางท่านคงจะสงสัยว่า SOAP messages ที่ส่งไปส่งมา ระหว่างเว็บเซอร์วิสและฝั่ง
client นั้น จริงๆแล้ว เป็นอย่างไร ซึ่งบทความนี้ก็ได้ยกตัวอย่างของ SOAP messages
ไปแล้วในตอนต้น แต่เพื่อความเข้าใจมากขึ้นจะขอแนะนำเมธอด SoapClient->__getLastRequest()
และ SoapClient->__getLastResponse()
สำหรับแอบดู SOAP message ของเว็บเซอร์วิสบวกเลขนี้อีกครั้งหนึ่ง

plus2.php

<?php

$client = new SoapClient("plus.wsdl",array(


"trace" =>
1,

"exceptions"
=>
0));

$client->plus(5,6);

print "<pre>\n";


print "Request :\n".htmlspecialchars($client->__getLastRequest())
.
"\n";

print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n";


print "</pre>";


?>


ผลการรัน plus2.php

จากตัวอย่างข้างต้น SoapClient->__getLastRequest()
ใช้สำหรับ เรียกดู SOAP message ที่ส่งไปครั้งล่าสุด SoapClient->__getLastResponse()
ใช้สำหรับ เรียกดู SOAP message ที่ได้รับครั้งล่าสุด






หมายเหตุ : เมธอด (Method) , ฟังก์ชั่น
(Function) , โอเปอร์เรชั่น (operation) เป็นคำที่มีความหมายคล้ายกัน คือเป็นคำสั่งให้เรียกใช้งาน
เหมือนกัน แต่ต่างกันตรงที่ เมธอด เป็นคำเรียกฟังก์ชั่นที่อยู่ในออบเจกต์
ส่วนโอเปอร์เรชั่น เป็นฟังก์ชั่นที่เปิดให้บริการ ผ่านเว็บเซอร์วิส

การเรียกดูฟังก์ชั่นของเว็บเซอร์วิส

ใน php5.0 หากเราต้องการทราบว่าเว็บเซอร์วิสนั้นมีโอเปอร์เรชั่นอะไรให้เรียก
ใช้บ้าง ก็สามารถเรียกดูได้ด้วยฟังก์ชั่น SoapClient->__getFunctions() ดังตัวอย่าง

plus3.php

<?php

$client = new SoapClient("plus.wsdl");

var_dump($client->__getFunctions());

?>


ผลการรัน plus3.php

ข้อมูลอ้างอิง

Apache
Axis USer Guide


PHP
SOAP Extension โดย Dmitry Stogov


SOAP Function
From PHP Offical site


SOAP Tutorial
By W3School


Web
Service Tutorial By W3School


WSDL Tutorial
By W3School