2011-09-16 3 views
0

저는 .NET 개발자이며 소켓 프로그래밍을 처음 사용합니다.동일한 TCP 소켓에 다중 스레드

.NET 소켓 라이브러리를 사용하여 TCP 소켓을 사용하여 클라이언트에 일부 데이터를 보내는 프로그램을 작성했습니다.

클라이언트는 연결을 유지하기 위해 40 초마다 Keep Alive 메시지를 사용자 지정해야합니다.

그래서 클라이언트와의 연결을 설정하는 주 프로그램을 작성했습니다. 이 메인 프로그램에서 스레드를 생성하고 이전에 작성된 소켓 클래스의 인스턴스를 전달합니다. 이 스레드는 주 스레드가 데이터 전송을 담당하는 동안 클라이언트에 연결 유지 메시지를 전송합니다.

모두 잘 작동합니다. 그러나 어떤 이유로 소켓 연결 시간이 초과되면 프로그램이 절대 복구되지 않습니까? 두 스레드의 논리를 모두 종료하고 새 연결을 설정하지만 항상 '호스트와의 연결이 중단되었습니다'또는 이와 유사한 오류가 발생합니다.

내가 잘못 했나요?

동일한 소켓에 연결된 두 개의 스레드가 있어야합니다. 하나의 쓰레드는 데이터 전송을 담당하고 다른 쓰레드는 연결 유지 메시지 전송을 담당한다. 무엇이 최선의 접근 방식이어야 하는가?

아니요, 동일한 소켓을 사용하려고하지 않습니다.

내가 mainThread이 handleClient를 호출 : 나는 여기

코드입니다 ... 루프 clntSock.close()에 대한 거리에서 휴식. handleClient 다른 thread를 작성합니다.

class DispatchLoop 
{ 
    ILogger logger; 
    TcpListener listener; 
    IProtocolFactory protoFactory; 

    public DispatchLoop(TcpListener listener, ILogger logger, IProtocolFactory protoFactory) 
    { 
     this.logger = logger; 
     this.listener = listener; 
     this.protoFactory = protoFactory; 
    } 

    public void mainThread() 
    { 
     // Run forever, accepting and handling each connection 
     for (; ;) 
     { 
      try 
      { 
       Socket clntSock = listener.AcceptSocket(); // Block waiting for connection 
       PoolDispatcher._stopper.Reset(); 
       clntSock.ReceiveTimeout = 10000; 
       IProtocol protocol = protoFactory.createProtocol(clntSock, logger); 
       protocol.handleClient(); 
      } 
      catch (SocketException se) 
      { 
       logger.writeEntry("(Run Dispatcher) Exception = " + se.Message); 
      } 
     } 
    } 
} 

    public void handleClient() 
    { 
     entry.Add("Main Thread Entered : Client address and Port = " + clntSock.RemoteEndPoint + ", Thread Number = " + Thread.CurrentThread.GetHashCode()); 

     //Kick Starting Keep Alive Thread 
     KeepAlive ka = new KeepAlive(clntSock, logger); 
     Thread thread = new Thread(new ThreadStart(ka.SendKeepAlive)); 
     thread.Start(); 
     try 
     { 
      int recvMsgSize; // Size of received message 
      byte[] rcvBuffer = new byte[BUFSIZE]; // Receive buffer 
      byte[] messageBuffer = new byte[1024]; 
      XDocument _messageXDoc; 
      FlightInfoExtended _flightInfoExtended; 
      try 
      { 
       LogEntry(entry); 
       for (; ;) 
       { 
        try 
        { 
         //Read from the Queue 
         var _queue = new IBMQueue(); 
         var message = _queue.ReceiveMessage(); 

         if (message.Length > 0) 
         { 
          entry.Add("Sending the GOS Message to the client : " + message); 
          messageBuffer = Encoding.ASCII.GetBytes(message); 

          if (clntSock.Connected) 
          { 
           clntSock.Send(messageBuffer, 0, messageBuffer.Length, SocketFlags.None); 
           recvMsgSize = clntSock.Receive(rcvBuffer, 0, rcvBuffer.Length, SocketFlags.None); 
           SaveGOSMessage(_auditMessage); 
          } 
          else 
          { 
           PoolDispatcher._stopper.Set(); 
           LogFailureStatus("No Socket Connection"); 
           Thread.Sleep(30000); 
           break; 
          } 
         } 
        } 
        catch (SocketException se) 
        { 
         PoolDispatcher._stopper.Set(); 
         LogFailureStatus(se.Message); 
         Thread.Sleep(30000); 
         break; 
        } 
        catch (Exception e) 
        { 
        } 
        LogEntry(entry); 
       } 
      } 
      catch (Exception se) 
      { 
       entry.Add(String.Format("{0}: {1}", se.Source, se.Message)); 
      } 
     } 
     catch (Exception se) 
     { 
      entry.Add(String.Format("{0}: {1}", se.Source, se.Message)); 
     } 

     clntSock.Close(); 

     logger.writeEntry(entry); 
    } 



