private void Dns_Resolve(IAsyncResult ar) { Random rnd = new Random(); IPHostEntry hostent; ConnQueueItem nextconn = (ConnQueueItem)(ar.AsyncState); while (!ar.IsCompleted) { ar.AsyncWaitHandle.WaitOne(10, false); } try { hostent = Dns.EndGetHostEntry(ar); } catch (Exception e2) { // DNS Failed. BufferedSocket sck = new BufferedSocket(null); sck.sckError = e2; nextconn.cb(sck); return; } nextconn.address = hostent.AddressList[rnd.Next(hostent.AddressList.Length)].ToString(); lock (this) { connectionqueue.Enqueue(nextconn); } }
private void SocketThread() { try { // Loop "forever". while (true) { // Even a tiny sleep like this goes a long way to keeping us from using 100% CPU. try { Thread.Sleep(10); } catch (ThreadInterruptedException) {} lock (this) { if ((sockets.Count + connectionqueue.Count) < 1) { continue; } // Process EXACTLY ONE connection attempt each time through. If we must DNS, // then do so and then put the attempt back on the end. if (connectionqueue.Count > 0) { ConnQueueItem nextconn = connectionqueue.Dequeue(); IPAddress ip; try { ip = IPAddress.Parse(nextconn.address); // We have IP - CONNECT! BufferedSocket sck = new BufferedSocket(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)); try { sck.sck.Connect(new IPEndPoint(ip, nextconn.port)); // CONNECTED! Notify the callback. nextconn.cb(sck); sockets.Add(sck); } catch (Exception e) { // Connect Failed :( Notify the callback. The callback doesn't need to try to remove - in fact it MUST NOT! I don't know what a double-lock might entail ;) . sck.sck = null; sck.sckError = e; nextconn.cb(sck); } } catch (Exception) { // We must DNS. try { Dns.BeginGetHostEntry(nextconn.address, new AsyncCallback(Dns_Resolve), nextconn); } catch (Exception e2) { // DNS Failed. BufferedSocket sck = new BufferedSocket(null); sck.sckError = e2; nextconn.cb(sck); } } } // Now process Socket buffers. foreach (BufferedSocket sck in sockets) { lock (sck) { // We shouldn't send more than about 1KB at a time, to avoid blocking // in Send(). // If we're pending disconnect... if (sck.sck == null) { continue; } if (sck.PendingDisconnect) { if (sck.sck.Poll(0, SelectMode.SelectWrite) && sck.sendbuffer.Length > 0) { sck.sck.Send(Encoding.ASCII.GetBytes(sck.sendbuffer)); } sck.sendbuffer = ""; sck.sck.Shutdown(SocketShutdown.Both); sck.sck.Close(); sck.sck = null; continue; } if (sck.sendbuffer.Length > 0) { byte[] data; if (sck.sendbuffer.Length > 1024) { data = Encoding.ASCII.GetBytes(sck.sendbuffer.Substring(0, 1024)); sck.sendbuffer = sck.sendbuffer.Substring(1024); } else { data = Encoding.ASCII.GetBytes(sck.sendbuffer); sck.sendbuffer = ""; } sck.sck.Send(data); } if (sck.sck.Poll(0, SelectMode.SelectRead) && sck.sck.Available <= 0) { // Remote endpoint disconnected. sck.sendbuffer = ""; if (sck.sck.Poll(0, SelectMode.SelectWrite)) { sck.sck.Shutdown(SocketShutdown.Send); } sck.sck.Close(); sck.sck = null; } else if (sck.sck.Available > 0) { byte[] data = new byte[sck.sck.Available]; sck.sck.Receive(data); sck.recvbuffer += Encoding.ASCII.GetString(data); } // In case someone had called Monitor.Wait() on this sck, pulse it. Monitor.PulseAll(sck); } } } } } catch (ThreadAbortException) { } }