socket
বছর পূর্বে কিছু (কম-বেশি বা কম) "নিম্ন-স্তরের" অ্যাসিঙ্ক প্রোগ্রামিং করার পরে (ইভেন্ট-ভিত্তিক অ্যাসিনক্রোনাস প্যাটার্ন (ইএপি) ফ্যাশনে) এবং সম্প্রতি একটি " TcpListener
অ্যাসিনক্রোনাস প্রোগ্রামিং মডেল (এপিএম) " তে সরানো এবং তারপরে async/await
(টাস্ক-ভিত্তিক অ্যাসিনক্রোনাস প্যাটার্ন (টিএপি) ) এ যাওয়ার চেষ্টা করলাম আমি এই সমস্ত 'নিম্ন স্তরের নদীর গভীরতানির্ণয়' নিয়ে বিরক্ত থাকার মতো অনেক কিছুই করেছি। সুতরাং আমি অনুমান ছিল; কেন RX
যেতে দেবেন না ( প্রতিক্রিয়াশীল এক্সটেনশানস ) যেহেতু এটি আমার সমস্যাযুক্ত ডোমেনে আরও বেশি ছড়িয়ে পড়ে।
আমার লিখিত প্রচুর কোডটি অনেক ক্লায়েন্টের সাথে আমার অ্যাপ্লিকেশনে টিসিপির সাথে সংযোগ স্থাপন করে যা এরপরে দ্বি-মুখী (অ্যাসিঙ্ক) যোগাযোগ শুরু করে। ক্লায়েন্ট বা সার্ভার যে কোনও মুহুর্তে কোনও বার্তা প্রেরণের প্রয়োজন এবং এটি করার সিদ্ধান্ত নিতে পারে, সুতরাং এটি আপনার ক্লাসিক request/response
সেটআপ নয় তবে উভয় পক্ষের কাছে যা খুশি তাই পাঠাতে রিয়েল-টাইম, দ্বিমুখী, "লাইন" খোলা রয়েছে যখনই তারা চায়। (কারও কাছে যদি এটি বর্ণনা করার জন্য একটি ভাল নাম থাকে তবে আমি এটি শুনে খুশি হব!)।
"প্রোটোকল" অ্যাপ্লিকেশন প্রতি পৃথক হয় (এবং আমার প্রশ্নের সাথে সত্যই প্রাসঙ্গিক নয়)। আমার অবশ্য প্রাথমিক প্রশ্ন আছে:
- প্রদত্ত যে কেবলমাত্র একটি "সার্ভার" চলছে, তবে এটির অভ্যন্তরীণ ট্র্যাক রাখতে তাদের "রাষ্ট্রীয় মেশিন" এর অনেকগুলি (সাধারণত হাজার হাজার) সংযোগের (যেমন ক্লায়েন্টদের) আরও ভাল বর্ণনার অভাব রয়েছে তাদের ট্র্যাক রাখতে হবে রাজ্য ইত্যাদি, আপনি কোন পদ্ধতির পছন্দ করবেন? ইএপি / টোকা / APM? আরএক্স এমনকি একটি বিকল্প হিসাবে বিবেচনা করা হবে? তা না হলে কেন?
সুতরাং, আমাকে অ্যাসিঙ্কের সাথে কাজ করা উচিত ক) এটি কোনও অনুরোধ / প্রতিক্রিয়া প্রোটোকল নয় তাই আমার "বার্তার অপেক্ষায়" ব্লকিং কল বা "বার্তা প্রেরণ" -ব্লকিং কলটিতে কোনও থ্রেড / ক্লায়েন্ট থাকতে পারে না তবে প্রেরণটি থাকলে কেবলমাত্র আমি তার সাথে থাকতে পারি) ক্লায়েন্টের জন্য ব্লকিং এবং) খ) আমার অনেক সমবর্তী সংযোগগুলি পরিচালনা করতে হবে। ব্লকিং কলগুলি ব্যবহার করে এটি (নির্ভরযোগ্যভাবে) করার কোনও উপায় আমি দেখতে পাচ্ছি না।
আমার অ্যাপ্লিকেশনগুলির বেশিরভাগই ভিওআইপি সম্পর্কিত; এটি এসআইপি সেন্টারগুলির এসআইপি বার্তা বা ফ্রিসুইচ / ওপেনসিআইপি ইত্যাদির মতো পিবিএক্স (সম্পর্কিত) বার্তাগুলি হতে পারে তবে আপনি এটি সহজতম ফর্মের মধ্যে অনেক "চ্যাট" ক্লায়েন্টকে পরিচালনা করার জন্য একটি "চ্যাট" সার্ভার কল্পনা করার চেষ্টা করতে পারেন। বেশিরভাগ প্রোটোকল হ'ল পাঠ্য ভিত্তিক (এএসসিআইআই)।
সুতরাং, পূর্বোক্ত কৌশলগুলির বিভিন্ন বিধি প্রয়োগ করার পরে আমি একটি বিষয় তৈরি করে আমার কাজটি সহজ করতে চাই যা আমি কেবল তাত্ক্ষণিকভাবে বলতে পারি, কোনটি IPEndpoint
শুনতে হবে তা বলুন এবং যখনই আগ্রহের কিছু চলছে তখন তা আমাকে বলতে হবে (যা আমি সাধারণত ইভেন্টগুলি ব্যবহার করুন, সুতরাং কিছু EAP সাধারণত অন্যান্য দুটি কৌশলগুলির সাথে মিশ্রিত হয়)। শ্রেণীর প্রোটোকলটি 'বোঝার' চেষ্টা করা বিরক্ত করা উচিত নয়; এটি কেবল ইনকামিং / আউটগোয়িং স্ট্রিংগুলি পরিচালনা করতে হবে। এবং এইভাবে, আরএক্সের প্রতি আমার নজর থাকায় আশা করা যায় যে (শেষ পর্যন্ত) কাজটি আরও সহজ করবে, আমি স্ক্র্যাচ থেকে একটি নতুন "ফ্রিডল" তৈরি করেছি:
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Reactive.Linq;
using System.Text;
class Program
{
static void Main(string[] args)
{
var f = new FiddleServer(new IPEndPoint(IPAddress.Any, 8084));
f.Start();
Console.ReadKey();
f.Stop();
Console.ReadKey();
}
}
public class FiddleServer
{
private TcpListener _listener;
private ConcurrentDictionary<ulong, FiddleClient> _clients;
private ulong _currentid = 0;
public IPEndPoint LocalEP { get; private set; }
public FiddleServer(IPEndPoint localEP)
{
this.LocalEP = localEP;
_clients = new ConcurrentDictionary<ulong, FiddleClient>();
}
public void Start()
{
_listener = new TcpListener(this.LocalEP);
_listener.Start();
Observable.While(() => true, Observable.FromAsync(_listener.AcceptTcpClientAsync)).Subscribe(
//OnNext
tcpclient =>
{
//Create new FSClient with unique ID
var fsclient = new FiddleClient(_currentid++, tcpclient);
//Keep track of clients
_clients.TryAdd(fsclient.ClientId, fsclient);
//Initialize connection
fsclient.Send("connect\n\n");
Console.WriteLine("Client {0} accepted", fsclient.ClientId);
},
//OnError
ex =>
{
},
//OnComplete
() =>
{
Console.WriteLine("Client connection initialized");
//Accept new connections
_listener.AcceptTcpClientAsync();
}
);
Console.WriteLine("Started");
}
public void Stop()
{
_listener.Stop();
Console.WriteLine("Stopped");
}
public void Send(ulong clientid, string rawmessage)
{
FiddleClient fsclient;
if (_clients.TryGetValue(clientid, out fsclient))
{
fsclient.Send(rawmessage);
}
}
}
public class FiddleClient
{
private TcpClient _tcpclient;
public ulong ClientId { get; private set; }
public FiddleClient(ulong id, TcpClient tcpclient)
{
this.ClientId = id;
_tcpclient = tcpclient;
}
public void Send(string rawmessage)
{
Console.WriteLine("Sending {0}", rawmessage);
var data = Encoding.ASCII.GetBytes(rawmessage);
_tcpclient.GetStream().WriteAsync(data, 0, data.Length); //Write vs WriteAsync?
}
}
আমি সচেতন যে, এই "ঝাঁকুনি" এ, কিছুটা বাস্তবায়নের সুনির্দিষ্ট বিশদ রয়েছে; এক্ষেত্রে আমি ফ্রিসুইচ ইএসএল নিয়ে কাজ করছি যাতে "connect\n\n"
আরও বেশি জেনেরিক পদ্ধতির উপর রিফ্যাক্ট করার সময় ফিডলে থাকা অপসারণ করা উচিত।
আমি এও সচেতন যে সার্ভার ক্লাসে আমার বেনাম পদ্ধতিগুলিকে ব্যক্তিগত উদাহরণ পদ্ধতিগুলির রিফ্যাক্টর করতে হবে; আমি ঠিক নিশ্চিত নই যে কোন পদ্ধতি (যেমন " OnSomething
" উদাহরণস্বরূপ) তাদের পদ্ধতি-নামের জন্য ব্যবহার করবেন?
এটি আমার ভিত্তি / শুরুর পয়েন্ট / ভিত্তি (যার জন্য কিছু "টুইট" প্রয়োজন)। এ সম্পর্কে আমার কিছু প্রশ্ন রয়েছে:
- উপরের প্রশ্নটি দেখুন "1"
- আমি কি সঠিক পথে রয়েছি? নাকি আমার "ডিজাইনের" সিদ্ধান্তগুলি অন্যায়?
- সংক্ষিপ্ত-ভিত্তিক: এটি হাজার হাজার ক্লায়েন্টের সাথে মোকাবেলা করবে (প্রকৃত বার্তাগুলিকে পার্সিং / পরিচালনা করে)
- ব্যতিক্রমগুলিতে: সার্ভারের কাছে "আপ" ক্লায়েন্টগুলির মধ্যে কীভাবে ব্যতিক্রমগুলি নেওয়া যায় তা আমি নিশ্চিত নই ("আরএক্স-ওয়াইজ"); একটি ভাল উপায় কি হবে?
- আমি এখন আমার সার্ভার ক্লাস থেকে যে কোনও সংযুক্ত ক্লায়েন্ট পেতে পারি (এটি ব্যবহার করে
ClientId
), ধরে নিচ্ছি যে আমি ক্লায়েন্টগুলিকে এক উপায়ে বা অন্য কোনও উপায়ে প্রকাশ করেছি এবং সেগুলিতে সরাসরি পদ্ধতিগুলি কল করি। আমি সার্ভার ক্লাসের মাধ্যমেও পদ্ধতিগুলি কল করতে পারি (উদাহরণস্বরূপ,Send(clientId, rawmessage)
পদ্ধতিটি (যেখানে পরবর্তী দিকটি দ্রুত অন্য দিকে কোনও বার্তা পাওয়ার জন্য "সুবিধা" পদ্ধতি হবে)। - এখান থেকে কোথায় (এবং কীভাবে) যাব আমি নিশ্চিত নই:
- ক) আমার আগত বার্তাগুলি পরিচালনা করতে হবে; আমি কিভাবে এটি সেট আপ করব? আমি অবশ্যই স্ট্রিম অফ কোর্স পেতে পারি তবে প্রাপ্ত বাইটগুলি পুনরুদ্ধার করতে আমি কোথায় পরিচালনা করব? আমি মনে করি আমার কোনও ধরণের "অবজার্ভ স্ট্রিম" দরকার যা আমি সাবস্ক্রাইব করতে পারি? আমি কি এটিতে রাখব
FiddleClient
নাকিFiddleServer
? - খ) ধরে নিচ্ছি যে এই
FiddleClient
/FiddleServer
ক্লাসগুলি আরও সুনির্দিষ্টFooClient
/FooServer
শ্রেণি ব্যবহার করে তাদের অ্যাপ্লিকেশন নির্দিষ্ট প্রোটোকল হ্যান্ডলিং ইত্যাদির জন্য নির্দিষ্টভাবে প্রয়োগ না করা পর্যন্ত আমি ইভেন্টটি ব্যবহার করা এড়াতে চাই : আমি কীভাবে তাদের অন্তর্নিহিত 'ফিডাল'-শ্রেণিতে ডেটা পেতে যাব? আরও নির্দিষ্ট অংশের?
- ক) আমার আগত বার্তাগুলি পরিচালনা করতে হবে; আমি কিভাবে এটি সেট আপ করব? আমি অবশ্যই স্ট্রিম অফ কোর্স পেতে পারি তবে প্রাপ্ত বাইটগুলি পুনরুদ্ধার করতে আমি কোথায় পরিচালনা করব? আমি মনে করি আমার কোনও ধরণের "অবজার্ভ স্ট্রিম" দরকার যা আমি সাবস্ক্রাইব করতে পারি? আমি কি এটিতে রাখব
নিবন্ধ / লিঙ্কগুলি আমি ইতিমধ্যে পড়তে / স্কিমড / রেফারেন্সের জন্য ব্যবহার করেছি:
- প্রতিক্রিয়াশীল এক্সটেনশন ব্যবহার করে সকেট গ্রহণ করুন
- সাধারণ পর্যবেক্ষণযোগ্য ক্রমগুলি তৈরি এবং সাবস্ক্রাইব করা
- প্রতিটি পর্যবেক্ষণযোগ্য টিসিপিলিস্টনার সংযোগ / সেশনে কীভাবে প্রসঙ্গ যুক্ত বা যুক্ত করতে হয়
- প্রতিক্রিয়াশীল ফ্রেমওয়ার্ক এবং টাস্ক সমান্তরাল গ্রন্থাগার - অধ্যায় 1 , 2 এবং 3 সহ অ্যাসিঙ্ক্রোনাস প্রোগ্রামিং ।
- সকেট প্রোগ্রামিং ব্যবহারিকের জন্য প্রতিক্রিয়াশীল এক্সটেনশনগুলি (আরএক্স) ব্যবহার করছেন?
- একটি। নেট আরএক্স চালিত ওয়েব সার্ভার এবং। নেট আরএক্স চালিত ওয়েব সার্ভার, 2 নিন
- কিছু আরএক্স টিউটোরিয়াল