2015-09-27 113 views
3

我正在開發一個將接收消息並作出響應的服務器應用程序。沒有什麼新東西。所以,其實我跟着this answerthis post,但我不能讓AcceptAsync()方法觸發Completed事件。在互聯網上到處搜索,嘗試類似問題的解決方案,但似乎沒有任何工作適合我。爲什麼Socket.AcceptAsync未觸發SocketAsyncEventArgs完成的事件?

我也嘗試從Task.Run()打電話server.Start(),但沒有運氣。我知道服務器聽的很好,因爲我可以在netstat -an上看到它,如果我在Listen()之後中斷,我也可以使用telnet進行連接。

從我的理解,如果AcceptAsync()方法返回true,它會提高SocketAsyncEventArgs.Completed事件,這將再次調用StartAccept()方法,並將循環,直到我強制退出。

SocketAsyncEventArgs.Completed也對:http://prntscr.com/8l3x8p,但仍然不起作用。

這裏是我的一段代碼:

public class TTSServer 
{ 
    private Socket m_serverSocket; 
    private IPEndPoint m_serverEndPoint; 

    [DefaultValue(39454)] 
    public int Port { get; set; } 
    [DefaultValue(100)] 
    public int IncommingQueueSize { get; set; } 
    [DefaultValue(512)] 
    public int BufferSize { get; set; } 

    //Listeners to hold event when something happens. 

    public static void Main(string[] args) 
    { 
     TTSServer server = new TTSServer(39454, 100, 512); 
     server.Start(); 
    } 

    public TTSServer(int port, int queueSize, int bufferSize) 
    { 
     Port = port; 
     IncommingQueueSize = queueSize; 
     BufferSize = bufferSize; 
    } 


    public void Start() 
    { 
     Console.WriteLine("Starting TTS Server (Port: {0}, QueueSize: {1}, BufferSize: {2})", Port, IncommingQueueSize, BufferSize); 
     m_serverEndPoint = new IPEndPoint(IPAddress.Any, Port); 
     m_serverSocket = new Socket(m_serverEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
     Console.WriteLine("Binding ({0})", m_serverEndPoint.ToString()); 
     m_serverSocket.Bind(m_serverEndPoint); 
     Console.WriteLine("Listening"); 
     m_serverSocket.Listen(IncommingQueueSize); 

     StartAccept(null); 
    } 

    public void Stop() 
    { 

    } 

    /// <summary> 
    /// Receive a incomming connection attemp in an asynchronous way. 
    /// </summary> 
    /// <param name="socketEvent">If is null, a new object is created, else, it'll be used for cache friendly reason.</param> 
    private void StartAccept(SocketAsyncEventArgs socketEvent) 
    { 
     //If received reference points to null, let's create a new object. 
     if (socketEvent == null) 
     { 
      Console.WriteLine("Accepting new connections..."); 
      socketEvent = new SocketAsyncEventArgs(); 
      socketEvent.Completed += AcceptCompleted; //Add a callback on completed accept incomming connections attemp. 
     } 
     else 
     { 
      //Clear current incomming connection socket, so object may be reused. 
      socketEvent.AcceptSocket = null; 
     } 

     //If there is an incomming connection pending(pooled), this method will receive the connection in a async way (witch returns true) 
     //and will call SocketAsyncEventArgs.Completed callback when done. 
     //Else, it waits for a new connection, returns false, and don't won't SocketAsyncEventArgs.Completed callback when done, so we have to 
     //call it manually. 
     bool async = true; 

     //When I debug this code, async receive true from AcceptAsync. 
     async = m_serverSocket.AcceptAsync(socketEvent); 

     if (!async) 
     { 
      AcceptCompleted(this, socketEvent); 
     } 
    } 

    /// <summary> 
    /// Handles a incomming connection after it's fully received. This function will do the business logic for incomming connections and prepare 
    /// to receive data. 
    /// </summary> 
    /// <param name="sender">Object who posted this function</param> 
    /// <param name="socketEvent">Information of the incomming connection</param> 
    private void AcceptCompleted(object sender, SocketAsyncEventArgs socketEvent) 
    { 
     Connection connection = new Connection(this, socketEvent.AcceptSocket, BufferSize); 

     SocketAsyncEventArgs connectedSocketEvent = new SocketAsyncEventArgs(); 
     connectedSocketEvent.UserToken = connection; 

     //Add a receive callback, to be called whenever the Receive function is finished. 
     connectedSocketEvent.Completed += FlushBuffer; 
     ReceiveData(connectedSocketEvent); 

     //Accept next incomming connection. 
     StartAccept(socketEvent); 
    } 

不知道爲什麼,在AcceptCompleted是從來沒有發射,即使AcceptAsync()方法返回true

+0

這不是一個答案,但真正的問題是沒有實際意義。您應該通過在APM模式中使用await包裝來開發套接字應用程序。根本不要使用socketeventargs。所有這些都已經過時了。使用網上現成的包裝。問題將會消失。也不是99%的套接字教程被破壞或被誤導。 – usr

+0

你會推薦我嗎? –

+0

您只需要添加等待Socket的東西。這是幾十行代碼。 – usr

回答

-1

編輯:在您的示例server.Start後放置一行代碼。

一時興起,你會考慮改變一條線。

更改此

socketEvent.Completed += AcceptCompleted; //Add a callback on completed accept incomming connections attemp. 

爲了此

socketEvent.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptCompleted); //Add a callback on completed accept incomming connections attemp. 
+0

這是我試過的第一件事,但沒有任何區別。 –

1

似乎根本原因是默認緩衝:

任選地,緩衝器可被提供,其中到在ConnectAsync方法成功後接收套接字上的初始數據塊秒。在這種情況下,需要將SocketAsyncEventArgs.Buffer屬性設置爲包含要接收的數據的緩衝區,並且需要將SocketAsyncEventArgs.Count屬性設置爲緩衝區中要接收的最大數據字節數。這些屬性可以使用SocketAsyncEventArgs.SetBuffer方法設置。傳入的部分緩衝區將在內部使用,供基礎Winsock AcceptEx調用使用。這意味着返回的數據量將始終小於所提供的System.Net.Sockets.SocketAsyncEventArgs實例上SocketAsyncEventArgs.Count屬性的值。內部使用的緩衝區的數量根據套接字的地址系列而異。所需的最小緩衝區大小爲288個字節。如果指定了更大的緩衝區大小,那麼Socket會期望一些額外的數據,而不是由Winsock AcceptEx調用收到的地址數據,並且將等待直到收到額外的數據。如果發生超時,則重置連接。所以如果額外的數據需要特定的數量,那麼緩衝區大小應該設置爲最小緩衝區大小加上這個數量。

- Socket.AcceptAsync Method (SocketAsyncEventArgs), MSDN

假設緩衝不需要,禁用緩衝seems to be a solution

SocketAsyncEventArgs args = ...; 
args.SetBuffer(null, 0, 0); 
相關問題