public class KeepAlive 
{ 
    ArrayList entry; 
    private ILogger logger; 
    private Socket clntSock; 
    public const int BUFSIZE = 1024; 

    public KeepAlive(Socket clntSock, ILogger logger) 
    { 
     this.logger = logger; 
     this.clntSock = clntSock; 
     entry = new ArrayList(); 
    } 

    void LogEntry(ArrayList _entry) 
    { 
     logger.writeEntry(_entry); 
     entry.Clear(); 
    } 

    public void SendKeepAlive() 
    { 
     entry.Add("Keep Alive Thread Entered : Client address and Port = " + clntSock.RemoteEndPoint + ", Thread Number = " + Thread.CurrentThread.GetHashCode()); 

     var message= "Some Keep Alive Message"; 

     try 
     { 
      byte[] messageBuffer = new byte[1024]; 
      LogEntry(entry); 
      for (; ;) 
      { 
       //Check if main thread died 
       if (PoolDispatcher._stopper.WaitOne(100, false)) 
       {         
        break; 
       } 

       if (clntSock.Connected) 
       { 
        entry.Add("Sending the Keep Alive Message... " + message); 
        messageBuffer = Encoding.ASCII.GetBytes(message); 
        clntSock.Send(messageBuffer, 0, messageBuffer.Length, SocketFlags.None); 
       } 
       else 
       { 
        entry.Add("Socket Connection is not active. Keep Alive not sent"); 
        break; 
       } 
       LogEntry(entry); 
       Thread.Sleep(30000); 
      } 
     } 
     catch (SocketException se) 
     { 
      entry.Add(String.Format("{0}: {1}", se.ErrorCode, se.Message)); 
     } 
     catch (ObjectDisposedException ode) 
     { 
      entry.Add("Connection to the socket lost. Child Thread Aborted"); 
     } 
     LogEntry(entry); 
    } 
} 
+1

종료 후 동일한 소켓을 사용하려고합니까? 이전 소켓을 다시 사용하지 않고 새 소켓을 만들어야합니다. – drew010

+1

새 연결을 설정하는 방법을 보여주는 몇 가지 코드를 제공 할 수 있습니까? 관련 코드를 모두 게시하면 누군가가 귀하를 도울 수 있습니다. –

+0

안녕하세요 ... 코드를 추가했습니다 ... 사람들이 살펴보고 내가 뭘 잘못하고 있는지 알려 줄 수 있습니까? handleClient에서 오류가 발생하면 루프에서 빠져 나오고 소켓은 닫히고 소켓의 새 인스턴스가 생성되는 mainThread로 컨트롤이 반환됩니다. – InvisibleDev

답변

0

(안 같은 포트를 통해서) IP 주소로 각 소켓에 대해 바로 접근 단일 스레드에있는 두 개의 모듈 .IE 서버와 클라이언트를 통합하고 각 인스턴스에 대해 읽기, 쓰기의 스레드를 생성하기 쉬운 http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=VS.90%29.aspx & http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener%28v=VS.90%29.aspx

사용이 혼자 완벽하게 작동합니다. 나는이 일을 끝냈다. 그 도움이 되었으면 좋겠다.

관련 문제