सॉकेट कनेक्ट करने के लिए कैसे टाइमआउट कनेक्ट करें


104

जब ग्राहक डिस्कनेक्ट किए गए IP पते से कनेक्ट करने का प्रयास करता है, तो 15 सेकंड से अधिक का समय समाप्त हो जाता है ... हम इस समय-सीमा को कैसे कम कर सकते हैं? इसे कॉन्फ़िगर करने की विधि क्या है?

सॉकेट कनेक्शन सेट करने के लिए मैं जिस कोड का उपयोग कर रहा हूं, वह इस प्रकार है:

try
{
    m_clientSocket = new Socket(
         AddressFamily.InterNetwork,
         SocketType.Stream,
         ProtocolType.Tcp);

    IPAddress ip = IPAddress.Parse(serverIp);
    int iPortNo = System.Convert.ToInt16(serverPort);
    IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);

    m_clientSocket.Connect(ipEnd);
    if (m_clientSocket.Connected)
    {
        lb_connectStatus.Text = "Connection Established";
        WaitForServerData();
    }
}
catch (SocketException se)
{
    lb_connectStatus.Text = "Connection Failed";
    MessageBox.Show(se.Message);
}

जवाबों:


146

मुझे मिला। स्वीकृत उत्तर की तुलना में सरल, और .NET v2 के साथ काम करता है

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// Connect using a timeout (5 seconds)

IAsyncResult result = socket.BeginConnect( sIP, iPort, null, null );

bool success = result.AsyncWaitHandle.WaitOne( 5000, true );

if ( socket.Connected )
{
    socket.EndConnect( result );
}
else 
{
     // NOTE, MUST CLOSE THE SOCKET

     socket.Close();
     throw new ApplicationException("Failed to connect server.");
}

//... 

20
ठीक है, इस पर थोड़ा इनपुट - मुझे यह पसंद है और इसका बहुत कम कोड है .. हालांकि सफलता सही स्थिति नहीं है। इसके बजाय, अगर (! _Socket.Connected) जोड़ें और यह बहुत बेहतर काम करता है। बीमार कम के लिए यह एक +1 है अधिक पहलू है।
ट्रैविसडब्लड

2
आपके दो अंत बिंदुओं पर निर्भर करता है। यदि वे दोनों एक डेटासेंटर में हैं, तो 1 सेकंड काफी होना चाहिए, 3 अच्छे उपाय के लिए, 10 दयालु होना चाहिए। यदि एक छोर एक मोबाइल डिवाइस पर है, जैसे कि एक स्मार्टफोन, तो आप 30 सेकंड देख सकते हैं।
FlappySocks

3
एक और बात भी के लिए बाहर देखो ... अगर इसके बजाय डालने की nullके लिए में callbackहै और आप की योजना बना रहे EndConnect()हैं, अगर सॉकेट किया गया है closedतो यह आपके लिए एक अपवाद दे देंगे। इसलिए सुनिश्चित करें कि आप जाँच करें ...
poy

9
क्या होगा अगर मैं इसे डिराइव करने के बजाय टाइमआउट को बढ़ाना चाहता हूं? मुझे लगता है कि async दृष्टिकोण बस आपको कोड को 20 सेकंड तक इंतजार नहीं करने देता (सॉकेट कनेक्ट में आंतरिक टाइमआउट सेट)। लेकिन अगर कनेक्शन में अधिक समय लगता है, तो BeginConnect वैसे भी बंद हो जाएगा। या, BeginConnect आंतरिक रूप से हमेशा इंतजार करता है? मेरे पास एक बहुत धीमा कनेक्शन है जब कभी-कभी इसे कनेक्ट करने के लिए 30-40 सेकंड तक की आवश्यकता होती है, और 21 वें सेकंड में टाइमआउट बहुत बार होता है।
एलेक्स

3
@TravisWhidden पुष्टि कर सकते हैं, यह बहुत महत्वपूर्ण है! मेरे अनुभव में, यदि अंतिम बिंदु तक पहुंचा जा सकता है, लेकिन कनेक्शन प्राप्त करने में सक्षम समापन बिंदु पर कोई सर्वर नहीं है, तो AsyncWaitHandle.WaitOneसंकेत दिया जाएगा, लेकिन सॉकेट असंबद्ध रहेगा।
निकोलस मिलर

