25 สิงหาคม 2557

[Android Code] การใช้งาน Simple TCP Library แบบ Simple TCP


        สำหรับ Simple TCP Library เป็นไลบรารีสำหรับการส่งข้อมูลผ่าน TCP ที่เจ้าของบล็อกได้เกริ่นไว้ในบทความก่อนหน้านี้แล้ว [Android Code] Simple TCP Library - ลากันที TCP ที่ยุ่งยาก โดยตั้งใจทำขึ้นมาเพื่อให้ผู้ที่หลงเข้ามาอ่านสามารถทำแอปพลิเคชันแอนดรอยด์ที่ส่งข้อมูลระหว่างวงแลนด้วยกันได้สะดวกยิ่งขึ้น


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

        สำหรับ Simple TCP จะเป็นการส่งข้อมูลแบบชุดเดียวจบ ก็คือเชื่อมต่อกับปลายทางแล้วส่งข้อมูลจนเสร็จแล้วก็หยุดเชื่อมต่อกันทันที เอาไว้ส่งข้อมูลสั้นๆง่ายๆไปที่ปลายทางโดยไม่ต้องการเชื่อมต่อด้วยกันตลอดเวลา






        โดยที่ Simple TCP จะมีคลาสอยู่ด้วยกันสองตัวคือ SimpleTCPClient และ SimpleTCPServer เอาไว้สำหรับการทำงานแบบ Server - Client นั่นเอง สามารถให้ฝั่งใดฝั่งหนึ่งเป็น Server แล้วอีกฝั่งเป็น Client ก็ได้ หรือว่าจะให้ทั้งคู่เป็น Server และ Client พร้อมๆกันก็ได้เช่นกัน เพราะทำเป็นคลาสแยกจากกัน

        ก่อนอื่นเลย การใช้งาน SimpleTCPLibrary จะต้องมีการประกาศ Permission ดังนี้

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />


SimpleTCPServer

        ในการประกาศใช้งานคลาส SimpleTCP ในส่วนของ Server จะประกาศง่ายๆดังนี้

SimpleTCPServer server = new SimpleTCPServer(PORT); 

        PORT คือ Port ที่จะเปิดใช้งาน เช่น 2000, 5555, 21111 เป็นต้น โดยที่ Server เปิด Port ใด เวลาที่ฝั่ง Client เชื่อมต่อก็จะต้องกำหนด Port ให้ตรงด้วย ไม่งั้นต่อให้ IP ถูกต้องแต่ Port ไม่ตรง ก็ส่งข้อมูลไม่ได้อยู่ดี

        และสำหรับ SimpleTCP จะประกอบไปด้วยคำสั่งดังนี้

void start();
void stop();

boolean isRunning();
int getPort();

void setOnDataReceivedListener(OnDataReceivedListener listener);

        คำสั่งน้อยดีใช่มั้ยล่ะ! โดยการเริ่มต้นใช้งานก็จะประมาณนี้

SimpleTCPServer server;

protected void onCreate(Bundle savedInstanceState) {
    ....
    ....
    ....
    server = new SimpleTCPServer(21111); 
    ....
    ....
    ....
}

public void onResume() {
    super.onResume();
    ....
    ....
    ....
    server.start();
}

public void onStop() {
    super.onStop();
    ....
    ....
    ....
    server.stop();
}

        โดยประกาศเรียกใช้งาน SimpleTCPServer ที่ onCreate จากนั้นก็เรียกคำสั่ง start เพื่อให้ Server เริ่มทำงานที่ onResume และ stop เพื่อให้ Server หยุดทำงานที่ onStop

        เวลามีข้อมูลส่งเข้ามาล่ะจะทำยังไง? ซึ่งในส่วนนี้เจ้าของบล็อกก็ใส่ Listener ไว้ให้ใช้งานง่ายๆแล้ว โดยมีชื่อว่า OnDataReceivedListener
SimpleTCPServer server;

protected void onCreate(Bundle savedInstanceState) {
    ....
    ....
    ....
    server = new SimpleTCPServer(21111); 
    server.setOnDataReceivedListener(new OnDataReceivedListener() {
        public void onDataReceived(String message, String ip) {
            // คำสั่งใดๆ เมื่อมีการรับข้อมูลเข้ามา
        }
    });
    ....
    ....
    ....
}

public void onResume() {
    super.onResume();
    ....
    ....
    ....
    server.start();
}

