স্ট্যান্ডার্ড ওয়েব অ্যাপ্লিকেশনগুলি সাধারণত HTTP-র মতো নির্দিষ্ট যোগাযোগ প্রোটোকল এবং WebSocket এবং WebRTC-এর মতো API-এর মধ্যে সীমাবদ্ধ থাকে। যদিও এগুলি শক্তিশালী, তবে অপব্যবহার রোধ করার জন্য এগুলিকে কঠোরভাবে সীমাবদ্ধ করার জন্য ডিজাইন করা হয়েছে। এগুলি raw TCP বা UDP সংযোগ স্থাপন করতে পারে না, যা ওয়েব অ্যাপগুলির লিগ্যাসি সিস্টেম বা হার্ডওয়্যার ডিভাইসগুলির সাথে যোগাযোগ করার ক্ষমতা সীমিত করে যা তাদের নিজস্ব নন-ওয়েব প্রোটোকল ব্যবহার করে। উদাহরণস্বরূপ, আপনি একটি ওয়েব-ভিত্তিক SSH ক্লায়েন্ট তৈরি করতে, একটি স্থানীয় প্রিন্টারের সাথে সংযোগ করতে, অথবা IoT ডিভাইসের একটি বহর পরিচালনা করতে চাইতে পারেন। ঐতিহাসিকভাবে, এর জন্য ব্রাউজার প্লাগইন বা স্থানীয় সহায়ক অ্যাপ্লিকেশনের প্রয়োজন ছিল।
ডাইরেক্ট সকেটস এপিআই এই সীমাবদ্ধতা মোকাবেলা করে আইসোলেটেড ওয়েব অ্যাপস (IWAs) কে রিলে সার্ভার ছাড়াই সরাসরি TCP এবং UDP সংযোগ স্থাপন করতে সক্ষম করে। IWAs এর মাধ্যমে, অতিরিক্ত সুরক্ষা ব্যবস্থার জন্য ধন্যবাদ - যেমন কঠোর কন্টেন্ট সিকিউরিটি পলিসি (CSP) এবং ক্রস-অরিজিন আইসোলেশন - এই এপিআই নিরাপদে প্রকাশ করা যেতে পারে।
ব্যবহারের ক্ষেত্রে
স্ট্যান্ডার্ড ওয়েবসকেটের পরিবর্তে কখন আপনার ডাইরেক্ট সকেট ব্যবহার করা উচিত?
- আইওটি এবং স্মার্ট ডিভাইস: HTTP-র পরিবর্তে কাঁচা TCP/UDP ব্যবহার করে এমন হার্ডওয়্যারের সাথে যোগাযোগ করা।
- লিগ্যাসি সিস্টেম: পুরোনো মেল সার্ভার (SMTP/IMAP), IRC চ্যাট সার্ভার, অথবা প্রিন্টারের সাথে সংযোগ স্থাপন।
- রিমোট ডেস্কটপ এবং টার্মিনাল: SSH, Telnet, অথবা RDP ক্লায়েন্ট বাস্তবায়ন করা।
- P2P সিস্টেম: ডিস্ট্রিবিউটেড হ্যাশ টেবিল (DHT) বা স্থিতিস্থাপক সহযোগিতা সরঞ্জাম (যেমন IPFS) বাস্তবায়ন করা।
- মিডিয়া সম্প্রচার: একসাথে একাধিক এন্ডপয়েন্টে কন্টেন্ট স্ট্রিম করার জন্য UDP ব্যবহার করা (মাল্টিকাস্টিং), খুচরা কিয়স্কের নেটওয়ার্ক জুড়ে সমন্বিত ভিডিও প্লেব্যাকের মতো ব্যবহারের ক্ষেত্রে সক্ষম করে।
- সার্ভার এবং শ্রোতাদের ক্ষমতা:
TCPServerSocketবা বাউন্ডUDPSocketব্যবহার করে ইনকামিং TCP সংযোগ বা UDP ডেটাগ্রামের জন্য IWA কে একটি রিসিভিং এন্ডপয়েন্ট হিসেবে কাজ করার জন্য কনফিগার করা।
ডাইরেক্ট সকেটের জন্য পূর্বশর্ত
ডাইরেক্ট সকেট ব্যবহার করার আগে, আপনাকে একটি কার্যকরী IWA সেট আপ করতে হবে। তারপর আপনি আপনার পৃষ্ঠাগুলিতে ডাইরেক্ট সকেট সংহত করতে পারেন।
অনুমতি নীতি যোগ করুন
ডাইরেক্ট সকেট ব্যবহার করার জন্য, আপনাকে আপনার IWA ম্যানিফেস্টে permissions_policy অবজেক্টটি কনফিগার করতে হবে। API স্পষ্টভাবে সক্ষম করার জন্য আপনাকে direct-sockets কী যোগ করতে হবে। অতিরিক্তভাবে, আপনাকে cross-origin-isolated কী অন্তর্ভুক্ত করতে হবে। এই কীটি ডাইরেক্ট সকেটের জন্য নির্দিষ্ট নয়, তবে সমস্ত IWA-এর জন্য প্রয়োজনীয় এবং এটি নির্ধারণ করে যে ডকুমেন্টটি ক্রস-অরিজিন আইসোলেশনের প্রয়োজন এমন API অ্যাক্সেস করতে পারে কিনা।
{
"permissions_policy": {
"direct-sockets": ["self"],
"cross-origin-isolated": ["self"]
}
}
direct-sockets কী নির্ধারণ করে যে new TCPSocket(...) , new TCPServerSocket(...) অথবা new UDPSocket(...) এ কল করার অনুমতি আছে কিনা। যদি এই নীতি সেট না করা থাকে, তাহলে এই কনস্ট্রাক্টরগুলি অবিলম্বে NotAllowedError দিয়ে প্রত্যাখ্যান করবে।
TCPSocket বাস্তবায়ন করুন
অ্যাপ্লিকেশনগুলি একটি TCPSocket ইনস্ট্যান্স তৈরি করে একটি TCP সংযোগের অনুরোধ করতে পারে।
একটি সংযোগ খুলুন
সংযোগ খুলতে, new অপারেটর ব্যবহার করুন এবং খোলা প্রতিশ্রুতির জন্য await ।
TCPSocket কনস্ট্রাক্টর নির্দিষ্ট remoteAddress এবং remotePort ব্যবহার করে সংযোগ শুরু করে।
const remoteAddress = 'example.com';
const remotePort = 7;
// Configure options like keepAlive or buffering
const options = {
keepAlive: true,
keepAliveDelay: 720000
};
let tcpSocket = new TCPSocket(remoteAddress, remotePort, options);
// Wait for the connection to be established
let { readable, writable } = await tcpSocket.opened;
ঐচ্ছিক কনফিগারেশন অবজেক্টটি সূক্ষ্ম নেটওয়ার্ক নিয়ন্ত্রণের অনুমতি দেয়; এই নির্দিষ্ট ক্ষেত্রে, নিষ্ক্রিয়তার সময় সংযোগ বজায় রাখার জন্য keepAliveDelay 720000 মিলিসেকেন্ডে সেট করা হয়। ডেভেলপাররা এখানে অন্যান্য বৈশিষ্ট্যও কনফিগার করতে পারেন, যেমন noDelay , যা Nagle-এর অ্যালগরিদমকে অক্ষম করে যাতে সিস্টেমটি ছোট প্যাকেটগুলি ব্যাচ করা বন্ধ করে দেয়—যা সম্ভাব্যভাবে লেটেন্সি হ্রাস করে—অথবা থ্রুপুট পরিচালনা করার জন্য sendBufferSize এবং receiveBufferSize ব্যবহার করে।
পূর্ববর্তী স্নিপেটের শেষ অংশে, কোডটি খোলা প্রতিশ্রুতির জন্য অপেক্ষা করছে, যা হ্যান্ডশেক সম্পূর্ণ হওয়ার পরেই সমাধান হয়, ডেটা ট্রান্সমিশনের জন্য প্রয়োজনীয় পঠনযোগ্য এবং লেখাযোগ্য স্ট্রিম ধারণকারী একটি TCPSocketOpenInfo অবজেক্ট ফেরত দেয়।
পড়ুন এবং লিখুন
সকেটটি খোলা হয়ে গেলে, স্ট্যান্ডার্ড স্ট্রিমস এপিআই ইন্টারফেস ব্যবহার করে এর সাথে ইন্টারঅ্যাক্ট করুন।
- লেখা: লেখার যোগ্য স্ট্রিমটি একটি
BufferSourceগ্রহণ করে (যেমন একটিArrayBuffer)। - পঠন: পঠনযোগ্য স্ট্রিমটি
Uint8Arrayডেটা প্রদান করে।
// Writing data
const writer = writable.getWriter();
const encoder = new TextEncoder();
await writer.write(encoder.encode("Hello Server"));
// Call when done
writer.releaseLock();
// Reading data
const reader = readable.getReader();
const { value, done } = await reader.read();
if (!done) {
const decoder = new TextDecoder();
console.log("Received:", decoder.decode(value));
}
// Call when done
reader.releaseLock();
BYOB এর সাথে অপ্টিমাইজড রিডিং
উচ্চ-কার্যক্ষমতা সম্পন্ন অ্যাপ্লিকেশনগুলির জন্য যেখানে মেমরি বরাদ্দকরণ পরিচালনা করা অত্যন্ত গুরুত্বপূর্ণ, API "Bring Your Own Buffer" (BYOB) রিডিং সমর্থন করে। প্রাপ্ত প্রতিটি ডেটার জন্য ব্রাউজারকে একটি নতুন বাফার বরাদ্দ করার পরিবর্তে, আপনি পাঠকের কাছে একটি পূর্ব-বরাদ্দকৃত বাফার প্রেরণ করতে পারেন। এটি আপনার বিদ্যমান মেমরিতে সরাসরি ডেটা লিখে আবর্জনা সংগ্রহের ওভারহেড হ্রাস করে।
// 1. Get a BYOB reader explicitly
const reader = readable.getReader({ mode: 'byob' });
// 2. Allocate a reusable buffer (e.g., 4KB)
let buffer = new Uint8Array(4096);
// 3. Read directly into the existing buffer
const { value, done } = await reader.read(buffer);
if (!done) {
// 'value' is a view of the data written directly into your buffer
console.log("Bytes received:", value.byteLength);
}
reader.releaseLock();
UDPSocket বাস্তবায়ন করুন
UDPSocket ক্লাসটি UDP যোগাযোগের অনুমতি দেয়। আপনি কীভাবে বিকল্পগুলি কনফিগার করেন তার উপর নির্ভর করে এটি দুটি স্বতন্ত্র মোডে কাজ করে।
সংযুক্ত মোড
এই মোডে, সকেটটি একটি নির্দিষ্ট গন্তব্যের সাথে যোগাযোগ করে। এটি স্ট্যান্ডার্ড ক্লায়েন্ট-সার্ভার কাজের জন্য কার্যকর।
// Connect to a specific remote host
let udpSocket = new UDPSocket({
remoteAddress: 'example.com',
remotePort: 7 });
let { readable, writable } = await udpSocket.opened;
বাউন্ড মোড
এই মোডে, সকেটটি একটি স্থানীয় আইপি এন্ডপয়েন্টের সাথে আবদ্ধ থাকে। এটি ইচ্ছামত উৎস থেকে ডেটাগ্রাম গ্রহণ করতে পারে এবং ইচ্ছামত গন্তব্যে পাঠাতে পারে। এটি প্রায়শই স্থানীয় আবিষ্কার প্রোটোকল বা সার্ভার-সদৃশ আচরণের জন্য ব্যবহৃত হয়।
// Bind to all interfaces (IPv6)
let udpSocket = new UDPSocket({
localAddress: '::'
// omitting localPort lets the OS pick one
});
// localPort will tell you the OS-selected port.
let { readable, writable, localPort } = await udpSocket.opened;
UDP বার্তা পরিচালনা করুন
TCP বাইটের স্ট্রিম থেকে ভিন্ন, UDP স্ট্রিমগুলি UDPMessage অবজেক্টে কাজ করে, যার মধ্যে ডেটা এবং রিমোট অ্যাড্রেস তথ্য থাকে। নিম্নলিখিত কোডটি "বাউন্ড মোডে" UDPSocket ব্যবহার করার সময় ইনপুট/আউটপুট অপারেশনগুলি কীভাবে পরিচালনা করতে হয় তা দেখায়।
// Writing (Bound Mode requires specifying destination)
const writer = writable.getWriter();
await writer.write({
data: new TextEncoder().encode("Ping"),
remoteAddress: '192.168.1.50',
remotePort: 8080
});
// Reading
const reader = readable.getReader();
const { value } = await reader.read();
// value contains: { data, remoteAddress, remotePort }
console.log(`Received from ${value.remoteAddress}:`, value.data);
"সংযুক্ত মোড" এর বিপরীতে, যেখানে সকেটটি একটি নির্দিষ্ট পিয়ারের সাথে লক করা থাকে, বাউন্ড মোড সকেটকে ইচ্ছামত গন্তব্যস্থলের সাথে যোগাযোগ করতে দেয়। ফলস্বরূপ, লেখার যোগ্য স্ট্রীমে ডেটা লেখার সময়, আপনাকে একটি UDPMessage অবজেক্ট পাস করতে হবে যা প্রতিটি প্যাকেটের জন্য remoteAddress এবং remotePort স্পষ্টভাবে নির্দিষ্ট করে, সকেটকে নির্দেশ দেয় যে সেই নির্দিষ্ট ডেটাগ্রামটি কোথায় রুট করতে হবে। একইভাবে, পঠনযোগ্য স্ট্রীম থেকে পড়ার সময়, ফেরত দেওয়া মানটিতে কেবল ডেটা পেলোডই নয় বরং প্রেরকের remoteAddress এবং remotePort ও অন্তর্ভুক্ত থাকে, যা আপনার অ্যাপ্লিকেশনকে প্রতিটি আগত প্যাকেটের উৎপত্তি সনাক্ত করতে সক্ষম করে।
দ্রষ্টব্য: "সংযুক্ত মোডে" UDPSocket ব্যবহার করার সময়, সকেটটি কার্যকরভাবে একটি নির্দিষ্ট পিয়ারে লক করা হয়, যা I/O প্রক্রিয়াটিকে সহজ করে তোলে। এই মোডে, লেখার সময় remoteAddress এবং remotePort বৈশিষ্ট্যগুলি কার্যকরভাবে নো-অপস হয়, কারণ গন্তব্য ইতিমধ্যেই স্থির করা আছে। একইভাবে, বার্তা পড়ার সময়, এই বৈশিষ্ট্যগুলি null ফিরে আসবে, কারণ উৎসটি সংযুক্ত পিয়ার হওয়ার নিশ্চয়তা রয়েছে।
মাল্টিকাস্ট সাপোর্ট
একাধিক কিয়স্ক জুড়ে ভিডিও প্লেব্যাক সিঙ্ক্রোনাইজ করা বা স্থানীয় ডিভাইস আবিষ্কার (উদাহরণস্বরূপ, mDNS) বাস্তবায়নের মতো ব্যবহারের ক্ষেত্রে, ডাইরেক্ট সকেটস মাল্টিকাস্ট UDP সমর্থন করে। এটি বার্তাগুলিকে একটি "গ্রুপ" ঠিকানায় পাঠানোর এবং নেটওয়ার্কের সমস্ত গ্রাহকদের দ্বারা গ্রহণ করার অনুমতি দেয়, একটি নির্দিষ্ট পিয়ারের পরিবর্তে।
মাল্টিকাস্ট অনুমতি
মাল্টিকাস্ট ক্ষমতা ব্যবহার করার জন্য, আপনাকে অবশ্যই আপনার IWA ম্যানিফেস্টে নির্দিষ্ট direct-sockets-multicast অনুমতি যোগ করতে হবে। এটি স্ট্যান্ডার্ড ডাইরেক্ট-সকেট অনুমতি থেকে আলাদা এবং এটি প্রয়োজনীয় কারণ মাল্টিকাস্ট শুধুমাত্র ব্যক্তিগত নেটওয়ার্কগুলিতে ব্যবহৃত হয়।
{
"permissions_policy": {
"direct-sockets": ["self"],
"direct-sockets-multicast": ["self"],
"direct-sockets-private": ["self"],
"cross-origin-isolated": ["self"]
}
}
মাল্টিকাস্ট ডেটাগ্রাম পাঠান
মাল্টিকাস্ট গ্রুপে পাঠানো স্ট্যান্ডার্ড UDP "সংযুক্ত মোড" এর অনুরূপ, যেখানে প্যাকেট আচরণ নিয়ন্ত্রণের জন্য নির্দিষ্ট বিকল্পগুলি যুক্ত করা হয়।
const MULTICAST_GROUP = '239.0.0.1';
const PORT = 12345;
const socket = new UDPSocket({
remoteAddress: MULTICAST_GROUP,
remotePort: PORT,
// Time To Live: How many router hops the packet can survive (default: 1)
multicastTimeToLive: 5,
// Loopback: Whether to receive your own packets (default: true)
multicastLoopback: true
});
const { writable } = await socket.opened;
// Write to the stream as usual...
মাল্টিকাস্ট ডেটাগ্রাম গ্রহণ করুন
মাল্টিকাস্ট ট্র্যাফিক পেতে, আপনাকে "বাউন্ড মোডে" একটি UDPSocket খুলতে হবে (সাধারণত 0.0.0.0 বা :: এর সাথে আবদ্ধ) এবং তারপর MulticastController ব্যবহার করে একটি নির্দিষ্ট গ্রুপে যোগদান করতে হবে। আপনি multicastAllowAddressSharing বিকল্পটিও ব্যবহার করতে পারেন (ইউনিক্সে SO_REUSEADDR এর অনুরূপ), যা ডিভাইস আবিষ্কার প্রোটোকলের জন্য অপরিহার্য যেখানে একই ডিভাইসে একাধিক অ্যাপ্লিকেশনকে একই পোর্ট শুনতে হয়।
const socket = new UDPSocket({
localAddress: '0.0.0.0', // Listen on all interfaces
localPort: 12345,
multicastAllowAddressSharing: true // Allow multiple applications to bind to the same address / port pair.
});
// The open info contains the MulticastController
const { readable, multicastController } = await socket.opened;
// Join the group to start receiving packets
await multicastController.joinGroup('239.0.0.1');
const reader = readable.getReader();
// Read the stream...
const { value } = await reader.read();
console.log(`Received multicast from ${value.remoteAddress}`);
// When finished, you can leave the group (this is an optional, but recommended practice)
await multicastController.leaveGroup('239.0.0.1');
একটি সার্ভার তৈরি করুন
API টিসিপি সার্ভারসকেটকে ইনকামিং টিসিপি সংযোগ গ্রহণের জন্য সমর্থন করে, যা কার্যকরভাবে আপনার আইডাব্লিউএকে স্থানীয় সার্ভার হিসেবে কাজ করার অনুমতি দেয়। নিম্নলিখিত কোডটি TCPServerSocket ইন্টারফেস ব্যবহার করে কীভাবে একটি টিসিপি সার্ভার স্থাপন করবেন তা ব্যাখ্যা করে।
// Listen on all interfaces (IPv6)
let tcpServerSocket = new TCPServerSocket('::');
// Accept connections via the readable stream
let { readable } = await tcpServerSocket.opened;
let reader = readable.getReader();
// Wait for a client to connect
let { value: clientSocket } = await reader.read();
// 'clientSocket' is a standard TCPSocket you can now read/write to
'::' ঠিকানা দিয়ে ক্লাসটি ইনস্ট্যান্টিয়েট করে, সার্ভারটি সমস্ত উপলব্ধ IPv6 নেটওয়ার্ক ইন্টারফেসের সাথে আবদ্ধ হয় যাতে ইনকামিং প্রচেষ্টা শোনা যায়। ঐতিহ্যবাহী কলব্যাক-ভিত্তিক সার্ভার API-এর বিপরীতে, এই API ওয়েবের Streams API প্যাটার্ন ব্যবহার করে: ইনকামিং সংযোগগুলি ReadableStream হিসাবে সরবরাহ করা হয়। যখন আপনি reader.read() কল করেন, তখন অ্যাপ্লিকেশনটি কিউ থেকে পরবর্তী সংযোগের জন্য অপেক্ষা করে এবং গ্রহণ করে, একটি মান সমাধান করে যা সম্পূর্ণরূপে কার্যকরী TCPSocket ইনস্ট্যান্স যা সেই নির্দিষ্ট ক্লায়েন্টের সাথে দ্বি-মুখী যোগাযোগের জন্য প্রস্তুত।
Chrome DevTools ব্যবহার করে ডাইরেক্ট সকেট ডিবাগ করুন
Chrome 138 থেকে, আপনি Chrome DevTools-এর নেটওয়ার্ক প্যানেলের মধ্যে সরাসরি Direct Sockets ট্র্যাফিক ডিবাগ করতে পারেন, যার ফলে বহিরাগত প্যাকেট স্নিফারের প্রয়োজন হয় না। এই টুলিং আপনাকে আপনার স্ট্যান্ডার্ড HTTP অনুরোধের পাশাপাশি TCPSocket সংযোগের পাশাপাশি UDPSocket ট্র্যাফিক (বাউন্ড এবং কানেক্টেড উভয় মোডে) পর্যবেক্ষণ করতে দেয়।
আপনার অ্যাপের নেটওয়ার্ক কার্যকলাপ পরীক্ষা করতে:
- Chrome DevTools-এ নেটওয়ার্ক প্যানেলটি খুলুন।
- অনুরোধ টেবিলে সকেট সংযোগটি সনাক্ত করুন এবং নির্বাচন করুন।
- সমস্ত প্রেরিত এবং প্রাপ্ত ডেটার লগ দেখতে বার্তা ট্যাবটি খুলুন।

এই ভিউটি একটি হেক্স ভিউয়ার প্রদান করে, যা আপনাকে আপনার TCP এবং UDP বার্তাগুলির কাঁচা বাইনারি পেলোড পরিদর্শন করতে দেয়, নিশ্চিত করে যে আপনার প্রোটোকল বাস্তবায়ন বাইট-নিখুঁত।
ডেমো
IWA কিচেন সিঙ্কে একাধিক ট্যাব সহ একটি অ্যাপ রয়েছে, প্রতিটি ট্যাবে ডাইরেক্ট সকেট, নিয়ন্ত্রিত ফ্রেম এবং আরও অনেক কিছুর মতো আলাদা IWA API দেখানো হয়েছে।
অন্যথায়, টেলনেট ক্লায়েন্ট ডেমোতে একটি আইসোলেটেড ওয়েব অ্যাপ থাকে যা ব্যবহারকারীকে একটি ইন্টারেক্টিভ টার্মিনালের মাধ্যমে একটি TCP/IP সার্ভারের সাথে সংযোগ স্থাপন করতে দেয়। অন্য কথায়, একটি টেলনেট ক্লায়েন্ট।
উপসংহার
ডাইরেক্ট সকেটস এপিআই ওয়েব অ্যাপ্লিকেশনগুলিকে কাঁচা নেটওয়ার্ক প্রোটোকল পরিচালনা করতে সক্ষম করে একটি গুরুত্বপূর্ণ কার্যকারিতা শূন্যতা পূরণ করে যা পূর্বে নেটিভ র্যাপার ছাড়া সমর্থন করা অসম্ভব ছিল। এটি সহজ ক্লায়েন্ট সংযোগের বাইরেও যায়; TCPServerSocket এর সাহায্যে, অ্যাপ্লিকেশনগুলি আগত সংযোগগুলি শুনতে পারে, যখন UDPSocket পিয়ার-টু-পিয়ার যোগাযোগ এবং স্থানীয় নেটওয়ার্ক আবিষ্কার উভয়ের জন্য নমনীয় মোড অফার করে।
আধুনিক Streams API-এর মাধ্যমে এই কাঁচা TCP এবং UDP ক্ষমতাগুলি প্রকাশ করে, আপনি এখন সরাসরি জাভাস্ক্রিপ্টে SSH, RDP, অথবা কাস্টম IoT স্ট্যান্ডার্ডের মতো লিগ্যাসি প্রোটোকলগুলির পূর্ণ-বৈশিষ্ট্যযুক্ত বাস্তবায়ন তৈরি করতে পারেন। যেহেতু এই API নিম্ন-স্তরের নেটওয়ার্ক অ্যাক্সেস প্রদান করে, এটি উল্লেখযোগ্য সুরক্ষা প্রভাব বহন করে। অতএব, এটি আইসোলেটেড ওয়েব অ্যাপস (IWAs)- এর মধ্যে সীমাবদ্ধ, নিশ্চিত করে যে এই ক্ষমতা শুধুমাত্র বিশ্বস্ত, স্পষ্টভাবে ইনস্টল করা অ্যাপ্লিকেশনগুলিকে দেওয়া হয় যা কঠোর সুরক্ষা নীতি প্রয়োগ করে। এই ভারসাম্য আপনাকে ওয়েব প্ল্যাটফর্ম থেকে ব্যবহারকারীদের প্রত্যাশা অনুযায়ী সুরক্ষা বজায় রেখে শক্তিশালী, ডিভাইস-কেন্দ্রিক অ্যাপ্লিকেশন তৈরি করতে দেয়।