29

मेरा स्वीकार कर लेना:

public static class SocketExtensions
{
    /// <summary>
    /// Connects the specified socket.
    /// </summary>
    /// <param name="socket">The socket.</param>
    /// <param name="endpoint">The IP endpoint.</param>
    /// <param name="timeout">The timeout.</param>
    public static void Connect(this Socket socket, EndPoint endpoint, TimeSpan timeout)
    {
        var result = socket.BeginConnect(endpoint, null, null);

        bool success = result.AsyncWaitHandle.WaitOne(timeout, true);
        if (success)
        {
            socket.EndConnect(result);
        }
        else
        {
            socket.Close();
            throw new SocketException(10060); // Connection timed out.
        }
    }
}

मैंने एक शर्त संभालने के लिए स्वतंत्रता ली। आशा है कि आप बुरा नहीं मानेंगे
हेमंत

टॉप-रेटेड उत्तर पर प्रति टिप्पणियां, जो इसे कॉपी करने के अलावा दिखता है कि इसे एक में बनाया गया है SocketExtension, आपने अभी भी यह .Connectedदेखने के लिए उपयोग नहीं किया है कि क्या आप हैं, और आप socket.Connected = true;परिभाषित करने के लिए उपयोग नहीं कर रहे हैं success
vapcguy

22

मैंने अभी कनेक्शन में टाइमआउट की अनुमति देने के लिए एक विस्तार वर्ग लिखा था। इसका उपयोग ठीक उसी तरह से करें जैसे आप मानक Connect()तरीकों का उपयोग करेंगे , जिसका नाम एक अतिरिक्त पैरामीटर होगा timeout

using System;
using System.Net;
using System.Net.Sockets;

/// <summary>
/// Extensions to Socket class
/// </summary>
public static class SocketExtensions
{
    /// <summary>
    /// Connects the specified socket.
    /// </summary>
    /// <param name="socket">The socket.</param>
    /// <param name="host">The host.</param>
    /// <param name="port">The port.</param>
    /// <param name="timeout">The timeout.</param>
    public static void Connect(this Socket socket, string host, int port, TimeSpan timeout)
    {
        AsyncConnect(socket, (s, a, o) => s.BeginConnect(host, port, a, o), timeout);
    }

    /// <summary>
    /// Connects the specified socket.
    /// </summary>
    /// <param name="socket">The socket.</param>
    /// <param name="addresses">The addresses.</param>
    /// <param name="port">The port.</param>
    /// <param name="timeout">The timeout.</param>
    public static void Connect(this Socket socket, IPAddress[] addresses, int port, TimeSpan timeout)
    {
        AsyncConnect(socket, (s, a, o) => s.BeginConnect(addresses, port, a, o), timeout);
    }

    /// <summary>
    /// Asyncs the connect.
    /// </summary>
    /// <param name="socket">The socket.</param>
    /// <param name="connect">The connect.</param>
    /// <param name="timeout">The timeout.</param>
    private static void AsyncConnect(Socket socket, Func<Socket, AsyncCallback, object, IAsyncResult> connect, TimeSpan timeout)
    {
        var asyncResult = connect(socket, null, null);
        if (!asyncResult.AsyncWaitHandle.WaitOne(timeout))
        {
            try
            {
                socket.EndConnect(asyncResult);
            }
            catch (SocketException)
            { }
            catch (ObjectDisposedException)
            { }
        }
    }

8
घोस्टडॉक के प्रशंसक, फिर से हैं? ;; "भूत कनेक्ट Asyncs" - क्लासिक GhostDoc WTFness।
कीथ्स

1
:) हाँ, और कभी-कभी ऐसा भी नहीं है कि क्या उत्पन्न हुआ है।
२३:३० बजे

सॉकेट से बेहतर।
कीकनेट

3
socket.EndConnectलेता है ~ 10 सेकंड इतना समारोह रिटर्न बंद करने के लिए समय अवधि के बाद नहीं लेकिन समयावधि + endConnect समय के बाद
Royi Namir