public void onStop() {
    super.onStop();
    ....
    ....
    ....
    server.stop();
}

        ดังนั้นเวลาที่ Client ส่งข้อมูลใดๆเข้ามา ก็จะเข้ามาใน onDataReceived เพื่อนำข้อมูลไปใช้งาน โดยข้อมูลที่ว่าจะอยู่ในรูปของ String ที่ตั้งชื่อไว้ว่า message และมี IP ส่งมาให้ด้วยเพื่อให้รู้ว่าข้อมูลที่ส่งมานั้นมาจาก IP อะไร ซึ่งก็อยู่ในรูป String เช่นกัน และตั้งชื่อไว้ว่า ip

        เท่านี้อุปกรณ์แอนดรอยด์ก็พร้อมจะทำงานเป็น Server แล้ว! และคำสั่งที่เหลือก็จะมีไว้เผื่อกรณีที่ผู้ที่หลงเข้ามาอ่านต้องการตรวจสอบข้อมูลบางอย่าง

        isRunning เอาไว้ใช้ว่า Server ยังทำงานอยู่หรือป่าว

        getPort เช็คว่า Server ใช้ค่า Port เท่าไร (ค่าเดียวกันกับตอนที่กำหนดใช้งาน)


       เมื่อ Server พร้อมใช้งานแล้ว ทีนี้มาดูการเรียกใช้งานในส่วนของ Client กันบ้างดีกว่า ซึ่งบอกได้เลยว่า ง่ายมากกกกกกกกกกกกก


SimpleTCPClient

        Client หรือก็คือฝั่งที่จะส่งข้อมูลไปยังฝั่ง Server นั่นเอง ซึ่งไม่ต้องประกาศอะไร เจ้าของบล็อกทำให้เรียกใช้งานได้ทันที!!! เพราะว่าเจ้าของบล็อกสร้างคำสั่งเป็นแบบ Static ไว้ โดยมีคำสั่งให้ใช้งานทั้งหมดดังนี้

void send(String message, String ip, int port);
void send(String message, String ip, int port, SendCallback callback, String tag);

        จะเห็นว่าคำสั่งที่ใช้มีแค่ send แต่ทว่า Overload ไว้สองแบบด้วยกัน เริ่มจากแบบที่ง่ายที่สุดก่อนละกันคือแบบแรกสุด

SimpleTCPClient.send(message, ip, port);

        นี่แหละครับ คำสั่งที่ใช้ส่งข้อมูลไปยังเป้าหมายที่ต้องการ ไม่ต้องประกาศอะไร อยากส่งก็ใช้คำสั่งนี้เลย กำหนดข้อความที่ต้องการ กำหนด IP และ Port ของเป้าหมายให้ถูกต้อง เท่านี้ก็ส่งข้อมูลได้แล้ว

button.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        SimpleTCPClient.send("Hello World", "192.168.1.33", "21111");
    }
});

        เรียกได้เลยว่าชีวิตนี้ง่ายขึ้นเยอะ

        แต่ทว่าคำสั่งแบบแรกจะไม่สามารถรู้ได้ว่าข้อมูลส่งไปถึงปลายทางจริงๆหรือป่าว ดังนั้นเจ้าของบล็อกจึง Overload คำสั่งเพิ่มขึ้นมานั่นเอง เพื่อให้มีการส่งความสั้นๆจาก Server กลับมาว่า "ได้รับข้อมูลแล้วนะ" ซึ่งคำสั่ง send แบบที่สองก็จะมี Callback เพิ่มเข้ามาเพื่อให้ตรวจสอบในจุดนี้ได้

SimpleTCPClient.send(message, ip, port, SendCallback callback, String tag);

        จะเห็นว่ามีเพิ่มเข้ามาสองตัวด้วยกันคือ callback กับ tag ขอเริ่มอธิบายจาก tag ก่อนละกัน

        tag อันนี้เป็นส่วนที่เพิ่มเข้ามาเพื่อให้ชีวิตนั้นง่ายขึ้น (ขนาดนั้นเชียว?) มีไว้ทำให้ผู้ที่หลงเข้ามาอ่านรู้ได้ว่า Callback ที่เกิดขึ้นเป็นของข้อความไหน เพราะลองนึกภาพว่าผู้ที่หลงเข้ามาอ่านส่งข้อความไปสามตัวด้วยกัน

                "AAA"
                "BBB"
                "CCC"

        เนื่องจากส่งทั้งหมดสามตัว ดังนั้นก็จะมีการเรียกใช้คำสั่ง send ทั้งหมดสามครั้ง เมื่อมี Callback กลับเข้ามาก็จะเกิดขึ้นทั้งหมดสามครั้งเช่นกัน แต่ทว่า

        จะรู้ได้ไงว่า Callback ที่ส่งกลับมาในแต่ละครั้ง เป็นของตัวไหน?

        ดังนั้นเจ้าของบล็อกจึงสร้างสิ่งที่เรียกว่า Tag ขึ้นมา เพื่อที่เวลา Callback ทำงานจะได้เช็คจาก Tag ที่ว่านี้ว่าเป็นข้อมูลตัวไหน เช่น

                Message : "AAA", Tag : "A"
                Message : "BBB", Tag : "B"
                Message : "CCC", Tag : "C"

        เมื่อกำหนด Tag ตอนที่ส่งข้อความต่างกัน เมื่อเกิด Callback ก็จะสามารถเช็คจาก Tag ที่มากับ Callback ได้ว่า Callback ที่เกิดขึ้นเป็นของข้อความตัวไหน โดยเช็คจาก Tag ที่กำหนดไว้นั่นเอง

        callback ที่ใช้ในที่นี้มาจาก SendCallback ที่เจ้าของบล็อกสร้างขึ้นมาไว้เพื่อเอาไว้ส่งผลลัพธ์กลับมาว่าข้อมูลถึงปลายทางจริงๆหรือไม่ เพราะคำสั่ง send ใน Simple TCP เป็นการส่งแบบไม่สนใจปลายทาง คือ นึกจะส่งก็ส่ง แค่กำหนด IP กับ Port ดังนั้นจึงอาจจะเกิดปัญหาส่งไม่ถึงปลายทาง เพราะว่าใส่ข้อมูลผิดหรือว่าปลายทางไม่ได้เปิด Server อยู่เป็นต้น โดยจะมีอยู่สองแบบด้วยกันคือ onSuccess กับ onFailed

