2010-01-19 2 views
5

Может кто-нибудь объяснить мне, почему следующий код не работает?Проблема с розеткой при использовании резьбы

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Net.Sockets; 
using System.Net; 
using System.Threading; 

namespace SocketThreadingTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Thread t = new Thread(delegate() 
      { 
       BeginConnect(new IPEndPoint("some address")); 
      }); 
      t.Start(); 

      Console.ReadKey(); 
     } 

     public static void BeginConnect(IPEndPoint address) 
     { 
      try 
      { 
       Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
       socket.BeginConnect(address, ConnectCallback, socket); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
      } 
     } 

     private static void ConnectCallback(IAsyncResult ar) 
     { 
      Socket sock = (Socket)ar.AsyncState; 
      try 
      { 
       sock.EndConnect(ar); 
       Console.WriteLine("Connected {0}", sock.LocalEndPoint); 

       sock.Send(Encoding.UTF8.GetBytes("Hello")); 

       Console.WriteLine("success"); 
       sock.Close(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("send ex " + ex); 

       if (sock != null) 
        sock.Close(); 
      } 
     } 
    } 
} 

Выход (обратите внимание на локальную конечную точку сокета):

Connected 0.0.0.0:28142 
send ex System.Net.Sockets.SocketException: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram 
socket using a sendto call) no address was supplied 
    at System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, So 
cketFlags socketFlags) 
    at System.Net.Sockets.Socket.Send(Byte[] buffer) 
    at SocketThreadingTest.Program.ConnectCallback(IAsyncResult ar) in Program.cs:line 44 

Конечно, когда я не использую нить и называем BeginConnect непосредственно работает нормально. Что еще более озадачивает, так это добавление Thread.Sleep, который достаточно длинный (1 сек), он также отлично работает. Любые идеи? Спасибо.

+1

Нить вы создаете, что вызывает BeginConnect выход после BeginConnect называется. Вы видите какое-либо другое поведение, если вы не позволяете этому концу потока (в документах API есть проблемы, если поток, вызывающий sock.BeginConnect, заканчивается, хотя это должно быть проблемой только для ранее подключенного сокета) – nos

+0

Да, есть разница. Как я уже сказал, даже добавление небольшого сна после вызова программы.BeginConnect делает эту работу. В документе API указано: «Если этот сокет ранее был отключен, необходимо вызвать BeginConnect в потоке, который не будет завершен, пока операция не будет завершена. Это ограничение основного поставщика». Но, как вы заявили, что это новый сокет и ранее не был отключен ... – Zvika

ответ

0

Ваш IPEndPoint должен содержать порт - я даже не уверен, как ваш EndPoint будет скомпилирован, как требуется. Вы можете поставить порт в качестве второго параметра вашего IPEndAddress или изменить метод BeginConnect следующим образом:

socket.BeginConnect(address, [port], ConnectCallback, socket); 

... где [порт] порт прослушивания на сервере.

+1

не будь глупым Джорджем ... конечно, код как есть, не компилируется. что вы ожидали, что я вставлю здесь настоящий адрес сервера ?! Я думал, что писать «какой-то адрес» - достаточно сильный намек на то, что это место, которое нужно заполнить перед запуском этого кода. – Zvika

+0

Вы ошибались!;) –

1

Что имеет смысл использовать отдельные темы Thread и BeginConnect? Если вы создаете отдельный поток (предпочтительно с пулом потоков), почему вы используете асинхронное соединение (в этом случае отдельный поток будет заимствован из пула потоков)?

Есть несколько вариантов: Использование ThreadPool и Socket.connect

class Program { 

    static void Connect(object o) 
    { 
     IPEndPoint address = (IPEndPoint)o; 
     Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     socket.Connect(address); 
     Console.WriteLine("Connected {0}", socket.LocalEndPoint); 
     socket.Send(Encoding.UTF8.GetBytes("Hello")); 
     Console.WriteLine("success"); 
     socket.Close(); 
    } 

    static void Main(string[] args) 
    { 
     IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 5111); 
     ThreadPool.QueueUserWorkItem(Connect, endPoint); 
     Console.ReadKey(); 
    } 
} 

Используйте BeginConnect без отдельного потока.

class Program { 

static void Main(string[] args) 
{ 
    BeginConnect(new IPEndPoint(IPAddress.Loopback, 5111)); 
    Console.ReadKey(); 
} 

public static void BeginConnect(IPEndPoint address) 
{ 
    try 
    { 
     Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     socket.BeginConnect(address, ConnectCallback, socket); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
    } 
} 

private static void ConnectCallback(IAsyncResult ar) 
{ 
    Socket sock = (Socket)ar.AsyncState; 
    try 
    { 
     sock.EndConnect(ar); 
     Console.WriteLine("Connected {0}", sock.LocalEndPoint); 
     sock.Send(Encoding.UTF8.GetBytes("Hello")); 
     Console.WriteLine("success"); 
     sock.Close(); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("send ex " + ex); 
     if (sock != null) 
      sock.Close(); 
    } 
} 
} 

Использование BeginConnect с отдельной теме:

class Program 
{ 

    static void Main(string[] args) 
    { 
     Thread t = new Thread(delegate() 
     { 
      BeginConnect(new IPEndPoint(IPAddress.Loopback, 5111)); 
     }); 
     t.Start(); 
     Console.ReadKey(); 
    } 

    public static void BeginConnect(IPEndPoint address) 
    { 
     try 
     { 
      Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      socket.BeginConnect(address, ConnectCallback, socket); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 
    } 

    private static void ConnectCallback(IAsyncResult ar) 
    { 
     Socket sock = (Socket)ar.AsyncState; 
     try 
     { 
      sock.EndConnect(ar); 
      Console.WriteLine("Connected {0}", sock.LocalEndPoint); 
      sock.Send(Encoding.UTF8.GetBytes("Hello")); 
      Console.WriteLine("success"); 
      sock.Close(); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("send ex " + ex); 
      if (sock != null) 
       sock.Close(); 
     } 
    } 
} 
+0

Мне известны эти параметры, но BeginConnect вызывается из отдельного потока. Это дизайн приложения. Я спрашиваю, почему в этой ситуации я получаю сообщение об ошибке. – Zvika

+0

Мой второй пример хорошо работает ... Вы можете изменить этот код, чтобы вместо этого использовать класс Thread. –

+0

Я изменил свой пример, чтобы использовать класс Thread. И он отлично работает. Я думаю, что проблема не в классе Thread вообще. –

0

возможно потому, что вы не ждут начального потока, операционная система отменяет запрос ввода/вывода? Windows отменит запрос ввода-вывода, если исходный поток, запускающий асинхронный ввод-вывод, умирает.

В этом случае вы вызываете BeginConnect из потока и позволяете потоку умереть, поэтому ввод-вывод отменяется. Теперь может возникнуть ситуация, когда ввод-вывод не может быть отменен, если поток, который вы начали, фактически не умер, когда вы вызывали Send() в сокете.

Если вы действительно хотите, чтобы это работало, вы можете попробовать следующий вариант:

 static void Main(string[] args) 
    { 
     Thread t = new Thread(delegate() 
     { 
      IAsyncResult ar = BeginConnect(new IPEndPoint("some address")); 
      // wait for the async connect to finish. 
      ar.WaitOne(); 
     }); 
     t.Start(); 

     Console.ReadKey(); 
    } 

    public static IAsyncResult BeginConnect(IPEndPoint address) 
    { 
     try 
     { 
      Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      return socket.BeginConnect(address, ConnectCallback, socket); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 
     return null; 
    } 
Смежные вопросы