8

मैं C # में प्रोग्राम नहीं करता हूं, लेकिन C में, हम सॉकेट को नॉन-ब्लॉकिंग करके उसी समस्या को हल करते हैं और फिर fd को समय के बराबर मूल्य के साथ चुनिंदा / पोल लूप में डाल देते हैं, हम कनेक्ट होने का इंतजार करने के लिए तैयार हैं सफलता के लिए।

मैंने इसे विजुअल C ++ के लिए पाया और वहां की व्याख्या भी मैंने पहले बताए गए सेलेक्ट / पोल मैकेनिज्म की ओर झुकती है।

मेरे अनुभव में, आप प्रति सॉकेट में कनेक्ट समय मान नहीं बदल सकते हैं। आप इसे सभी के लिए बदलते हैं (ओएस मापदंडों को ट्यून करके)।


7

यह बहुत देर हो सकती है लेकिन टास्क के आधार पर साफ-सुथरा समाधान है। WitAny (c # 5 +):

 public static bool ConnectWithTimeout(this Socket socket, string host, int port, int timeout)
        {
            bool connected = false;
            Task result = socket.ConnectAsync(host, port);               
            int index = Task.WaitAny(new[] { result }, timeout);
            connected = socket.Connected;
            if (!connected) {
              socket.Close();
            }

            return connected;
        }

क्या कोई भी "ConnectAsync" ओवरलोड होस्ट और पोर्ट को स्वीकार करता है?
मार्श-

@ marsh-wiggle, "ConnectAsync" विधि में 4 अधिभार docs.microsoft.com/en-us/dotnet/api/ ... कृपया विस्तार विधि अनुभाग देखें
ओलेग बोंडारेंको

1
@OlegBondarenko ठीक है, .net 4.5.1 के लिए उपलब्ध नहीं है। मुझे इसे खुद से लपेटना होगा। धन्यवाद!
मार्श-

5

मैंने सॉकेट के बजाय सॉकेट का उपयोग करके समस्या हल की। Socket.ConnectAsync (SocketAsyncEventArgs) को इनवॉइस करने के बाद, एक टाइमर (टाइमर_कनेक्शन) शुरू करें, यदि समय हो रहा है, तो जांचें कि सॉकेट कनेक्शन जुड़ा हुआ है (यदि (m_clientSocket .Connected)), यदि नहीं, तो टाइमआउट त्रुटि पॉप अप करें।

private void connect(string ipAdd,string port)
    {
        try
        {
            SocketAsyncEventArgs e=new SocketAsyncEventArgs();


            m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPAddress ip = IPAddress.Parse(serverIp);
            int iPortNo = System.Convert.ToInt16(serverPort);
            IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);

            //m_clientSocket.
            e.RemoteEndPoint = ipEnd;
            e.UserToken = m_clientSocket;
            e.Completed+=new EventHandler<SocketAsyncEventArgs>(e_Completed);                
            m_clientSocket.ConnectAsync(e);

            if (timer_connection != null)
            {
                timer_connection.Dispose();
            }
            else
            {
                timer_connection = new Timer();
            }
            timer_connection.Interval = 2000;
            timer_connection.Tick+=new EventHandler(timer_connection_Tick);
            timer_connection.Start();
        }
        catch (SocketException se)
        {
            lb_connectStatus.Text = "Connection Failed";
            MessageBox.Show(se.Message);
        }
    }
private void e_Completed(object sender,SocketAsyncEventArgs e)
    {
        lb_connectStatus.Text = "Connection Established";
        WaitForServerData();
    }
    private void timer_connection_Tick(object sender, EventArgs e)
    {
        if (!m_clientSocket.Connected)
        {
            MessageBox.Show("Connection Timeout");
            //m_clientSocket = null;

            timer_connection.Stop();
        }
    }