SendCallback callback = new SendCallback() {
        public void onSuccess(String tag) {
                // ส่งข้อมูลสำเร็จ
        }

        public void onFailed(String tag) {
                // ส่งข้อมูลไม่สำเร็จ
        }
});

        โดยจะเห็นว่าทั้ง onSuccess และ onFailed จะมี Tag ส่งเข้ามาให้สามารถนำไปเช็คได้ตลอดเวลาว่าเป็นของข้อมูลตัวไหน

        เวลาใช้งานจริงก็จะประมาณนี้

button.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
                SimpleTCPClient.send("Hi everyone"
                                , "192.168.43.155"
                                , 2000, new Callback() {
                        public void onSuccess(String tag) {
                                // เมื่อส่งข้อมูลสำเร็จ
                                // tag ที่ส่งมาในนี้จะเป็น "Hi"
                        }

                        public void onFailed(String tag) {
                                // เมื่อส่งข้อมูลไม่สำเร็จ
                                // tag ที่ส่งมาในนี้จะเป็น "Hi"
                        }
                }, "Hi");
        }
});

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

        ซึ่งแบบที่สองนี้สามารถประยุกต์ใช้ค้นหา IP ของฝั่ง Server ได้เหมือนกันนะ โดยใช้หลักการส่งข้อความกวาดให้ทั่ว เช่น เครื่อง Client มีหมายเลข IP เป็น 192.168.1.3 และอยากรู้ว่าในวงแลนดังกล่าวนี้มีเครื่องไหนเปิด Server ไว้อยู่หรือไม่ ก็จะใช้วิธีส่งข้อความง่ายๆเช่น "Ping" แล้วทยอยส่งข้อความดังกล่าวนี้ตั้งแต่ 192.168.1.1 ไปจนถึง 192.168.1.255 โดยกำหนด Tag เป็นหมายเลข IP ที่ส่ง ดังนั้นเมื่อเกิด onSuccess ขึ้นก็ให้เช็คที่ Tag ก็จะรู้ได้ทันทีว่า IP ใดเปิด Server ไว้อยู่


        จบแล้ว ง่ายๆสั้นๆกับการใช้ SimpleTCPLibrary ในแบบ Simple TCP ที่จะช่วยให้ชีวิตง่ายขึ้นเยอะ โดยสามารถดาวน์โหลดไลบรารีได้ที่

                SimpleTCPLibrary [GitHub]
                SimpleTCPLibrary [Google Drive]
                SimpleTCPLibrary [SleepingForLess]

        โดยจะมีตัวอย่างสำหรับ Simple TCP อยู่ในนี้ 3 ตัวอย่างด้วยกัน

        ตัวอย่างแรกจะเป็นการรับส่งปกติ โดยทั้งสองฝั่งเป็น Server และ Client จะมีช่องให้ใส่ข้อความและ IP ที่จะส่ง ฝั่งที่รับข้อมูลก็จะแสดงข้อมูลผ่าน Toast



        ตัวอย่างที่สองจะทำคล้ายๆกับระบบ Chat มี List View แสดงข้อความที่รับเข้ามา มีช่องให้ใส่ข้อความและ IP ของเป้าหมาย แต่ตัวนี้จะใช้ Callback ด้วย เพราะเมื่อกดส่งจะมีข้อความแสดงสถานะว่าส่งข้อความสำเร็จหรือไม่



        ตัวอย่างที่สามเอาไว้ประยุกต์ใช้ส่งข้อมูลไปสั่งงานไมโครคอนโทรลเลอร์ซะมากกว่า เพราะจะให้ฝั่งหนึ่งเป็น Server และอีกฝั่งเป็น Client เมื่อกดสั่งงานก็จะทำตามคำสั่ง โดยตัวอย่างนี้จะมี Text View แสดงอยู่ และฝั่ง Client จะมีให้เลือกว่าจะให้ข้อความที่ฝั่ง Server เป็นตัวหนา ตัวเอียง หรือเปลี่ยนสีเป็นต้น




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

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


        เขียนให้ขนาดนี้แล้ว ก็เอาไปประยุกต์กันให้เต็มที่หน่อยนะ XD


บทความที่เกี่ยวข้อง

        • [Android Code] Simple TCP Library - ลากันที TCP ที่ยุ่งยาก




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium