0

我已经实现了这个 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);它只接收消息的一部分而不是整个消息。

4

4 回答 4

3

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

if (messageSizeRemaining > 0)
{
      sock.ReceiveAsync(e);
      return;
}
于 2012-06-13T16:01:52.920 回答
1

为了让客户端尝试阅读更多数据以查看我是否真的阅读了整个消息,我需要更改什么?

你必须实现一个协议,上面写着“Here come 50 bytes”“This is all data, goodbye”

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

这就是您的协议的用武之地。这必须在服务器和客户端中定义。例如,HTTP 使用两个CRLF's 让客户端说“这是我的请求,请立即响应”。另一方面,服务器(默认情况下)在发送所有数据时关闭连接,但也会发送一个Content-length标头,因此客户端可以验证它是否已收到所有数据。

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

于 2012-06-13T12:31:36.230 回答
0

如果您使用 Web 服务,则可以使用双工通道。客户端使用以下方式在服务器上注册数据流:

[OperationContract(IsOneWay = true)]
void RequestData();

服务器会将调用 OneWay 操作的数据发送回客户端,例如:

[OperationContract(IsOneWay = true)]
void SendNewData(byte[] data, bool completed)

客户端会将所有数据组合在一起,并在收到完成标志时从服务器注销。

要了解有关 DuplexChannels 的更多信息,请查看此处:Duplex Services

于 2012-06-13T12:36:36.743 回答
0

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

    public static Stream getDataFromHttp(string strUrl)
    {
        Stream strmOutput = null;
        try
        {
            HttpWebRequest request;
            Uri targetUri = new Uri(strUrl);
            request = (HttpWebRequest)HttpWebRequest.Create(targetUri);
            request.Timeout = 5000;
            request.ReadWriteTimeout = 20000;
            request.Method = "Get";


            request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)";
            if (request != null)
            {
                request.GetResponse();
                if (request.HaveResponse)
                {
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    strmOutput = response.GetResponseStream();
                }
            }

        }
        catch (WebException wex)
        {

        }
        catch (Exception ex)
        {

        }
        return strmOutput;
    }

现在要将流转换为文本,请使用以下命令:

    Public Static String StreamToString(Stream stream)
    {
            StreamReader SR = new StreamReader(stream);
            try
            {
               String strOutput = SR.ReadToEnd();
               Return strOutput;
             }
             catch(Exception ex)
             {
                  return ex.message
             }
   }

希望这有效

于 2012-06-13T12:44:48.190 回答