2009-10-16 12 views
3

Je dois écrire un serveur TCP pour un projet au travail et j'ai cherché comment faire. J'ai obtenu une réponse MSDN et j'ai réussi à le faire fonctionner, mais je n'ai aucune idée de comment obtenir des données pour être en mesure de recevoir dans les deux sens. Les prises ne seront pas connectées plus de 30 secondes MAX (car mon patron ne veut pas que les prises restent ouvertes sur les ordinateurs ici). Le but de cette classe est de fournir un moyen rapide pour moi dans mon programme principal de récupérer des données sur un ordinateur et son utilisateur.TcpServer - Envoyer et recevoir des données

En nommant l'espace de noms, vous pouvez probablement deviner que c'est pour un laboratoire d'informatique.

namespace LabAssist.Server.Common.Objects { 
    using Atlantis.Net.Sockets; 

    using LabAssist.Server.Common.Data; 

    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Net; 
    using System.Net.Sockets; 
    using System.Text; 
    using System.Windows.Forms; 

    public class TcpServer { 

     #region Constructor(s) 

     public TcpServer(IPEndPoint endPoint) { 
      RemoteEndPoint = endPoint; 
      Host = new Socket(RemoteEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
     } 

     public TcpServer(String hostNameOrIpAddress, Int32 port) { 
      RemoteEndPoint = new IPEndPoint(Dns.GetHostEntry(hostNameOrIpAddress).AddressList[0], port); 
      Host = new Socket(RemoteEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
     } 

     public TcpServer(Int32 port) { 
      RemoteEndPoint = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], port); 
      Host = new Socket(RemoteEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
     } 

     #endregion 

     #region Fields 

     private Boolean m_IsBound = false; 
     private List<Socket> m_Connections = new List<Socket>(50); // allow 50 sockets 
     private static System.Threading.ManualResetEvent AllDone = new System.Threading.ManualResetEvent(false); 

     #endregion 

     #region Properties 

     private Int32 m_Backlog = 32; 
     /// <summary> 
     ///  Gets or sets the number of connections the host can accept at any given point 
     /// </summary> 
     public Int32 Backlog { 
      set { 
       m_Backlog = value; 
      } 
      get { 
       return m_Backlog; 
      } 
     } 

     private Socket m_Host = null; 
     /// <summary> 
     ///  Gets or sets the host master socket 
     /// </summary> 
     public Socket Host { 
      private set { 
       m_Host = value; 
      } 
      get { 
       return m_Host; 
      } 
     } 

     private Int32 m_Port = 1337; 
     /// <summary> 
     ///  Gets or sets the binding port for the server 
     /// </summary> 
     public Int32 Port { 
      set { 
       m_Port = value; 
      } 
      get { 
       return m_Port; 
      } 
     } 

     private IPEndPoint m_EndPoint = null; 
     /// <summary> 
     ///  Gets or sets the binding address to be used when binding the socket 
     /// </summary> 
     public IPEndPoint RemoteEndPoint { 
      private set { 
       m_EndPoint = value; 
      } 
      get {    // follows a singleton pattern with a private-setter. 
       if (m_EndPoint == null) { 
        RemoteEndPoint = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port); 
       } 

       return m_EndPoint; 
      } 
     } 

     #endregion 

     #region Methods 