2
जब टाइमर बंद हो जाता है, तो आप एक त्रुटि संदेश दिखाते हैं? यह आपके टीसीपी स्टैक को वास्तव में कनेक्ट करने से कैसे रोकता है। एक परिदृश्य की कल्पना करें, जहां एक दूरस्थ होस्ट 2 सेकंड से अधिक दूर यानी rto> 2. आपका टाइमर बंद हो जाएगा और आप त्रुटि संदेश प्रिंट करेंगे। हालाँकि, TCP आपके टाइमर द्वारा नियंत्रित नहीं है। यह अभी भी कनेक्ट करने का प्रयास करेगा और 2 सेकंड के बाद सफलतापूर्वक कनेक्ट हो सकता है। क्या C # "कनेक्ट" अनुरोधों को रद्द करने या सॉकेट पर बंद करने की सुविधा प्रदान करता है। आपका टाइमर समाधान 2 सेकंड के बाद जाँच करने के बराबर है कि क्या कनेक्शन सफल हुआ।
आदित्य सहगल

मुझे यह मिला: splinter.com.au/blog/?p=28 इस तरह दिखता है। यह आपके लिए समान है लेकिन मुझे लगता है कि यह वही करता है जो मैंने ऊपर समझाया।
आदित्य सहगल

जब यह समय समाप्त हो जाता है, तो आपको m_clientSocket.Close () को कॉल करना चाहिए;
विन्सेंट मैकनाब

अद्यतन करें, आदित्य द्वारा संदर्भित के रूप में मेरा ब्लॉग लिंक बदल गया है: splinter.com.au/opening-a-tcp-connection-in-c-with-a-custom-t
Chris

मैं कॉल "टाइमर_कनेक्शन.डिजाइन ();" से संबंधित तर्क को फिर से लिखूंगा। संभवत: ऑब्जेक्ट के निस्तारण के बाद टाइमर_कनेक्शन ऑब्जेक्ट संदर्भ का उपयोग किया जाता है।
BoiseBaked

2

MSDN पर इसे देखें । ऐसा प्रतीत नहीं होता है कि आप सॉकेट क्लास में कार्यान्वित गुणों के साथ ऐसा कर सकते हैं।

MSDN पर पोस्टर ने वास्तव में थ्रेडिंग का उपयोग करके अपनी समस्या को हल किया । उनके पास एक मुख्य धागा था जो अन्य थ्रेड्स को कॉल करता था जो कुछ सेकंड के लिए कनेक्शन कोड चलाते हैं और फिर सॉकेट की कनेक्टेड संपत्ति की जांच करते हैं:

मैंने एक और तरीका बनाया है जो वास्तव में सॉकेट से जुड़ा था ... 2 सेकंड के लिए मुख्य थ्रेड स्लीप था और फिर कनेक्टिंग विधि (एक अलग थ्रेड में चलाया जाता है) पर जांच करें यदि सॉकेट अच्छी तरह से जुड़ा हुआ था अन्यथा एक अपवाद छोड़ दिया "टाइम आउट" और बस यही। फिर से धन्यवाद के लिए धन्यवाद।

आप क्या करने की कोशिश कर रहे हैं, और यह समय से पहले 15-30 सेकंड तक इंतजार क्यों नहीं कर सकता है?


2

