How to use Socket.SendAsync to send large data

余生长醉 提交于 2019-12-07 17:49:36

问题


private void ProcessReceive(SocketAsyncEventArgs e)
{
    // Check if the remote host closed the connection.
    if (e.BytesTransferred > 0)
    {
        if (e.SocketError == SocketError.Success)
        {
            Token token = e.UserToken as Token;
            token.SetData(e);

            Socket s = token.Connection;
            if (s.Available == 0)
            {
                Boolean willRaiseEvent = false;
                // GET DATA TO SEND
                byte[] sendBuffer = token.GetRetBuffer();
                // this.bufferSize IS SocketAsyncEventArgs buffer SIZE
                byte[] tempBuffer = new byte[this.bufferSize];
                int offset = 0;
                int size = (int)Math.Ceiling((double)sendBuffer.Length / (double)this.bufferSize);
                for (int i = 0; i < size - 1; i++)
                {
                    Array.Clear(tempBuffer, 0, this.bufferSize);
                    Array.Copy(sendBuffer, offset, tempBuffer, 0, this.bufferSize);
                    e.SetBuffer(tempBuffer, 0, this.bufferSize);
                    willRaiseEvent = s.SendAsync(e);
                    offset += this.bufferSize;
                }
                int remainSize = sendBuffer.Length - this.bufferSize * (size - 1);
                Array.Clear(tempBuffer, 0, this.bufferSize);
                Array.Copy(sendBuffer, offset, tempBuffer, 0, remainSize);
                e.SetBuffer(tempBuffer, 0, remainSize);
                willRaiseEvent = s.SendAsync(e);

                if (!willRaiseEvent)
                {
                    this.ProcessSend(e);
                }
            }
            else if (!s.ReceiveAsync(e))
            {
                // Read the next block of data sent by client.
                this.ProcessReceive(e);
            }
        }
        else
        {
            this.ProcessError(e);
        }
    }
    else
    {
        this.CloseClientSocket(e);
    }
}

This code is modified from MSDN

Why in circulation, execute s.SendAsync(e) the second time, it will be error

Exception:An asynchronous socket operation is already in progress using this SocketAsyncEventArgs instance

How can I send large data ?


回答1:


You have to wait for the Completed event to be raised before you can make another asynchronous send. Don't forget to add your own event handler in order for you to get the callback:

e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCallback);

You can use my example of an Asynchronous HTTP client to model yours:

private void BeginSend()
{
    _clientState = EClientState.Sending;
    byte[] buffer = GetSomeData(); // gives you data for the buffer

    SocketAsyncEventArgs e = new SocketAsyncEventArgs();
    e.SetBuffer(buffer, 0, buffer.Length);
    e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCallback);

    bool completedAsync = false;

    try
    {
        completedAsync = _socket.SendAsync(e);
    }
    catch (SocketException se)
    {
        Console.WriteLine("Socket Exception: " + se.ErrorCode + " Message: " + se.Message);
    }

    if (!completedAsync)
    {
        // The call completed synchronously so invoke the callback ourselves
        SendCallback(this, e);
    }

}

Here is the callback method:

private void SendCallback(object sender, SocketAsyncEventArgs e)
{
    if (e.SocketError == SocketError.Success)
    {
        // You may need to specify some type of state and 
        // pass it into the BeginSend method so you don't start
        // sending from scratch
        BeginSend();
    }
    else
    {
        Console.WriteLine("Socket Error: {0} when sending to {1}",
               e.SocketError,
               _asyncTask.Host);
    }
}

After the callback is complete, you can make another call to BeginSend again, until you're done sending data.




回答2:


The problem is not that you have to wait until Completed is raised. I think, it is also not the purpose of async programing to wait for any event.

But the SocketAsyncEventArgs can only be reused if the last action is completed. So, you can resolve the issue just by create a new SocketAsyncEventArgs within each loop.




回答3:


Another solution: you may use blocked socket, this return after completition or error, but it must be in another thread.



来源:https://stackoverflow.com/questions/9170126/how-to-use-socket-sendasync-to-send-large-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!