কিভাবে প্রোটোকল কাস্টমাইজ করবেন
প্রকৃতপক্ষে, নিজের প্রোটোকল তৈরি করা বেশ সহজ। সাধারণ প্রোটোকলে সাধারণত দুটি অংশ থাকে:
- ডেটা সীমা চিহ্নিত করার চিহ্ন
- ডেটা ফর্ম্যাটের সংজ্ঞা
একটি উদাহরণ
প্রোটোকল সংজ্ঞা
ধরি ডেটা সীমা চিহ্নিত করার চিহ্ন হল newline চরিত্র "\n" (দ্রষ্টব্য: অনুরোধ ডেটার অভ্যন্তরে নিজেই newline চরিত্র থাকতে পারবে না), এবং ডেটার ফর্ম্যাট হল JSON। উদাহরণস্বরূপ, নিচে একটি অনুরোধ প্যাকের উদাহরণ দেওয়া হলো যা এই নিয়মের সাথে মিলে।
{"type":"message","content":"hello"}
দ্রষ্টব্য: উপরের অনুরোধ ডেটার শেষে একটি newline চিহ্ন রয়েছে (PHP-তে ডাবল কোটেশন স্ট্রিং "\n" দ্বারা নির্ধারিত), যা একটি অনুরোধের শেষ নির্দেশ করে।
সম্পাদনের ধাপ
Workerman এ যদি উপরের প্রোটোকল বাস্তবায়ন করতে হয়, ধরি প্রোটোকলের নাম JsonNL, প্রজেক্টটি MyApp, তাহলে নিম্নলিখিত পদক্ষেপগুলি প্রয়োজন:
-
প্রোটোকল ফাইলটি প্রজেক্টের Protocols ফোল্ডারে রাখতে হবে, যেমন ফাইল MyApp/Protocols/JsonNL.php
-
JsonNL ক্লাসটি বাস্তবায়ন করতে হবে,
namespace Protocols;জন্য নামকরণস্থান হিসেবে, এতে অবশ্যই তিনটি স্থিতিশীল পদ্ধতি থাকতে হবে: input, encode, decode
দ্রষ্টব্য: workerman স্বয়ংক্রিয়ভাবে এই তিনটি স্থিতিশীল পদ্ধতি কল করবে, যেগুলি প্যাকেট বিভাজন, ডিকোডিং এবং প্যাক করার জন্য ব্যবহার করা হবে। বিস্তারিত প্রক্রিয়া নিচে সঞ্চালন প্রক্রিয়া ব্যাখ্যার জন্য দেখুন।
Workerman এবং প্রোটোকল ক্লাসের মধ্যে ইন্টারঅ্যাকশন প্রক্রিয়া
- ধরি ক্লায়েন্ট একটি ডেটা প্যাক সার্ভারে পাঠাচ্ছে, সার্ভার ডেটা পেয়ে (সম্ভবত আংশিক ডেটা) তাৎক্ষণিকভাবে প্রোটোকলের
inputপদ্ধতি কল করবে, যা প্যাকটির দৈর্ঘ্য পরীক্ষা করবে,inputপদ্ধতি দৈর্ঘ্য মান$lengthকাজের জন্য প্রেরণ করবে workerman ফ্রেমওয়ার্ককে। - workerman ফ্রেমওয়ার্ক এই
$lengthমানের ভিত্তিতে বর্তমান ডেটা বাফারটির মধ্যে$lengthদৈর্ঘ্যের ডেটা ইতোমধ্যেই এসেছে কি না তা পরীক্ষা করবে; যদি না আসে তবে এটি ডেটার জন্য অপেক্ষা করতে থাকবে যতক্ষণ না বাফারের মধ্যে ডেটার দৈর্ঘ্য$lengthএর তলদেশে না চলে আসে। - বাফারের ডেটার দৈর্ঘ্য যথেষ্ট হলে, workerman বাফার থেকে
$lengthদৈর্ঘ্যের ডেটা কেটে নেবে (অর্থাৎ প্যাকেট বিভাজন), এবং প্রোটোকলেরdecodeপদ্ধতি কল করে ডিকোড করবে, ডিকোডের পরের ডেটা হবে$data। - ডিকোড করার পর workerman ডেটা
$dataকে কলব্যাকেরonMessage($connection, $data)ফরম্যাটে ব্যবসায়ের কাছে পাঠাবে, ব্যবসায় onMessage এর ভিতরে$dataভেরিয়েবল ব্যবহার করে ক্লায়েন্টের কাছ থেকে আসা সম্পূর্ণ এবং ডিকোড করা ডেটা পেতে পারবে। - যখন
onMessage-এ ব্যবসায়ের প্রয়োজন হয়$connection->send($buffer)পদ্ধতি কল করে ক্লায়েন্টকে ডেটা পাঠানোর জন্য, workerman স্বয়ংক্রিয়ভাবে প্রোটোকলেরencodeপদ্ধতিকে ব্যবহার করে$bufferপ্যাক করবে এবং পরে ক্লায়েন্টের কাছে পাঠাবে।
নির্দিষ্ট বাস্তবায়ন
MyApp/Protocols/JsonNL.php এর বাস্তবায়ন
namespace Protocols;
class JsonNL
{
/**
* প্যাকেটের সম্পূর্ণতা পরীক্ষা করে
* যদি প্যাক এর দৈর্ঘ্য জানা যায়, তাহলে বাফারের মধ্যে প্যাকেটের দৈর্ঘ্য ফেরত দেয়, অন্যথায় 0 রিটার্ন করে ডেটার জন্য অপেক্ষা করতে থাকে
* যদি প্রোটোকলে সমস্যা ঘটে তবে -1 ফেরত দিতে পারে, বর্তমান ক্লায়েন্ট সংযোগ এর জন্য বন্ধ হয়ে যাবে
* @param string $buffer
* @return int
*/
public static function input($buffer)
{
// newline চরিত্র "\n" এর অবস্থান পান
$pos = strpos($buffer, "\n");
// কোন newline নেই, প্যাকেট দৈর্ঘ্য জানা যাবে না, 0 ফেরত দেয় এবং ডেটার জন্য অপেক্ষা করে
if($pos === false)
{
return 0;
}
// newline রয়েছে, বর্তমান প্যাকেটের দৈর্ঘ্য ফেরত দেয় (newline সহ)
return $pos+1;
}
/**
* প্যাক করা, ক্লায়েন্টকে ডেটা পাঠানোর সময় স্বয়ংক্রিয়ভাবে কল করা হয়
* @param string $buffer
* @return string
*/
public static function encode($buffer)
{
// json সিরিয়ালাইজ করা হয়, এবং newline চরিত্র যুক্ত করা হয় অনুরোধ শেষের চিহ্ন হিসেবে
return json_encode($buffer)."\n";
}
/**
* ডিকোড করা, যখন পাওয়া ডেটার বাইট সংখ্যা input এর ফেরত দেওয়া মানের সমান (0 এর উপর) স্বয়ংক্রিয়ভাবে কল হয়
* এবং onMessage কলব্যাক ফাংশনের $data প্যারামিটারে পাঠায়
* @param string $buffer
* @return string
*/
public static function decode($buffer)
{
// newline বাদ দিয়ে, অ্যারের মধ্যে পুনরুদ্ধার করে
return json_decode(trim($buffer), true);
}
}
এতক্ষণে, JsonNL প্রোটোকল সম্পন্ন হয়েছে এবং এটি MyApp প্রকল্পে ব্যবহার করা যেতে পারে, ব্যবহারের উদাহরণ নিচে দেওয়া হলো
ফাইল: MyApp\start.php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$json_worker = new Worker('JsonNL://0.0.0.0:1234');
$json_worker->onMessage = function(TcpConnection $connection, $data) {
// $data হল ক্লায়েন্টের পাঠানো ডেটা, ডেটা JsonNL::decode প্রক্রিয়াকৃত হয়েছে
echo $data;
// $connection->send ডেটা JsonNL::encode পদ্ধতি দ্বারা প্যাক হয়ে ক্লায়েন্টকে পাঠানো হবে
$connection->send(array('code'=>0, 'msg'=>'ok'));
};
Worker::runAll();
...
দ্রষ্টব্য
workermanProtocolsনামকরণস্থানের অধীনে প্রোটোকলগুলি লোড করতে চেষ্টা করবে, যেমনnew Worker('JsonNL://0.0.0.0:1234')Protocols\JsonNLপ্রোটোকলটি লোড করতে চেষ্টা করবে।
যদি ত্রুটি হয়Class 'Protocols\JsonNL' not foundতাহলে স্বয়ংক্রিয় লোডিং প্রদর্শনের জন্য যাচাই করুন।
প্রোটোকল ইন্টারফেসের বর্ণনা
Workerman এ বিকাশ করা প্রোটোকল ক্লাসে তিনটি স্থিতিশীল পদ্ধতি, input, encode, decode থাকতে হবে, প্রোটোকল ইন্টারফেস বর্ণনা Workerman/Protocols/ProtocolInterface.php তে আছে, নিম্নরূপ সংজ্ঞায়িত করা হয়েছে:
namespace Workerman\Protocols;
use \Workerman\Connection\ConnectionInterface;
/**
* প্রোটোকল ইন্টারফেস
* @author walkor <walkor@workerman.net>
*/
interface ProtocolInterface
{
/**
* যা প্রাপ্ত recv_buffer এ প্যাকেট বিভজিত করতে ব্যবহৃত হয়
*
* যদি $recv_buffer এর মধ্যে অনুরোধ প্যাকেটটির দৈর্ঘ্য পাওয়া যায় তবে পুরো প্যাকেটের দৈর্ঘ্য ফেরত দেয়
* অন্যথায় 0 ফেরত দেয়, নির্দেশ করে আরও ডেটার প্রয়োজন যাতে বর্তমানে অনুরোধ প্যাকেটের দৈর্ঘ্য পাওয়া যায়
* যদি -1 ফেরত দেওয়া হয়, তবে এটি একটি ত্রুটিপূর্ণ অনুরোধ বোঝায়, ফলে সংযোগ বিচ্ছিন্ন হবে
*
* @param ConnectionInterface $connection
* @param string $recv_buffer
* @return int
*/
public static function input($recv_buffer, ConnectionInterface $connection);
/**
* ডিকোডিং এর জন্য ব্যবহৃত
*
* input এর ফেরত মান বড় 0, এবং Workerman যথেষ্ট ডেটা পেলে, তখন স্বয়ংক্রিয়ভাবে decode কল হয়
* তারপর onMessage কলব্যাক বিগ্রস্ত হয় এবং decode ডিকোড করা ডেটা onMessage কলব্যাকের দ্বিতীয় প্যারামিটার হিসাবে পাঠানো হয়
* অর্থাৎ ক্লায়েন্টের সম্পূর্ণ অনুরোধ পাওয়ার সময়, decoding স্বয়ংক্রিয়ভাবে ডিকোড কল হয়, যাতে ব্যবসায়ের কোডে ম্যানুয়াল কল না করতে হয়
* @param ConnectionInterface $connection
* @param string $recv_buffer
*/
public static function decode($recv_buffer, ConnectionInterface $connection);
/**
* প্যাক করার জন্য ব্যবহৃত
*
* যখন ক্লায়েন্টে ডেটা পাঠানোর প্রয়োজন হয় অর্থাৎ $connection->send($data); তখন
* স্বয়ংক্রিয়ভাবে $data কে encode দিয়ে প্যাক করে, যেটি প্রোটোকল ডেটা ফরম্যাটে কনভার্ট করে, তারপর ক্লায়েন্টে পাঠানো হয়
* অর্থাৎ ক্লায়েন্টে পাঠানো ডেটা স্বয়ংক্রিয়ভাবে encode করা হয়, যাতে ব্যবসায়ের কোডে ম্যানুয়াল কল করতে হয় না
* @param ConnectionInterface $connection
* @param mixed $data
*/
public static function encode($data, ConnectionInterface $connection);
}
দ্রষ্টব্য:
Workerman এ প্রোটোকল ক্লাস অবশ্যই ProtocolInterface ভিত্তিতে থাকতে হবে এমন কোনো কঠোর নিয়ম নেই, প্রকৃতপক্ষে প্রোটোকল ক্লাসটি input, encode, decode তিনটি স্থিতিশীল পদ্ধতি থাকলেই হবে।