सॉकेट से कनेक्ट करते समय मुझे एक ही समस्या थी और मैं नीचे दिए गए समाधान के साथ आया, यह मेरे लिए ठीक काम करता है। `

private bool CheckConnectivityForProxyHost(string hostName, int port)
       {
           if (string.IsNullOrEmpty(hostName))
               return false;

           bool isUp = false;
           Socket testSocket = null;

           try
           {

               testSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
               IPAddress ip = null;
               if (testSocket != null && NetworkingCollaboratorBase.GetResolvedConnecionIPAddress(hostName, out ip))//Use a method to resolve your IP
               {
                   IPEndPoint ipEndPoint = new IPEndPoint(ip, port);

                   isUp = false;
//time out 5 Sec
                  CallWithTimeout(ConnectToProxyServers, 5000, testSocket, ipEndPoint);

                       if (testSocket != null && testSocket.Connected)
                       {
                           isUp = true;
                       }
                   }

               }
           }
           catch (Exception ex)
           {
               isUp = false;
           }
           finally
           {
               try
               {
                   if (testSocket != null)
                   {
                       testSocket.Shutdown(SocketShutdown.Both);
                   }
               }
               catch (Exception ex)
               {

               }
               finally
               {
                   if (testSocket != null)
                       testSocket.Close();
               }

           }

           return isUp;
       }


 private void CallWithTimeout(Action<Socket, IPEndPoint> action, int timeoutMilliseconds, Socket socket, IPEndPoint ipendPoint)
       {
           try
           {
               Action wrappedAction = () =>
               {
                   action(socket, ipendPoint);
               };

               IAsyncResult result = wrappedAction.BeginInvoke(null, null);

               if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
               {
                   wrappedAction.EndInvoke(result);
               }

           }
           catch (Exception ex)
           {

           }
       }

  private void ConnectToProxyServers(Socket testSocket, IPEndPoint ipEndPoint)
       {
           try
           {
               if (testSocket == null || ipEndPoint == null)
                   return;

                   testSocket.Connect(ipEndPoint);

           }
           catch (Exception ex)
           {

           }
       } 

1

मैंने यूनिटी के साथ काम किया और सॉकेट से बिगिनकॉन और अन्य एसिंक्स तरीकों के साथ कुछ समस्या थी।

मेरे द्वारा काम नहीं करने से पहले कोड सैंपल की समझ में कुछ है।

इसलिए मैंने इसे काम करने के लिए कोड का यह टुकड़ा लिखा। मैं इसे एंड्रॉइड और पीसी के साथ एडहॉक नेटवर्क पर परीक्षण करता हूं, अपने कंप्यूटर पर स्थानीय में भी। आशा है कि यह मदद कर सकता है।

using System.Net.Sockets;
using System.Threading;
using System.Net;
using System;
using System.Diagnostics;

class ConnexionParameter : Guardian
{
    public TcpClient client;
    public string address;
    public int port;
    public Thread principale;
    public Thread thisthread = null;
    public int timeout;

    private EventWaitHandle wh = new AutoResetEvent(false);

    public ConnexionParameter(TcpClient client, string address, int port, int timeout, Thread principale)
    {
        this.client = client;
        this.address = address;
        this.port = port;
        this.principale = principale;
        this.timeout = timeout;
        thisthread = new Thread(Connect);
    }


    public void Connect()
    {
        WatchDog.Start(timeout, this);
        try
        {
            client.Connect(IPAddress.Parse(address), port);

        }
        catch (Exception)
        {
            UnityEngine.Debug.LogWarning("Unable to connect service (Training mode? Or not running?)");
        }
        OnTimeOver();
        //principale.Resume();
    }

    public bool IsConnected = true;
    public void OnTimeOver()
    {
        try
        {
            if (!client.Connected)
            {
                    /*there is the trick. The abort method from thread doesn't
 make the connection stop immediately(I think it's because it rise an exception
 that make time to stop). Instead I close the socket while it's trying to
 connect , that make the connection method return faster*/
                IsConnected = false;

                client.Close();
            }
            wh.Set();

        }
        catch(Exception)
        {
            UnityEngine.Debug.LogWarning("Connexion already closed, or forcing connexion thread to end. Ignore.");
        }
    }


    public void Start()
    {

        thisthread.Start();
        wh.WaitOne();
        //principale.Suspend();
    }

    public bool Get()
    {
        Start();
        return IsConnected;
    }
}


public static class Connexion
{


    public static bool Connect(this TcpClient client, string address, int port, int timeout)
    {
        ConnexionParameter cp = new ConnexionParameter(client, address, port, timeout, Thread.CurrentThread);
        return cp.Get();
    }

//http://stackoverflow.com/questions/19653588/timeout-at-acceptsocket
    public static Socket AcceptSocket(this TcpListener tcpListener, int timeoutms, int pollInterval = 10)
    {
        TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutms);
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        while (stopWatch.Elapsed < timeout)
        {
            if (tcpListener.Pending())
                return tcpListener.AcceptSocket();

            Thread.Sleep(pollInterval);
        }
        return null;
    }


}

और यह काम करने के लिए C # पर एक बहुत ही सरल प्रहरी है:

using System.Threading;

public interface Guardian
{
    void OnTimeOver();
}

public class WatchDog {

    int m_iMs;
    Guardian m_guardian;

    public WatchDog(int a_iMs, Guardian a_guardian)
    {
        m_iMs = a_iMs;
        m_guardian = a_guardian;
        Thread thread = new Thread(body);
        thread.Start(this);
    }


    private void body(object o)
    {
        WatchDog watchdog = (WatchDog)o;
        Thread.Sleep(watchdog.m_iMs);
        watchdog.m_guardian.OnTimeOver();
    }

    public static void Start(int a_iMs, Guardian a_guardian)
    {
        new WatchDog(a_iMs, a_guardian);
    }
}

1

यह FlappySock के उत्तर की तरह है, लेकिन मैंने इसमें एक कॉलबैक जोड़ा क्योंकि मुझे लेआउट पसंद नहीं था और कैसे बूलियन वापस मिल रहा था। निक मिलर के उस जवाब की टिप्पणियों में:

मेरे अनुभव में, यदि अंतिम बिंदु तक पहुंचा जा सकता है, लेकिन कनेक्शन प्राप्त करने में सक्षम समापन बिंदु पर कोई सर्वर नहीं है, तो AsyncWaitHandle.WaitOne को संकेत दिया जाएगा, लेकिन सॉकेट असंबद्ध रहेगा

इसलिए मेरे लिए, यह इस बात पर निर्भर करता है कि जो लौटा है वह खतरनाक हो सकता है - मैं उपयोग करना पसंद करता हूं socket.Connected। मैं एक अशक्त बूलियन सेट करता हूं और कॉलबैक फ़ंक्शन में इसे अपडेट करता हूं। मैंने यह भी पाया कि यह हमेशा मुख्य फ़ंक्शन पर लौटने से पहले परिणाम की रिपोर्ट करना समाप्त नहीं करता है - मैं उस के लिए भी संभालता हूं, और टाइमआउट का उपयोग करके परिणाम की प्रतीक्षा करें:

private static bool? areWeConnected = null;

private static bool checkSocket(string svrAddress, int port)
{
    IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(svrAddress), port);
    Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    int timeout = 5000; // int.Parse(ConfigurationManager.AppSettings["socketTimeout"].ToString());
    int ctr = 0;
    IAsyncResult ar = socket.BeginConnect(endPoint, Connect_Callback, socket);
    ar.AsyncWaitHandle.WaitOne( timeout, true );

    // Sometimes it returns here as null before it's done checking the connection
    // No idea why, since .WaitOne() should block that, but it does happen
    while (areWeConnected == null && ctr < timeout)
    {
        Thread.Sleep(100);
        ctr += 100;
    } // Given 100ms between checks, it allows 50 checks 
      // for a 5 second timeout before we give up and return false, below

    if (areWeConnected == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}

private static void Connect_Callback(IAsyncResult ar)
{
    areWeConnected = null;
    try
    {
        Socket socket = (Socket)ar.AsyncState;
        areWeConnected = socket.Connected;
        socket.EndConnect(ar);
    }
    catch (Exception ex)
    {
      areWeConnected = false;
      // log exception 
    }
}

संबंधित: अगर मैं जुड़ा हूं तो कैसे जांचें?


-8

सॉकेट क्लास में एक रिसीवेटआउट प्रॉपर्टी होनी चाहिए।

सॉकेट .eceiveTimeout संपत्ति


1
मैंने कोशिश की। यह सिर्फ काम नहीं करता है। मैंने m_clientSocket.ReceiveTimeout = 1000 जोड़ा; m_clientSocket.Connect (ipEnd) को लागू करने से पहले। हालाँकि, अपवाद संदेश को पॉपअप करने से पहले यह लगभग 15-20 सेकंड प्रतीक्षा करता है।
नाइनकिन

2
यह उस समय के लिए समय निर्धारित करता है जब कनेक्शन बनने के बाद सॉकेट डेटा प्राप्त कर रहा है।
eric.christensen

1
उपयोग नहीं कर सकते हैं ReceiveTimeout- यह सख्ती से जब BeginReceiveऔर साथ प्राप्त करने के लिए है EndReceive। जब आप कनेक्ट हो रहे हों तो आप जब आप देख रहे हों तो इसके लिए कोई समकक्ष नहीं है।
vapcguy
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.