วันพฤหัสบดีที่ 23 มีนาคม พ.ศ. 2560

สร้าง PHP ทำหน้าที่เป็น TCP server รองรับจำนวนลูกข่ายมากกว่า 10 เครื่องพร้อมกัน

บทความนี้ผู้เขียนใช้เวลาทดสอบมายาวนานกว่า 3 เดือนและสามารถใช้งานได้จริงรองรับจำนวนลูกข่ายเข้ามาแอคเซสในเวลาเดียวกันมากกว่า 10 เครื่องพร้อมกัน  การเขียนโปรแกรมแบบซ็อกเกต(socket)เพื่อรองรับจำนวนลูกข่ายเข้ามาใช้งานพร้อม ๆ กันสามารถทำได้อยู่หลายวิธีด้วยกัน แต่ที่พบมากมีอยู่ 3 แบบคือ forking หรือการสร้างโพรเซสลูก, threading หรือการทำงานพร้อม ๆกันยังไม่มีใน php และ select methods เป็นการรอเพื่ออ่านค่าเฉพาะที่มีการส่งมาจากลูกข่าย

สำหรับเนื้อหานี้จะใช้วิธีการที่เรียกว่า select methods โดยฟังก์ชั่น select จะทำงานเฉพาะเมื่อมีกิจกรรมเกิดขึ้นหรือมีการส่งข้อมูลจากฝั่งเครื่องลูกข่ายมายังเซิร์ฟเวอร์นั่นเอง โค๊ดเบื้องต้นผู้เขียนพัฒนาจากอินเทอร์เน็ต เน้นว่าเป็นสคริปง่าย ๆ สะดวกต่อการทำความเข้าใจ ไม่ต้องการไลบราลี่หรือสร้างเป็นคลาสให้ยุ่งยาก

<?php
        error_reporting(E_ALL);
        set_time_limit(0);
        ob_implicit_flush();
        $address = "0.0.0.0";
        $port = "4444";
        $client_socks = array();
        if (($server = socket_create(AF_INET, SOCK_STREAM,0))===false){
                echo "socket_create() failed: reason: ".socket_strerror(socket_last_error())."\n";
                die('something went wrong while creating');
        };
        if (socket_bind($server,$address,$port)===false){
                echo "socket_bind() failed: reason: ".socket_strerror(socket_last_error())."\n";
                die('something went wrong while binding');
        };
        if (socket_listen($server)===false){
                echo "socket_listen() failed: reason: ".socket_strerror(socket_last_error())."\n";
                die('something went wrong while listening');
        };
        while(true){
                //prepare readable sockets
                $read_socks = $client_socks;
                $read_socks[] = $server;
                //start reading and use a large timeout
                if(!socket_select ( $read_socks, $write, $except, 300000 )){
                        die('something went wrong while selecting');
                }
                //new client
                if(in_array($server, $read_socks)){
                        $new_client = socket_accept($server);
                        if ($new_client) {
                                //print remote client information, ip and port number
                                //echo 'Connection accepted from ' . socket_getsockname($new_client, true) . "n";
                                $client_socks[] = $new_client;
                                echo "Now there are total ". count($client_socks) . " clients.n";
                        }
                        //delete the server socket from the read sockets
                        unset($read_socks[ array_search($server, $read_socks) ]);
                }
                //message from existing client
                foreach($read_socks as $sock) {
                        $data = socket_read($sock, 128);
                        if(!$data){
                                unset($client_socks[ array_search($sock, $client_socks) ]);
                                socket_close($sock);
                                echo "A client disconnected. Now there are total ". count($client_socks) . " clients.n";
                                continue;
                        }
                        //send the message back to client
                        socket_write($sock, $data);
                }
        }


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

ต้องขอขอบพระคุณ บจก.ไทย พรอสเพอรัส ไอที ผู้นำด้านการให้บริการระบบจีพีเอสติดตามรถยนต์ รู้ลึกรู้จริงเรื่องติดตาม บริหารงานโดยทีมงานวิศวกร

1 ความคิดเห็น: