如何通过异步连接获取完整的消息,而不仅仅是消息的一部分

问题描述 投票:0回答:4

我已经实现了此C#客户端,该客户端通过异步连接与我用Java创建的另一台服务器进行通信。这是客户:

public class NetworkTransaction
{
    private GenericRequest request;
    private const string serverName = "192.168.1.101";
    private const int serverPort = 7777;
    private const int TIMEOUT_MILLISECONDS = 3000;
    private Delegate method;

    public NetworkTransaction(GenericRequest request, Delegate method)
    {
        this.request = request;
        this.method = method;
    }

    public void SendRequest()
    {
        SocketAsyncEventArgs connectionOperation = new SocketAsyncEventArgs();
        DnsEndPoint hostEntry = new DnsEndPoint(serverName, serverPort);
        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        connectionOperation.Completed += new EventHandler<SocketAsyncEventArgs>(SocketEventArg_Completed);
        connectionOperation.RemoteEndPoint = hostEntry;
        connectionOperation.UserToken = socket;

        try
        {
            socket.ConnectAsync(connectionOperation);
        }
        catch (SocketException ex)
        {
            throw new SocketException((int)ex.ErrorCode);
        }
    }

    private void SocketEventArg_Completed(object sender, SocketAsyncEventArgs e)
    {
        switch (e.LastOperation)
        {
            case SocketAsyncOperation.Connect:
                ProcessConnectCompleted(e);
                break;
            case SocketAsyncOperation.Receive:
                ProcessReceiveCompleted(e);
                break;
            case SocketAsyncOperation.Send:
                ProcessSendCompleted(e);
                break;
            default:
                throw new Exception("Invalid operation completed");
        }
    }

    private void ProcessConnectCompleted(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(request.ToJson() + "\n\r");
            e.SetBuffer(buffer, 0, buffer.Length);
            Socket sock = e.UserToken as Socket;
            sock.SendAsync(e);
        }
    }

    private void ProcessSendCompleted(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            Socket sock = e.UserToken as Socket;
            sock.ReceiveAsync(e);
        }
    }

    private void ProcessReceiveCompleted(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
            Socket sock = e.UserToken as Socket;
            sock.Shutdown(SocketShutdown.Send);
            sock.Close();

            method.DynamicInvoke(dataFromServer);
        }
    }
}

我该怎么做才能从服务器获取长消息?为了使客户端尝试读取更多数据以查看我是否实际读取了整个消息,我需要更改什么?由于以下行可能存在问题:string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);仅接收部分消息,而不接收全部消息。

c# sockets asynchronous client-server socketasynceventargs
4个回答
1
投票

为了使客户端尝试读取更多数据以查看我是否实际读取了整个消息,我需要更改什么?

您必须实现一个说“这里有50个字节”“这是所有数据,再见”]的协议。

ProcessReceiveCompleted()每当接收到一条数据时都将被调用,这可以是一个字节到很多字节之间的任何值。套接字不保证将“消息”作为整体发送,因为该级别不存在消息。接收的数据量取决于CPU和网络利用率等因素。

这就是您的协议的来源。必须在服务器和客户端中都定义它。例如,HTTP使用两个CRLF来让客户端说“这是我的请求,请立即响应”

。另一方面,服务器(默认情况下)在发送所有数据时关闭连接,但还会发送Content-length标头,因此客户端可以验证它是否已接收到所有数据。

因此,您必须将数据存储在ProcessReceiveCompleted()中,并在收到整条消息后开始处理。


3
投票

关于创建协议的答案对我帮助最大。我最终要做的是在消息中附加一个“标题”,说明其大小。客户端然后解析标头,并根据消息大小标头和接收到的实际字节数检查是否还有更多数据要发送。如果还有更多的数据要读取,那我就去做:


0
投票

如果使用Web服务,则可以使用双工频道。客户端使用类似以下命令在服务器上注册数据流的位置:


0
投票

我已经同步使用了以下方法(我知道您想要异步)来从HTTP获取数据

© www.soinside.com 2019 - 2024. All rights reserved.