C# Language
अतुल्यकालिक सॉकेट
खोज…
परिचय
अतुल्यकालिक सॉकेट्स का उपयोग करके एक सर्वर आने वाले कनेक्शनों के लिए सुन सकता है और समकालिक सॉकेट के विपरीत मतलब समय में कुछ अन्य तर्क कर सकता है जब वे सुन रहे होते हैं कि वे मुख्य धागे को ब्लॉक करते हैं और एप्लिकेशन अप्रतिसादी हो रहा है जब तक कि एक क्लाइंट कनेक्ट नहीं होता।
टिप्पणियों
सॉकेट और नेटवर्क
अपने स्वयं के नेटवर्क के बाहर एक सर्वर का उपयोग कैसे करें? यह एक सामान्य प्रश्न है और जब यह पूछा जाता है तो अधिकतर विषय के रूप में चिह्नित किया जाता है।
सर्वर साइड
अपने सर्वर के नेटवर्क पर आपको अपने राउटर को अपने सर्वर पर पोर्ट करना होगा।
उदाहरण के लिए पीसी जहां सर्वर चल रहा है:
स्थानीय आईपी = 192.168.1.115
सर्वर 1234 पोर्ट को सुन रहा है।
Port 1234
राउटर पर आने वाले कनेक्शन को 192.168.1.115
पर फॉरवर्ड 192.168.1.115
ग्राहक की ओर
केवल एक चीज जिसे आपको बदलने की आवश्यकता है वह है आईपी। आप अपने लूपबैक पते से कनेक्ट नहीं करना चाहते हैं लेकिन आपके सर्वर पर चल रहे नेटवर्क से सार्वजनिक आईपी पर। यह आईपी आप यहां प्राप्त कर सकते हैं ।
_connectingSocket.Connect(new IPEndPoint(IPAddress.Parse("10.10.10.10"), 1234));
तो अब आप इस अंतिम बिंदु पर एक अनुरोध बनाते हैं: 10.10.10.10:1234
यदि आपने प्रॉपर्टी पोर्ट को राउटर से आगे किया तो आपका सर्वर और क्लाइंट बिना किसी समस्या के जुड़ जाएंगे।
यदि आप एक स्थानीय आईपी से कनेक्ट करना चाहते हैं, तो आपको लूपबैक एड्रेस को बदलकर 192.168.1.178
या कुछ ऐसा ही करना होगा।
डेटा भेजना:
डेटा बाइट सरणी में भेजा जाता है। आपको एक बाइट सरणी में डेटा को पैक करने और इसे दूसरी तरफ अनपैक करने की आवश्यकता है।
यदि आप सॉकेट से परिचित हैं तो आप भेजने से पहले अपने बाइट सरणी को एन्क्रिप्ट करने का प्रयास कर सकते हैं। यह आपके पैकेज को चुराने से किसी को भी रोक देगा।
एसिंक्रोनस सॉकेट (क्लाइंट / सर्वर) उदाहरण।
सर्वर साइड उदाहरण
सर्वर के लिए श्रोता बनाएँ
एक सर्वर बनाने के साथ शुरू करें जो कनेक्ट करने वाले क्लाइंट्स को हैंडल करेगा, और जो अनुरोध भेजे जाएंगे। इसलिए एक श्रोता वर्ग बनाएं जो इसे संभाल लेगा।
class Listener
{
public Socket ListenerSocket; //This is the socket that will listen to any incoming connections
public short Port = 1234; // on this port we will listen
public Listener()
{
ListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
}
पहले हमें श्रोता सॉकेट को इनिशियलाइज़ करना होगा जहाँ हम किसी भी कनेक्शन के लिए सुन सकते हैं। हम एक Tcp सॉकेट का उपयोग करने जा रहे हैं यही कारण है कि हम SocketType.Stream का उपयोग करते हैं। इसके अलावा, हम डायन पोर्ट को निर्दिष्ट करते हैं जिसे सर्वर को सुनना चाहिए
फिर हम किसी भी आने वाले कनेक्शन के लिए सुनना शुरू करते हैं।
हमारे द्वारा उपयोग किए जाने वाले पेड़ के तरीके हैं:
यह विधि सॉकेट को IPEndPoint से बांधती है । इस वर्ग में होस्ट और स्थानीय या दूरस्थ पोर्ट जानकारी होती है जो किसी होस्ट पर सेवा से जुड़ने के लिए किसी एप्लिकेशन द्वारा आवश्यक होती है।
बैकलॉग पैरामीटर आने वाले कनेक्शनों की संख्या को निर्दिष्ट करता है जिन्हें स्वीकृति के लिए कतारबद्ध किया जा सकता है।
ListenerSocket.BeginAccept ();
सर्वर आने वाले कनेक्शनों के लिए सुनना शुरू कर देगा और अन्य तर्क के साथ आगे बढ़ेगा। जब कोई कनेक्शन होता है तो सर्वर इस विधि पर वापस आ जाता है और AcceptCallBack मेथड को चलाएगा
public void StartListening()
{
try
{
MessageBox.Show($"Listening started port:{Port} protocol type: {ProtocolType.Tcp}");
ListenerSocket.Bind(new IPEndPoint(IPAddress.Any, Port));
ListenerSocket.Listen(10);
ListenerSocket.BeginAccept(AcceptCallback, ListenerSocket);
}
catch(Exception ex)
{
throw new Exception("listening error" + ex);
}
}
इसलिए जब कोई ग्राहक जुड़ता है तो हम उन्हें इस विधि से स्वीकार कर सकते हैं:
तीन तरीकों का उपयोग कर रहे हैं यहाँ हैं:
हमने
Listener.BeginAccept()
साथ कॉलबैक शुरू किया, अब हमें उस कॉल को वापस समाप्त करना है।The EndAccept()
विधि एक IAsyncResult पैरामीटर को स्वीकार करता है, यह एसिंक्रोनस विधि की स्थिति को संग्रहीत करेगा, इस स्थिति से हम सॉकेट को निकाल सकते हैं जहां से आने वाला कनेक्शन आ रहा था।ClientController.AddClient()
EndAccept()
से हमें जो सॉकेट मिला है,EndAccept()
साथ हम खुद की बनाई विधि के साथ एक क्लाइंट बनाते हैं (कोड क्लाइंटकंट्रोलर सर्वर उदाहरण के नीचे) ।नए कनेक्शन को संभालने के साथ सॉकेट किए जाने पर हमें फिर से सुनना शुरू करना होगा। इस कॉलबैक को पकड़ने वाले तरीके को पास करें। और श्रोता सॉकेट को भी पास करें ताकि हम आगामी कनेक्शन के लिए इस सॉकेट का पुनः उपयोग कर सकें।
public void AcceptCallback(IAsyncResult ar)
{
try
{
Console.WriteLine($"Accept CallBack port:{Port} protocol type: {ProtocolType.Tcp}");
Socket acceptedSocket = ListenerSocket.EndAccept(ar);
ClientController.AddClient(acceptedSocket);
ListenerSocket.BeginAccept(AcceptCallback, ListenerSocket);
}
catch (Exception ex)
{
throw new Exception("Base Accept error"+ ex);
}
}
अब हमारे पास एक सुनने वाला सॉकेट है लेकिन हम ग्राहक द्वारा डेटा भेजने को कैसे प्राप्त करते हैं जो कि अगला कोड दिखा रहा है।
प्रत्येक ग्राहक के लिए सर्वर रिसीवर बनाएँ
पैरामीटर के रूप में सॉकेट में लेने वाले कंस्ट्रक्टर के साथ एक प्राप्त वर्ग बनाएं:
public class ReceivePacket
{
private byte[] _buffer;
private Socket _receiveSocket;
public ReceivePacket(Socket receiveSocket)
{
_receiveSocket = receiveSocket;
}
}
अगली विधि में हम पहले बफर को 4 बाइट्स (Int32) का आकार देने के साथ शुरू करते हैं या पैकेज में {lenght, वास्तविक डेटा} भाग होते हैं। तो पहले 4 बाइट्स हम वास्तविक डेटा के लिए बाकी डेटा की कमी के लिए आरक्षित करते हैं।
अगला हम BeginReceive () पद्धति का उपयोग करते हैं। इस विधि का उपयोग कनेक्टेड क्लाइंट्स से प्राप्त करना शुरू करने के लिए किया जाता है और जब यह डेटा प्राप्त करेगा तो यह ReceiveCallback
फ़ंक्शन को ReceiveCallback
।
public void StartReceiving()
{
try
{
_buffer = new byte[4];
_receiveSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch {}
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
// if bytes are less than 1 takes place when a client disconnect from the server.
// So we run the Disconnect function on the current client
if (_receiveSocket.EndReceive(AR) > 1)
{
// Convert the first 4 bytes (int 32) that we received and convert it to an Int32 (this is the size for the coming data).
_buffer = new byte[BitConverter.ToInt32(_buffer, 0)];
// Next receive this data into the buffer with size that we did receive before
_receiveSocket.Receive(_buffer, _buffer.Length, SocketFlags.None);
// When we received everything its onto you to convert it into the data that you've send.
// For example string, int etc... in this example I only use the implementation for sending and receiving a string.
// Convert the bytes to string and output it in a message box
string data = Encoding.Default.GetString(_buffer);
MessageBox.Show(data);
// Now we have to start all over again with waiting for a data to come from the socket.
StartReceiving();
}
else
{
Disconnect();
}
}
catch
{
// if exeption is throw check if socket is connected because than you can startreive again else Dissconect
if (!_receiveSocket.Connected)
{
Disconnect();
}
else
{
StartReceiving();
}
}
}
private void Disconnect()
{
// Close connection
_receiveSocket.Disconnect(true);
// Next line only apply for the server side receive
ClientController.RemoveClient(_clientId);
// Next line only apply on the Client Side receive
Here you want to run the method TryToConnect()
}
इसलिए हमने एक सर्वर सेटअप किया है जो आने वाले कनेक्शन के लिए प्राप्त कर सकता है और सुन सकता है। जब एक क्लाइंट कनेक्ट होता है तो इसे क्लाइंट की सूची में जोड़ा जाएगा और हर क्लाइंट की अपनी प्राप्त कक्षा होगी। सर्वर को सुनने के लिए:
Listener listener = new Listener();
listener.StartListening();
कुछ कक्षाएं मैं इस उदाहरण में उपयोग करता हूं
class Client
{
public Socket _socket { get; set; }
public ReceivePacket Receive { get; set; }
public int Id { get; set; }
public Client(Socket socket, int id)
{
Receive = new ReceivePacket(socket, id);
Receive.StartReceiving();
_socket = socket;
Id = id;
}
}
static class ClientController
{
public static List<Client> Clients = new List<Client>();
public static void AddClient(Socket socket)
{
Clients.Add(new Client(socket,Clients.Count));
}
public static void RemoveClient(int id)
{
Clients.RemoveAt(Clients.FindIndex(x => x.Id == id));
}
}
क्लाइंट साइड उदाहरण
सर्वर से सम्बद्ध कर रहा है
सबसे पहले हम एक वर्ग बनाना चाहते हैं जो सर्वर ते नाम से जोड़ता है जो हम इसे देते हैं: कनेक्टर:
class Connector
{
private Socket _connectingSocket;
}
इस वर्ग के लिए अगली विधि TryToConnect () है
इस विधि में कुछ ब्याज की चीजें मिलेंगी:
सॉकेट बनाएं;
सॉकेट कनेक्ट होने तक अगला आई लूप
हर लूप यह केवल 1 सेकंड के लिए थ्रेड को पकड़े हुए है हम सर्वर XD को डॉस नहीं करना चाहते हैं
कनेक्ट () के साथ यह सर्वर से कनेक्ट करने का प्रयास करेगा। यदि यह विफल रहता है तो यह एक अपवाद को फेंक देगा लेकिन wile प्रोग्राम को सर्वर से कनेक्ट रखेगा। आप इसके लिए कनेक्ट कॉलबैक विधि का उपयोग कर सकते हैं, लेकिन मैं केवल एक विधि को कॉल करने के लिए जाऊंगा जब सॉकेट जुड़ा हुआ है।
ध्यान दें कि क्लाइंट अब पोर्ट 1234 पर अपने स्थानीय पीसी से कनेक्ट होने का प्रयास कर रहा है।
public void TryToConnect() { _connectingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); while (!_connectingSocket.Connected) { Thread.Sleep(1000); try { _connectingSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234)); } catch { } } SetupForReceiveing(); } } private void SetupForReceiveing() { // View Client Class bottom of Client Example Client.SetClient(_connectingSocket); Client.StartReceiving(); }
सर्वर को संदेश भेजना
तो अब हमारे पास लगभग खत्म या सॉकेट एप्लिकेशन है। केवल एक चीज जो हमारे पास नहीं है वह सर्वर पर एक संदेश भेजने के लिए एक वर्ग है।
public class SendPacket
{
private Socket _sendSocked;
public SendPacket(Socket sendSocket)
{
_sendSocked = sendSocket;
}
public void Send(string data)
{
try
{
/* what hapends here:
1. Create a list of bytes
2. Add the length of the string to the list.
So if this message arrives at the server we can easily read the length of the coming message.
3. Add the message(string) bytes
*/
var fullPacket = new List<byte>();
fullPacket.AddRange(BitConverter.GetBytes(data.Length));
fullPacket.AddRange(Encoding.Default.GetBytes(data));
/* Send the message to the server we are currently connected to.
Or package stucture is {length of data 4 bytes (int32), actual data}*/
_sendSocked.Send(fullPacket.ToArray());
}
catch (Exception ex)
{
throw new Exception();
}
}
अंतिम दो टोकरा एक से कनेक्ट करने के लिए दो और एक संदेश भेजने के लिए दूसरे:
private void ConnectClick(object sender, EventArgs e)
{
Connector tpp = new Connector();
tpp.TryToConnect();
}
private void SendClick(object sender, EventArgs e)
{
Client.SendString("Test data from client");
}
ग्राहक वर्ग जिसका मैंने इस उदाहरण में उपयोग किया है
public static void SetClient(Socket socket)
{
Id = 1;
Socket = socket;
Receive = new ReceivePacket(socket, Id);
SendPacket = new SendPacket(socket);
}
नोटिस
सर्वर से प्राप्त वर्ग ग्राहक से प्राप्त वर्ग के समान है।
निष्कर्ष
अब आपके पास एक सर्वर और एक क्लाइंट है। आप इस मूल उदाहरण को काम कर सकते हैं। उदाहरण के लिए यह बनाएं कि सर्वर भी फाइल या अन्य टिंग प्राप्त कर सकता है। या ग्राहक को एक संदेश भेजें। सर्वर में आपको क्लाइंट की एक सूची मिलती है, इसलिए जब आप कुछ प्राप्त करते हैं तो आपको क्लाइंट से पता चलेगा कि यह कहां से आया है।