     private void AcceptCallback(IAsyncResult ar) { 
      Socket client = ((Socket)ar.AsyncState); 
      Socket handler = client.EndAccept(ar); 
      m_Connections.Add(handler); 

      AllDone.Set(); 

      Console.WriteLine("Client accepted.\t Remote address and port : {0}", handler.RemoteEndPoint.ToString()); 

      Byte[] buf = Encoding.ASCII.GetBytes("hello world. This is my first TCP Server >:)"); 
      Int32 ret = 0; 
      Boolean ext = false; 
      //try-catch temporary until sending is figured out. >< 
      try { 
       ret = client.Send(buf, buf.Length, SocketFlags.None); 
      } catch (Exception ex) { 
       ext = true; 
       ConsoleColor c = Console.ForegroundColor; 
       Console.ForegroundColor = ConsoleColor.Yellow; 
       Console.WriteLine(ex.ToString()); 
       Console.ForegroundColor = c; 
      } 
      // error check for debugging 
      if (ret > 0) { 
       Console.WriteLine("Sent -> {0}", Encoding.ASCII.GetString(buf, 0, buf.Length)); 
      } else { 
       if (ext) { 
        ConsoleColor c = Console.ForegroundColor; 
        Console.ForegroundColor = ConsoleColor.Red; 
        Console.WriteLine("Caught an exception"); 
        Console.ForegroundColor = c; 
       } 
       Console.WriteLine("Failed to send welcome packet to client."); 
      } 

      State state = new State(); 
      state.WorkSocket = handler; 
      handler.BeginReceive(state.Buffer, 0, State.BufferSize, 0, new AsyncCallback(ReceiveDataCallback), state); 
     } 

     /// <summary> 
     ///  Intialises the socket to listen and begins to accept connections 
     /// </summary> 
     /// <returns></returns> 
     public void Initialise() { 
      Host.Bind(RemoteEndPoint); 

      Console.WriteLine("Local address and port : {0}", RemoteEndPoint.ToString()); 

      m_IsBound = true; 
      Host.Listen(Backlog); 
      try { 
       while (true) { 
        AllDone.Reset(); 

        Console.WriteLine("Awaiting{0} client connection...", (m_Connections.Count > 0 ? " another" : "")); 

        Host.BeginAccept(new AsyncCallback(AcceptCallback), Host); 

        AllDone.WaitOne(); 

        Application.DoEvents(); 
       } 
      } catch (Exception e) { 
       Log.HandledException(e); 
      } 
     } 

     private void ReceiveDataCallback(IAsyncResult ar) { 
      State state = ((State)ar.AsyncState); 
      Socket handler = state.WorkSocket; 

      if (!handler.IsConnected()) { 
       return; 
      } 

      Int32 read = handler.EndReceive(ar); 

      if (read > 0) { 
       state.DataReceived.Append(Encoding.ASCII.GetString(state.Buffer, 0, read)); 
       handler.BeginReceive(state.Buffer, 0, State.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveDataCallback), state); 
      } else { 
       if (state.DataReceived.Length > 1) { 
        String content = state.DataReceived.ToString(); 
        Console.WriteLine("Read {0} bytes from socket.\n Data: {1}", content.Length, content); 
       } 
       handler.Close(); 
      } 
     } 

     #endregion 
    } 
} 

En ce moment, je suis en train d'obtenir une version simple de travail où le connecter le client reçoit un paquet à partir du serveur en disant quelque chose comme « bonjour le monde du net! ». Je continue d'avoir une exception étrange. Le code ci-dessus est juste une "copie" directe (pour ainsi dire) de MSDN. J'ai utilisé MSDN's example comme un guide lors de l'écriture et j'ai encore du travail à faire dessus (comme pour supprimer la nature de blocage qu'il utilise). Pour l'instant, je veux juste savoir comment envoyer des données de l'hôte à un client qui se connecte! :(

System.Net.Sockets.SocketException: A request to send or receive data was disall owed 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, SocketFlags socketFlags) 
    at System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 size, SocketFlags socketFlags) 
    at LabAssist.Server.Common.Objects.TcpServer.AcceptCallback(IAsyncResult ar) in F:\Source\ACCL\Lab Suite\Code\LabAssist.Server\Common\Objects\TcpServer.cs:li 
ne 119 
+0

Quelle est l'exception bizarre –

+0

Er oui, était SocketException dire l'envoi ou la réception est désactivé sur la prise.?.?/I havre de paix » t vraiment utilisé des raw-sockets * beaucoup * jusqu'à maintenant. – Zack

Répondre

2

Je suggère d'utiliser UDP plutôt que TCP avec des commandes manuelles ACK, de cette façon vous ne recevez pas les sockets connectées constants par votre patron. UDP Information

Un autre point que je voudrais faire est de ne pas utiliser socket brut comme votre première connexion TCP, utilisez la classe TCPClient TCPClient

Questions connexes