2013-03-13 24 views
5

Mam następujący problem:C kwestia połączenia # .NET Socket - Tylko jedno użycie każdego adresu gniazda jest normalnie dozwolone

Gdy zamknę aplikację WM6, a następnie spróbuj uruchomić go ponownie i dostać ten błąd: Tylko jedno użycie każdego adresu gniazda (protokołu/adresu sieciowego/portu) jest zwykle dozwolone w System.Net.Sockets.Socket.Bind (EndPoint localEP) pod adresem System.Net.Sockets.Socket.TcpListener.Start() ...

Myślę, że jest to spowodowane interwałem czasu połączenia z limitem czasu, więc chciałbym jak zamknąć wszystkie otwarte połączenia i zmusić je do utworzenia nowego połączenia, czy jest to właściwy sposób postępowania, czy jest inny sposób poradzenia sobie z tym?

Oto kod używany aby rozpocząć odtwarzanie:

/// <summary> 
/// Listens Asynchronously to Clients, creates a recieveMessageHandler to process the read. 
/// 
/// Check WIKI, TODOS 
/// </summary> 
/// <returns></returns> 
public void Listen() 
{ 
    myTcpListener.Start(); 

    while (true) 
    { 
     //blocks until a client has connected to the server 
     try 
     { 
      TcpClient myTcpClient = myTcpListener.AcceptTcpClient(); 
      DateTime now = DateTime.Now; 
      //Test if it's necessary to create a client 
      ClientConnection client = new ClientConnection(myTcpClient, new byte[myTcpClient.ReceiveBufferSize]); 

      // Capture the specific client and pass it to the receive handler 
      client.NetworkStream.BeginRead(client.Data, 0, myTcpClient.ReceiveBufferSize, r => receiveMessageHandler(r, client), null); 
     } 
     catch (Exception excp) 
     { 
      Debug.WriteLine(excp.ToString()); 
     } 
    } 
} 
+0

Podczas zamykania zamknij plik myTcpListener. –

+0

Tak, ale nazywam niektóre biblioteki DLL, które czasami powodują awarię aplikacji, a kod zamknięcia nie jest wywoływany. – Astronaut

+0

Musisz lepiej poradzić sobie z tym błędem. Po prostu rozbijając się i pozostawiając niezarządzane zasoby leżące wokół, pojawia się ten błąd. Mimo że CLR obsługuje zarządzanie pamięcią dla zarządzanych obiektów, należy to zrobić dla niezarządzanych obiektów, takich jak połączenia plików i sieci. –

Odpowiedz

4

Tak, gniazdo serwera jest prawdopodobnie w stanie CZAS_OCZEKIWANIA.

Można uzyskać dostęp do podstawowej ServerSocket, a następnie użyć SetSocketOption i określić ReuseAddress.

+0

Poddałbym się próbie ...Uważam, że Compact Framework ma pewne dziwactwa z gniazdami, więc spróbuję sprawdzić, czy to jest dostępne. – Astronaut

+3

Po utworzeniu listnera powinienem: myTcpListener.Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); – Astronaut

2

Zamierzam zgadnąć, że ClientConnection to Twoja biblioteka DLL, ponieważ nie widzę, że jest już zawarta w CF.

Tak naprawdę nie potrzebujesz tego, jeśli zadeklarujesz MethodInvoker.

public delegate void MethodInvoker(); // required 

Aby kod naprawdę śliska, należy również stworzyć swój własny EventArgs klasę:

public class WmTcpEventArgs : EventArgs { 

    private string data; 

    public WmTcpEventArgs(string text) { 
    data = text; 
    } 

    public string Data { get { return data; } } 

} 

bardzo proste. Dzięki tej nowej WmTcpEventArgs klasa a, powinno być wszystko gotowe do odbioru danych, które można wysłać do czegoś jak TextBox sterowania:

private void NetworkResponder(object sender, WmTcpEventArgs e) { 
    textBox1.Text = e.Data; 
} 

Zamiast kodowania while(true) w kodzie, wolę to trochę Boolean zmienna

private bool abortListener; 

kod będzie wyglądał tak:

public void Listen() { 
    listener.Start(); 
    while (!abortListener) { 
    try { 
     using (var client = listener.AcceptTcpClient()) { 
     int MAX = client.ReceiveBufferSize; 
     var now = DateTime.Now; 
     using (var stream = client.GetStream()) { 
      Byte[] buffer = new Byte[MAX]; 
      int len = stream.Read(buffer, 0, MAX); 
      if (0 < len) { 
      string data = Encoding.UTF8.GetString(buffer, 0, len); 
      MethodInvoker method = delegate { NetworkResponder(this, new WmTcpEventArgs(data)); }; 
      abortListener = ((form1 == null) || form1.IsDisposed); 
      if (!abortListener) { 
       form1.Invoke(method); 
      } 
      } 
     } 
     } 
    } catch (Exception err) { 
     Debug.WriteLine(err.Message); 
    } finally { 
     listener.Stop(); 
    } 
    } 
} 

Zauważ, że nadal łapiesz swoje wyjątki, ale zatrzymujesz też TcpListener.