2012-05-07 2 views
-1

J'ai essayé de faire fonctionner cela pendant un certain temps et j'ai même cherché à travers la plupart du forum, mais je n'ai rien pour l'instant. Process_send fonctionne parfaitement dans la mesure où mon client peut recevoir tout ce que le serveur envoie. Cependant, lorsque le client dit quelque chose, le tampon dans la fonction process_receive est retourné comme nul, même si la propriété TransferredBytes dit "46", ce qui est censé être.Tampon serveur C# TCP

S'il vous plaît laissez-moi savoir comment je peux résoudre ce problème. Merci!

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Net.Sockets; 
using System.Threading; 
using System.Net; 

namespace MonkeySyncServer 
{ 
    public partial class ServerForm : Form 
    { 
     public ServerForm() 
     { 
      InitializeComponent(); 
     } 

     private void btn_startServer_Click(object sender, EventArgs e) 
     { 
      Server s = new Server(100, 1024); 
      s.Init(); 
      s.Start(new IPEndPoint(IPAddress.Any, 1000)); 
     } 


    } 
    /// <summary> 
    /// Implements the connection logic for the socket server. 
    /// </summary> 
    class Server 
    { 
     private int m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously 
     private int m_receiveBufferSize;// buffer size to use for each socket I/O operation 
     BufferManager m_bufferManager; // represents a large reusable set of buffers for all socket operations 
     const int opsToPreAlloc = 2; // read, write (don't alloc buffer space for accepts) 
     Socket listenSocket;   // the socket used to listen for incoming connection requests 
     // pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations 
     SocketAsyncEventArgsPool m_readWritePool; 
     int m_totalBytesRead;   // counter of the total # bytes received by the server 
     int m_numConnectedSockets;  // the total number of clients connected to the server 
     Semaphore m_maxNumberAcceptedClients; 

     /// <summary> 
     /// Create an uninitialized server instance. To start the server listening for connection requests 
     /// call the Init method followed by Start method 
     /// </summary> 
     /// <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param> 
     /// <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param> 
     public Server(int numConnections, int receiveBufferSize) 
     { 
      m_totalBytesRead = 0; 
      m_numConnectedSockets = 0; 
      m_numConnections = numConnections; 
      m_receiveBufferSize = receiveBufferSize; 
      // allocate buffers such that the maximum number of sockets can have one outstanding read and 
      //write posted to the socket simultaneously 
      m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc, 
       receiveBufferSize); 

      m_readWritePool = new SocketAsyncEventArgsPool(numConnections); 
      m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); 
     } 

     /// <summary> 
     /// Initializes the server by preallocating reusable buffers and context objects. These objects do not 
     /// need to be preallocated or reused, by is done this way to illustrate how the API can easily be used 
     /// to create reusable objects to increase server performance. 
     /// </summary> 
     public void Init() 
     { 
      // Allocates one large byte buffer which all I/O operations use a piece of. This gaurds 
      // against memory fragmentation 
      m_bufferManager.InitBuffer(); 

      // preallocate pool of SocketAsyncEventArgs objects 
      SocketAsyncEventArgs readWriteEventArg; 

      for (int i = 0; i < m_numConnections; i++) 
      { 
       //Pre-allocate a set of reusable SocketAsyncEventArgs 
       readWriteEventArg = new SocketAsyncEventArgs(); 
       readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); 
       readWriteEventArg.UserToken = new AsyncUserToken(); 

       // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object 
       m_bufferManager.SetBuffer(readWriteEventArg); 

       // add SocketAsyncEventArg to the pool 
       m_readWritePool.Push(readWriteEventArg); 
      } 

     } 

     /// <summary> 
     /// Starts the server such that it is listening for incoming connection requests.  
     /// </summary> 
     /// <param name="localEndPoint">The endpoint which the server will listening for conenction requests on</param> 
     public void Start(IPEndPoint localEndPoint) 
     { 
      // create the socket which listens for incoming connections 
      listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
      listenSocket.Bind(localEndPoint); 
      // start the server with a listen backlog of 100 connections 
      listenSocket.Listen(100); 

      // post accepts on the listening socket 
      StartAccept(null); 


     } 


     /// <summary> 
     /// Begins an operation to accept a connection request from the client 
     /// </summary> 
     /// <param name="acceptEventArg">The context object to use when issuing the accept operation on the 
     /// server's listening socket</param> 
     public void StartAccept(SocketAsyncEventArgs acceptEventArg) 
     { 
      if (acceptEventArg == null) 
      { 
       acceptEventArg = new SocketAsyncEventArgs(); 
       acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed); 
      } 
      else 
      { 
       // socket must be cleared since the context object is being reused 
       acceptEventArg.AcceptSocket = null; 
      } 

      m_maxNumberAcceptedClients.WaitOne(); 
      bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg); 
      if (!willRaiseEvent) 
      { 
       ProcessAccept(acceptEventArg); 
      } 
     } 

     /// <summary> 
     /// This method is the callback method associated with Socket.AcceptAsync operations and is invoked 
     /// when an accept operation is complete 
     /// </summary> 
     void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) 
     { 
      ProcessAccept(e); 
     } 

     private void ProcessAccept(SocketAsyncEventArgs e) 
     { 
      Interlocked.Increment(ref m_numConnectedSockets); 
      Console.WriteLine("Client connection accepted. There are {0} clients connected to the server", 
       m_numConnectedSockets); 

      // Get the socket for the accepted client connection and put it into the 
      //ReadEventArg object user token 
      SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop(); 
      ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket; 
      byte[] d = e.Buffer; 

      // As soon as the client is connected, post a receive to the connection 
      bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs); 

      d = d; 
      if (!willRaiseEvent) 
      { 
       ProcessReceive(readEventArgs); 
      } 

      // Accept the next connection request 
      StartAccept(e); 
     } 



     /// <summary> 
     /// This method is called whenever a receive or send opreation is completed on a socket 
     /// </summary> 
     /// <param name="e">SocketAsyncEventArg associated with the completed receive operation</param> 
     void IO_Completed(object sender, SocketAsyncEventArgs e) 
     { 
      // determine which type of operation just completed and call the associated handler 
      switch (e.LastOperation) 
      { 
       case SocketAsyncOperation.Receive: 
        ProcessReceive(e); 
        break; 
       case SocketAsyncOperation.Send: 
        ProcessSend(e); 
        break; 
       default: 
        throw new ArgumentException("The last operation completed on the socket was not a receive or send"); 
      } 

     } 

     private bool sendToClient(AsyncUserToken token, SocketAsyncEventArgs e, string s) 
     { 
      // Send 'Hello World' to the server 
      byte[] buffer = Encoding.UTF8.GetBytes(s); 
      Console.WriteLine("Sending: " + buffer.Length + " bytes of data"); 
      e.SetBuffer(buffer, 0, buffer.Length);    
      bool willRaiseEvent = token.Socket.SendAsync(e); 
      return willRaiseEvent; 
     } 

     /// <summary> 
     /// This method is invoked when an asycnhronous receive operation completes. If the 
     /// remote host closed the connection, then the socket is closed. If data was received then 
     /// the data is echoed back to the client. 
     /// </summary> 
     private void ProcessReceive(SocketAsyncEventArgs e) 
     { 
      m_bufferManager.SetBuffer(e); 
      // check if the remote host closed the connection 
      AsyncUserToken token = (AsyncUserToken)e.UserToken; 
      if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) 
      { 
       //increment the count of the total bytes receive by the server 
       Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred); 
       // Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead); 
       Console.WriteLine("Received from client: {0}", Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred)); 


       byte[] data = new byte[1024]; 
       data = e.Buffer; 
      String dataString = Encoding.UTF8.GetString(data); 


       if (dataString.StartsWith("hello")) 
       { 
        token.encryptionKey = Encoding.UTF8.GetString(data).Substring(5, dataString.IndexOf("world") - 5); 
        Console.WriteLine(token.encryptionKey); 
       } 
       /* bool willRaiseEvent = sendToClient(token, e, "hello world"); 

       if (!willRaiseEvent) 
       { 
        ProcessSend(e); 
       }*/ 



      } 
      else 
      { 
       CloseClientSocket(e); 
      } 



     } 

     /// <summary> 
     /// This method is invoked when an asynchronous send operation completes. The method issues another receive 
     /// on the socket to read any additional data sent from the client 
     /// </summary> 
     /// <param name="e"></param> 
     private void ProcessSend(SocketAsyncEventArgs e) 
     { 
      if (e.SocketError == SocketError.Success) 
      { 
       // done echoing data back to the client 
       AsyncUserToken token = (AsyncUserToken)e.UserToken; 
       // read the next block of data send from the client 
       bool willRaiseEvent = token.Socket.ReceiveAsync(e); 
       if (!willRaiseEvent) 
       { 
       // e.SetBuffer(e.Offset, listenSocket.ReceiveBufferSize); 
       //  ProcessReceive(e); 
       } 
      } 
      else 
      { 
       CloseClientSocket(e); 
      } 
     } 

     private void CloseClientSocket(SocketAsyncEventArgs e) 
     { 
      AsyncUserToken token = e.UserToken as AsyncUserToken; 

      // close the socket associated with the client 
      try 
      { 
       token.Socket.Shutdown(SocketShutdown.Send); 
      } 
      // throws if client process has already closed 
      catch (Exception) { } 
      token.Socket.Close(); 

      // decrement the counter keeping track of the total number of clients connected to the server 
      Interlocked.Decrement(ref m_numConnectedSockets); 
      m_maxNumberAcceptedClients.Release(); 
      Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets); 

      // Free the SocketAsyncEventArg so they can be reused by another client 
      m_readWritePool.Push(e); 
     } 

    } 
} 
+2

que vous avez posté plus de 300 lignes de code qui est beaucoup demander à quiconque de regarder à travers. Pouvez-vous distiller votre code à seulement les bits essentiels qui causent le problème, mais encore compiler? –

+1

FYI à toute personne qui se sent comme attaquer ce problème, c'est copypasta avec la source d'origine ici: http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx –

+0

merci, je devrais J'ai mentionné que ce code vient de là ... – rkrishnan2012

Répondre

1

Juste une supposition sauvage basée sur le code. Je vous suggère de parcourir ce code avec un débogueur, la réponse devrait être assez claire quand vous le faites.

Ces lignes se méfient:

byte[] data = new byte[1024]; 
data = e.Buffer; // reassigns data, so that byte[1024] gets ignored. 
String dataString = Encoding.UTF8.GetString(data); // Ignores the e.Offset value. 

Je pense que le tampon obtient-initialisé à zéro, mais pour des raisons je ne connais pas les données de prise ne sont pas lues dans le début du tampon, mais plutôt un autre endroit . L'encodeur UTF8 voit un 0 comme premier caractère (0 étant le signifiant de fin de chaîne dans UTF8) et retourne une chaîne vide, différente de null.

Remplacer les trois lignes avec:

String dataString = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred); 
+0

Merci! J'ai fait quelque chose de similaire et ça marche maintenant. – rkrishnan2012