2023 সালে ইউনিটি নেটওয়ার্কিং ল্যান্ডস্কেপে আমার নিবন্ধের সিরিজ অব্যাহত রয়েছে! আজকের পোস্টটি রিয়েল-টাইম মাল্টিপ্লেয়ার গেমগুলিতে ব্যবহৃত ডেটা ট্রান্সমিশন প্রোটোকলগুলিকে কভার করবে।
সবাইকে শুভেচ্ছা! আমি দিমিত্রি ইভাশচেঙ্কো, MY.GAMES-এর একজন লিড সফটওয়্যার ইঞ্জিনিয়ার৷ আমরা নেটওয়ার্ক ইন্টারঅ্যাকশনের বিভিন্ন স্তরে কোন প্রোটোকল বিদ্যমান তার একটি সংক্ষিপ্ত বিবরণ দিয়ে শুরু করব।
OSI (ওপেন সিস্টেম ইন্টারকানেকশন) মডেল হল একটি ধারণাগত মডেল যা বিমূর্ততা স্তরের পরিপ্রেক্ষিতে একটি যোগাযোগ ব্যবস্থার ফাংশনগুলিকে চিহ্নিত করে এবং মানক করে। এই মডেলটি 1978 সালে ইন্টারন্যাশনাল অর্গানাইজেশন ফর স্ট্যান্ডার্ডাইজেশন (ISO) দ্বারা তৈরি করা হয়েছিল।
এটি সাতটি স্তর নিয়ে গঠিত:
ভৌত স্তর : এই স্তরটি চ্যানেলের উপর কাঁচা বিটগুলির সংক্রমণ এবং অভ্যর্থনা নিয়ে কাজ করে। এই স্তরের প্রোটোকলগুলি বিট উপস্থাপনা, ট্রান্সমিশন রেট, ফিজিক্যাল কেবল, কার্ড এবং সংযোগকারী ডিজাইন সহ শারীরিক ইন্টারফেস এবং মাধ্যমের বৈশিষ্ট্যগুলি বর্ণনা করে।
ডেটা লিঙ্ক লেয়ার : এই স্তরটি ভৌত মাধ্যম জুড়ে ডেটা স্থানান্তর প্রদান করে এবং শারীরিক স্তরে ঘটতে পারে এমন ত্রুটিগুলি পরিচালনা করে।
নেটওয়ার্ক লেয়ার : এই স্তরটি নেটওয়ার্কগুলির মধ্যে ডেটা ট্রান্সমিশনের জন্য পথ (রাউটিং) নির্ধারণ করে।
ট্রান্সপোর্ট লেয়ার : এই স্তরটি পয়েন্টের মধ্যে বার্তা বিতরণ পরিচালনা করে এবং প্রয়োজনে নির্ভরযোগ্যতা প্রদান করে।
সেশন লেয়ার : এই স্তরটি ব্যবহারকারী এবং অ্যাপ্লিকেশনের মধ্যে সেশন প্রতিষ্ঠা, রক্ষণাবেক্ষণ এবং সমাপ্তি পরিচালনা করে।
প্রেজেন্টেশন লেয়ার : এই স্তরটি প্রেরক এবং প্রাপকের পক্ষের ডেটা উপস্থাপনা (এনকোডিং) এর পার্থক্য থেকে ডেটা স্বাধীনতা নিশ্চিত করে।
অ্যাপ্লিকেশন লেয়ার : এই স্তরটিতে এমন প্রোটোকল রয়েছে যেগুলির সাথে ব্যবহারকারীর যোগাযোগের অ্যাপ্লিকেশনগুলির সাথে সরাসরি সম্পর্ক রয়েছে।
এটা লক্ষনীয় যে প্রতিটি স্তর আগেরটির উপর তৈরি হয়। ট্রান্সপোর্ট লেয়ারের উপরের স্তরগুলি (সেশন, উপস্থাপনা এবং অ্যাপ্লিকেশন) অত্যন্ত বিশেষায়িত এবং আমাদের রিয়েল-টাইম মাল্টিপ্লেয়ার সংগঠিত করতে সাহায্য করতে পারে না। অতএব, আমাদের ট্রান্সপোর্ট লেয়ারে থামতে হবে এবং খেলোয়াড়দের মধ্যে সর্বোত্তম ডেটা বিনিময়ের জন্য এর TCP এবং UDP প্রোটোকল ব্যবহার করতে হবে।
TCP হল একটি সংযোগ-ভিত্তিক প্রোটোকল, যার অর্থ হল যোগাযোগ দুটি ডিভাইসের মধ্যে ঘটে যা ডেটা বিনিময়ের জন্য একটি সংযোগ স্থাপন করে। এই প্রোটোকল নির্ভরযোগ্যতা নিশ্চিত করে কারণ এটি গ্যারান্টি দেয় যে সমস্ত প্রেরিত ডেটা সঠিক ক্রমে তার গন্তব্যে পৌঁছাবে। ট্রান্সমিশনের সময় কোনো ডেটা হারিয়ে গেলে, সমস্ত ডেটা সফলভাবে প্রেরণ না হওয়া পর্যন্ত TCP স্বয়ংক্রিয়ভাবে অনুরোধটি পুনরায় চেষ্টা করবে।
একটি সংযোগ স্থাপনের জন্য নিম্নলিখিত পদক্ষেপগুলি জড়িত:
নীচের উদাহরণটি একটি TCP ক্লায়েন্টের একটি মৌলিক বাস্তবায়ন দেখায় এবং নির্দিষ্ট ডেটা এবং গেম লজিকের সাথে কাজ করার জন্য প্রসারিত করা যেতে পারে।
কোডটি একটি নির্দিষ্ট আইপি ঠিকানা এবং পোর্ট সহ একটি সার্ভারের সাথে সংযোগ করে এবং তারপর সংযোগের মাধ্যমে ডেটা পাঠায় এবং গ্রহণ করে। সার্ভার থেকে অ্যাসিঙ্ক্রোনাস ডেটা রিসেপশনের জন্য একটি নেটওয়ার্ক স্ট্রিম ব্যবহার করা হয়।
using System; using System.Net; using System.Net.Sockets; using UnityEngine; public class TCPClient : MonoBehaviour { private TcpClient tcpClient; private NetworkStream networkStream; private byte[] receiveBuffer; private void Start() { // Example: Connect to server with IP address 127.0.0.1 (localhost) and port 5555 ConnectToServer("127.0.0.1", 5555); } private void ConnectToServer(string ipAddress, int port) { tcpClient = new TcpClient(); tcpClient.Connect(IPAddress.Parse(ipAddress), port); networkStream = tcpClient.GetStream(); // Start asynchronous operation to receive data from the server receiveBuffer = new byte[tcpClient.ReceiveBufferSize]; networkStream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveData, null); } private void ReceiveData(IAsyncResult result) { int bytesRead = networkStream.EndRead(result); byte[] receivedBytes = new byte[bytesRead]; Array.Copy(receiveBuffer, receivedBytes, bytesRead); string receivedMessage = System.Text.Encoding.UTF8.GetString(receivedBytes); Debug.Log("Received from server: " + receivedMessage); // Continue the asynchronous operation to receive data networkStream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveData, null); } private void SendData(string message) { byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(message); networkStream.Write(sendBytes, 0, sendBytes.Length); networkStream.Flush(); } }
ConnectToServer(string ipAddress, int port)
পদ্ধতিটি নির্দিষ্ট আইপি ঠিকানা এবং পোর্টে সার্ভারের সাথে একটি সংযোগ স্থাপন করে। সার্ভার থেকে ডেটা গ্রহণ করা হয় ReceiveData(IAsyncResult result)
পদ্ধতিতে, যখন SendData(string message)
পদ্ধতিতে ডেটা ট্রান্সমিশন করা হয়। প্রাপ্ত ডেটা Debug.Log
ব্যবহার করে কনসোলে আউটপুট হয়।
নীচের কোড উদাহরণ ইউনিটিতে একটি সাধারণ TCP সার্ভার উপস্থাপন করে। কোডটি সার্ভার শুরু করে, নির্দিষ্ট পোর্ট শোনে এবং ক্লায়েন্টদের কাছ থেকে আগত সংযোগ গ্রহণ করে। একটি ক্লায়েন্টের সাথে সংযোগ করার পরে, সার্ভার নেটওয়ার্ক স্ট্রিমের মাধ্যমে ডেটা পাঠায় এবং গ্রহণ করে।
StartServer(int port)
পদ্ধতিটি নির্দিষ্ট পোর্টে সার্ভারকে আরম্ভ করে এবং ইনকামিং সংযোগের জন্য শোনা শুরু করে। যখন একটি ক্লায়েন্ট সংযোগ প্রতিষ্ঠিত হয়, HandleIncomingConnection(IAsyncResult result)
পদ্ধতিটি কার্যকর করা হয়, যা ক্লায়েন্টের কাছ থেকে ডেটা গ্রহণ করে এবং ডেটা গ্রহণের জন্য একটি অ্যাসিঙ্ক্রোনাস অপারেশন শুরু করে।
প্রাপ্ত ডেটা ReceiveData(IAsyncResult result)
পদ্ধতিতে প্রক্রিয়া করা হয়। ক্লায়েন্ট থেকে ডেটা পাওয়ার পরে, সার্ভার প্রয়োজনীয় প্রক্রিয়াকরণ করতে পারে বা ক্লায়েন্টের কাছে ডেটা ফেরত পাঠাতে পারে।
SendData(string message)
পদ্ধতি নেটওয়ার্ক স্ট্রীমের মাধ্যমে ক্লায়েন্টকে ডেটা পাঠায়। ডেটা একটি বাইট অ্যারেতে রূপান্তরিত হয় এবং ক্লায়েন্টকে পাঠানো হয়।
using System; using System.Net; using System.Net.Sockets; using UnityEngine; public class TCPServer : MonoBehaviour { private TcpListener tcpListener; private TcpClient connectedClient; private NetworkStream networkStream; private byte[] receiveBuffer; private void Start() { // Example: Start the server on port 5555 StartServer(5555); } private void StartServer(int port) { tcpListener = new TcpListener(IPAddress.Any, port); tcpListener.Start(); Debug.Log("Server started. Waiting for connections..."); // Start accepting client connections asynchronously tcpListener.BeginAcceptTcpClient(HandleIncomingConnection, null); } }
একটি ইনকামিং ক্লায়েন্ট সংযোগ পরিচালনা করতে HandleIncomingConnection
পদ্ধতি ব্যবহার করা হয়। একটি সংযোগ গ্রহণ করার পরে, এটি ক্লায়েন্টের সাথে ডেটা বিনিময়ের জন্য একটি স্ট্রিম প্রাপ্ত করে এবং ক্লায়েন্টের কাছ থেকে ডেটা গ্রহণের জন্য একটি অ্যাসিঙ্ক্রোনাস অপারেশন শুরু করে।
তারপরে, পদ্ধতিটি সংযুক্ত ক্লায়েন্ট থেকে প্রাপ্ত বাফার আকারের উপর ভিত্তি করে ডেটা গ্রহণের জন্য একটি বাফার তৈরি করে। তৈরি বাফার ব্যবহার করে স্ট্রীম থেকে ডেটা পড়ার জন্য একটি অ্যাসিঙ্ক্রোনাস অপারেশন চালু করা হয়। রিড অপারেশন শেষ হওয়ার পরে, আরও প্রক্রিয়াকরণের জন্য ডেটা ReceiveData
পদ্ধতিতে প্রেরণ করা হবে।
এছাড়াও, পরবর্তী ক্লায়েন্ট গ্রহণ করার সম্ভাবনার জন্য ইনকামিং সংযোগগুলি গ্রহণ করার জন্য পদ্ধতিটি আরেকটি অ্যাসিঙ্ক্রোনাস অপারেশন চালু করে।
যখন একটি ক্লায়েন্ট সার্ভারের সাথে সংযোগ স্থাপন করে, তখন সংযোগটি পরিচালনা করার জন্য এই পদ্ধতিটি কল করা হবে এবং সার্ভারটি পরবর্তী ক্লায়েন্টদের অ্যাসিঙ্ক্রোনাসভাবে গ্রহণ করার জন্য প্রস্তুত থাকবে।
private void HandleIncomingConnection(IAsyncResult result) { connectedClient = tcpListener.EndAcceptTcpClient(result); networkStream = connectedClient.GetStream(); Debug.Log("Client connected: " + connectedClient.Client.RemoteEndPoint); // Start asynchronous operation to receive data from the client receiveBuffer = new byte[connectedClient.ReceiveBufferSize]; networkStream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveData, null); // Accept next client connection asynchronously tcpListener.BeginAcceptTcpClient(HandleIncomingConnection, null); }
ক্লায়েন্টের কাছ থেকে প্রাপ্ত ডেটা প্রক্রিয়া করতে ReceiveData
পদ্ধতি ব্যবহার করা হয়। ডেটা রিডিং অপারেশন শেষ হওয়ার পরে, পদ্ধতিটি পঠিত বাইটের সংখ্যা পরীক্ষা করে। যদি বাইটের সংখ্যা শূন্যের চেয়ে কম বা সমান হয়, তাহলে ক্লায়েন্ট সংযোগ বিচ্ছিন্ন হয়ে গেছে। এই ক্ষেত্রে, পদ্ধতিটি ক্লায়েন্টের সাথে সংযোগ বন্ধ করে এবং মৃত্যুদন্ড বন্ধ করে দেয়।
পঠিত বাইটের সংখ্যা শূন্যের চেয়ে বেশি হলে, পদ্ধতিটি প্রাপ্ত ডেটার জন্য একটি বাইট অ্যারে তৈরি করে এবং এই অ্যারেতে পঠিত ডেটা কপি করে। তারপর, পদ্ধতিটি UTF-8 এনকোডিং ব্যবহার করে প্রাপ্ত বাইটগুলিকে একটি স্ট্রিংয়ে রূপান্তর করে এবং প্রাপ্ত বার্তাটি কনসোলে আউটপুট করে।
private void ReceiveData(IAsyncResult result) { int bytesRead = networkStream.EndRead(result); if (bytesRead <= 0) { Debug.Log("Client disconnected: " + connectedClient.Client.RemoteEndPoint); connectedClient.Close(); return; } byte[] receivedBytes = new byte[bytesRead]; Array.Copy(receiveBuffer, receivedBytes, bytesRead); string receivedMessage = System.Text.Encoding.UTF8.GetString(receivedBytes); Debug.Log("Received from client: " + receivedMessage); // Process received data // Continue the asynchronous operation to receive data networkStream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReceiveData, null); } private void SendData(string message) { byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(message); networkStream.Write(sendBytes, 0, sendBytes.Length); networkStream.Flush(); Debug.Log("Sent to client: " + message); }
SendData
পদ্ধতিটি ক্লায়েন্টকে ডেটা পাঠাতে ব্যবহৃত হয়। এটি UTF-8 এনকোডিং ব্যবহার করে বার্তা স্ট্রিংটিকে একটি বাইট অ্যারেতে রূপান্তর করে এবং এই অ্যারেটিকে নেটওয়ার্ক স্ট্রীমে লেখে। ডেটা পাঠানোর পরে, পদ্ধতিটি স্ট্রিমটি সাফ করে এবং কনসোলে প্রেরিত বার্তাটি আউটপুট করে।
যদিও নির্ভরযোগ্যতা একটি বড় প্লাসের মতো শোনাতে পারে, এই TCP বৈশিষ্ট্যটি রিয়েল-টাইম মাল্টিপ্লেয়ার গেমগুলিতে সমস্যা তৈরি করতে পারে। টিসিপি-তে ডেটা ট্রান্সমিশন রিট্রান্সমিশন এবং প্রবাহ নিয়ন্ত্রণের পদ্ধতির দ্বারা ধীর হয়ে যেতে পারে, যা বিলম্ব বা "ল্যাগ" হতে পারে।
UDP হল একটি সহজ প্রোটোকল যা ডেলিভারি বা প্যাকেট অর্ডারের নিশ্চয়তা দেয় না। এটি এটিকে টিসিপির চেয়ে অনেক দ্রুত করে তোলে, কারণ এটি সংযোগ স্থাপন বা হারিয়ে যাওয়া প্যাকেটগুলি পুনরায় প্রেরণে সময় ব্যয় করে না। এর গতি এবং সরলতার কারণে, ইউডিপি প্রায়শই নেটওয়ার্ক গেম এবং অন্যান্য অ্যাপ্লিকেশনগুলিতে ব্যবহৃত হয় যার জন্য রিয়েল-টাইম ডেটা ট্রান্সমিশন প্রয়োজন।
যাইহোক, UDP ব্যবহার করার জন্য ডেভেলপারদের আরও সাবধানে ডেটা ট্রান্সমিশন পরিচালনা করতে হবে। যেহেতু ইউডিপি ডেলিভারির গ্যারান্টি দেয় না, তাই আপনাকে হারিয়ে যাওয়া প্যাকেট বা প্যাকেটগুলি যা অর্ডারের বাইরে এসেছে তা পরিচালনা করার জন্য আপনার নিজস্ব পদ্ধতি প্রয়োগ করতে হতে পারে।
এই কোডটি ইউনিটিতে একটি UDP ক্লায়েন্টের মৌলিক বাস্তবায়ন প্রদর্শন করে। StartUDPClient
পদ্ধতি UDP ক্লায়েন্টকে আরম্ভ করে এবং IP ঠিকানা এবং পোর্ট দ্বারা নির্দিষ্ট করা দূরবর্তী সার্ভারের সাথে সংযুক্ত করে। ক্লায়েন্ট BeginReceive
পদ্ধতি ব্যবহার করে অ্যাসিঙ্ক্রোনাসভাবে ডেটা গ্রহণ করা শুরু করে এবং SendData
পদ্ধতি ব্যবহার করে সার্ভারে একটি বার্তা পাঠায়।
using System; using System.Net; using System.Net.Sockets; using UnityEngine; public class UDPExample : MonoBehaviour { private UdpClient udpClient; private IPEndPoint remoteEndPoint; private void Start() { // Example: Start the UDP client and connect to the remote server StartUDPClient("127.0.0.1", 5555); } private void StartUDPClient(string ipAddress, int port) { udpClient = new UdpClient(); remoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); // Start receiving data asynchronously udpClient.BeginReceive(ReceiveData, null); // Send a message to the server SendData("Hello, server!"); } private void ReceiveData(IAsyncResult result) { byte[] receivedBytes = udpClient.EndReceive(result, ref remoteEndPoint); string receivedMessage = System.Text.Encoding.UTF8.GetString(receivedBytes); Debug.Log("Received from server: " + receivedMessage); // Continue receiving data asynchronously udpClient.BeginReceive(ReceiveData, null); } private void SendData(string message) { byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(message); // Send the message to the server udpClient.Send(sendBytes, sendBytes.Length, remoteEndPoint); Debug.Log("Sent to server: " + message); } }
যখন সার্ভার থেকে ডেটা প্রাপ্ত হয়, তখন ReceiveData
পদ্ধতিটি চালু করা হয়, যা প্রাপ্ত বাইটগুলিকে প্রক্রিয়া করে এবং সেগুলিকে একটি স্ট্রিংয়ে রূপান্তর করে। প্রাপ্ত বার্তা তারপর কনসোলে লগ ইন করা হয়. ক্লায়েন্ট আবার BeginReceive
কল করে অ্যাসিঙ্ক্রোনাসভাবে ডেটা গ্রহণ করতে থাকে।
SendData
পদ্ধতি বার্তাটিকে বাইটে রূপান্তর করে এবং UDP ক্লায়েন্টের Send
পদ্ধতি ব্যবহার করে সার্ভারে পাঠায়।
এই কোডটি ইউনিটিতে একটি UDP সার্ভারের একটি মৌলিক বাস্তবায়ন প্রদর্শন করে। StartUDPServer
পদ্ধতিটি নির্দিষ্ট পোর্টে UDP সার্ভারকে আরম্ভ করে এবং BeginReceive
পদ্ধতি ব্যবহার করে অ্যাসিঙ্ক্রোনাসভাবে ডেটা গ্রহণ করা শুরু করে।
যখন একটি ক্লায়েন্টের কাছ থেকে ডেটা প্রাপ্ত হয়, তখন ReceiveData
পদ্ধতিটি চালু করা হয়, যা প্রাপ্ত বাইটগুলিকে প্রক্রিয়া করে এবং তাদের একটি স্ট্রিংয়ে রূপান্তর করে। প্রাপ্ত বার্তা তারপর কনসোলে লগ ইন করা হয়. আবার BeginReceive
কল করে সার্ভার অসিঙ্ক্রোনাসভাবে ডেটা গ্রহণ করতে থাকে।
using System; using System.Net; using System.Net.Sockets; using UnityEngine; public class UDPServer : MonoBehaviour { private UdpClient udpServer; private IPEndPoint remoteEndPoint; private void Start() { // Example: Start the UDP server on port 5555 StartUDPServer(5555); } private void StartUDPServer(int port) { udpServer = new UdpClient(port); remoteEndPoint = new IPEndPoint(IPAddress.Any, port); Debug.Log("Server started. Waiting for messages..."); // Start receiving data asynchronously udpServer.BeginReceive(ReceiveData, null); } private void ReceiveData(IAsyncResult result) { byte[] receivedBytes = udpServer.EndReceive(result, ref remoteEndPoint); string receivedMessage = System.Text.Encoding.UTF8.GetString(receivedBytes); Debug.Log("Received from client: " + receivedMessage); // Process the received data // Continue receiving data asynchronously udpServer.BeginReceive(ReceiveData, null); } private void SendData(string message, IPEndPoint endPoint) { byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(message); // Send the message to the client udpServer.Send(sendBytes, sendBytes.Length, endPoint); Debug.Log("Sent to client: " + message); } }
SendData
পদ্ধতিটি ক্লায়েন্টের ঠিকানা এবং পোর্ট প্রতিনিধিত্ব করে একটি বার্তা এবং একটি IPEndPoint
নেয়। এটি বার্তাটিকে বাইটে রূপান্তর করে এবং UDP সার্ভারের Send
পদ্ধতি ব্যবহার করে ক্লায়েন্টের কাছে পাঠায়।
গেম ডেভেলপমেন্টের প্রেক্ষাপটে, টিসিপি এবং ইউডিপির মধ্যে পছন্দটি মূলত আপনার গেমের ধরনের উপর নির্ভর করে। যদি আপনার গেমের জন্য নির্ভরযোগ্য ডেটা সরবরাহের প্রয়োজন হয় এবং প্রতিক্রিয়া সময় একটি গুরুত্বপূর্ণ কারণ না হয় (উদাহরণস্বরূপ, রিয়েল-টাইম কৌশল বা টার্ন-ভিত্তিক গেমগুলিতে), তাহলে TCP একটি উপযুক্ত পছন্দ হতে পারে। অন্যদিকে, যদি আপনার গেমের দ্রুত ডেটা ট্রান্সমিশনের প্রয়োজন হয় এবং কিছু ডেটা ক্ষয় সামাল দিতে পারে (উদাহরণস্বরূপ, প্রথম-ব্যক্তি শ্যুটার বা রেসিং গেমগুলিতে), তাহলে UDP সেরা পছন্দ হতে পারে।
WebSocket একটি যোগাযোগ প্রোটোকল যা একটি ব্রাউজার এবং একটি সার্ভারের মধ্যে একটি অবিরাম সংযোগ স্থাপনের অনুমতি দেয়। নিয়মিত HTTP থেকে প্রধান পার্থক্য হল যে এটি দ্বিমুখী যোগাযোগ সক্ষম করে; সার্ভার শুধুমাত্র ক্লায়েন্টের অনুরোধে সাড়া দিতে সক্ষম নয়, এটিতে বার্তাও পাঠাতে পারে।
WebSocket টিসিপি ভিত্তিক একটি অ্যাপ্লিকেশন-স্তরের প্রোটোকল। এটি বার্তা সমর্থন করে, স্ট্রিম নয়, যা এটিকে নিয়মিত TCP থেকে আলাদা করে। WebSocket অতিরিক্ত কার্যকারিতা অন্তর্ভুক্ত করে যা কিছু কর্মক্ষমতা ওভারহেড যোগ করতে পারে।
ধাপে ধাপে এটি কীভাবে কাজ করে তা এখানে:
ক্লায়েন্ট "আপগ্রেড অনুরোধ" নামে একটি বিশেষ HTTP অনুরোধ পাঠায়। এই অনুরোধ সার্ভারকে জানায় যে ক্লায়েন্ট WebSocket এ স্যুইচ করতে চায়।
যদি সার্ভার WebSocket সমর্থন করে এবং স্যুইচ করতে সম্মত হয়, তাহলে এটি একটি বিশেষ HTTP প্রতিক্রিয়ার সাথে সাড়া দেয় যা WebSocket-এ আপগ্রেড নিশ্চিত করে।
এই বার্তাগুলি বিনিময় করার পরে, ক্লায়েন্ট এবং সার্ভারের মধ্যে একটি স্থায়ী, দ্বিমুখী সংযোগ স্থাপন করা হয়। উভয় পক্ষই যেকোন সময় বার্তা পাঠাতে পারে, শুধু অন্য পক্ষের অনুরোধের জবাবে নয়।
এখন ক্লায়েন্ট এবং সার্ভার যেকোনো সময় বার্তা পাঠাতে এবং গ্রহণ করতে পারে। প্রতিটি WebSocket বার্তা "ফ্রেমে" মোড়ানো থাকে যা নির্দেশ করে কখন বার্তা শুরু হয় এবং শেষ হয়। এটি ব্রাউজার এবং সার্ভারকে বার্তাগুলিকে সঠিকভাবে ব্যাখ্যা করতে দেয়, এমনকি যদি সেগুলি মিশ্র ক্রমে আসে বা নেটওয়ার্ক সমস্যার কারণে অংশে বিভক্ত হয়।
উভয় পক্ষ একটি বিশেষ "ক্লোজ কানেকশন" ফ্রেম পাঠিয়ে যে কোনো সময় সংযোগ বন্ধ করতে পারে। অন্য পক্ষ বন্ধের নিশ্চিতকরণের সাথে প্রতিক্রিয়া জানাতে পারে এবং এর পরে, উভয় পক্ষকেই অবিলম্বে অন্য কোনও ডেটা পাঠানো বন্ধ করতে হবে। স্ট্যাটাস কোডগুলিও বন্ধের কারণ নির্দেশ করতে ব্যবহার করা যেতে পারে।
নীচের কোডটি C# ভাষা এবং WebSocketSharp লাইব্রেরি ব্যবহার করে ইউনিটিতে একটি WebSocket ক্লায়েন্ট বাস্তবায়নের একটি উদাহরণ প্রদান করে।
Start()
পদ্ধতিতে, যাকে অবজেক্ট ইনিশিয়ালাইজেশন বলা হয়, WebSocket
একটি নতুন উদাহরণ তৈরি করা হয়, আপনার ওয়েবসকেট সার্ভারের ঠিকানা দিয়ে শুরু করা হয়।
এর পরে, ইভেন্ট হ্যান্ডলারগুলি OnOpen
এবং OnMessage
সেট আপ করা হয়৷
using UnityEngine; using WebSocketSharp; public class WebSocketClient : MonoBehaviour { private WebSocket ws; void Start() { ws = new WebSocket("ws://your-websocket-server-url/Auth"); ws.OnOpen += OnOpenHandler; ws.OnMessage += OnMessageHandler; ws.ConnectAsync(); } private void OnOpenHandler(object sender, System.EventArgs e) { var data = "Player1"; ws.Send(data) } private void OnMessageHandler(object sender, MessageEventArgs e) { Debug.Log("WebSocket server said: " + e.Data); } }
সার্ভারের সাথে সংযোগ স্থাপন করা হলে OnOpen
ট্রিগার হয়। এই উদাহরণে, সংযোগ স্থাপন করা হলে, "Player1" পাঠ্য সহ একটি বার্তা সার্ভারে পাঠানো হয়।
সার্ভার থেকে একটি বার্তা প্রাপ্ত হলে OnMessage
ট্রিগার হয়। এখানে, একটি বার্তা পাওয়ার পরে, এর বিষয়বস্তু কনসোলে প্রদর্শিত হয়।
তারপর, ConnectAsync()
পদ্ধতি বলা হয়, যা অ্যাসিঙ্ক্রোনাসভাবে সার্ভারের সাথে সংযোগ করে।
নীচের কোডটি একটি WebSocket সার্ভার তৈরির একটি উদাহরণ।
Start()
পদ্ধতিতে, যাকে বলা হয় যখন অবজেক্টটি আরম্ভ করা হয়, WebSocketServer
একটি নতুন উদাহরণ তৈরি করা হয়, আপনার ওয়েবসকেট সার্ভারের ঠিকানা দিয়ে শুরু করা হয়। তারপর AuthBehaviour
WebSocket পরিষেবা সার্ভারে যোগ করা হয়, যা /Auth
পাথে উপলব্ধ। এর পরে, Start()
পদ্ধতি ব্যবহার করে সার্ভার শুরু হয়।
using UnityEngine; using WebSocketSharp; using WebSocketSharp.Server; public class WebSocketServer : MonoBehaviour { void Start() { var socket = new WebSocketServer("ws://your-websocket-server-url"); socket.AddWebSocketService<AuthBehaviour>("/Auth"); socket.Start(); } } public class AuthBehaviour : WebSocketBehavior { protected override void OnMessage (MessageEventArgs e) { var playerName = e.Data; Debug.Log("WebSocket client connected: " + playerName); Send("Auth Complete: " + playerName); } }
AuthBehaviour
হল WebSocketBehavior
থেকে প্রাপ্ত একটি ক্লাস যা ক্লায়েন্টদের কাছ থেকে বার্তা পাওয়ার সময় সার্ভারের আচরণকে সংজ্ঞায়িত করে। এখানে, OnMessage()
পদ্ধতিটি ওভাররাইড করা হয়, যেটিকে বলা হয় যখন সার্ভার একটি ক্লায়েন্ট থেকে একটি বার্তা পায়।
এই পদ্ধতিতে, বার্তার পাঠ্যটি প্রথমে বের করা হয়, তারপর একটি বার্তা কনসোলে আউটপুট হয় যা নির্দেশ করে যে বার্তায় পাস করা নাম ব্যবহার করে কোন ক্লায়েন্ট সংযোগ করেছে। তারপরে, সার্ভারটি ক্লায়েন্টকে একটি বার্তা পাঠায় যাতে প্রমাণীকরণের সমাপ্তির তথ্য রয়েছে।
আমরা আলোচনা করেছি কিভাবে TCP, UDP, এবং WebSockets ব্যবহার করে ইউনিটি গেমগুলির জন্য সংযোগ তৈরি করতে হয়, সেইসাথে প্রতিটির সুবিধা এবং অসুবিধাগুলি। UDP-এর হালকা প্রকৃতি এবং TCP-এর নির্ভরযোগ্যতা সত্ত্বেও, গেমগুলিতে রিয়েল-টাইম মাল্টিপ্লেয়ার সংগঠিত করার জন্য কোনটিই ভাল পছন্দ নয়। UDP কিছু ডেটা হারাবে, এবং TCP প্রয়োজনীয় ট্রান্সমিশন গতি প্রদান করবে না। পরবর্তী নিবন্ধে, আমরা আলোচনা করব কিভাবে UDP ব্যবহার করে নির্ভরযোগ্য ডেটা ট্রান্সমিশন সংগঠিত করা যায়।