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

C# 如何通过异步连接获取完整消息,而不仅仅是其中的一部分,c#,sockets,asynchronous,client-server,socketasynceventargs,C#,Sockets,Asynchronous,Client Server,Socketasynceventargs,我实现了这个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_MILLISEC

我实现了这个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);
        }
    }
}
公共类网络事务
{
私人一般请求;
私有常量字符串serverName=“192.168.1.101”;
private const int serverPort=7777;
private const int TIMEOUT_毫秒=3000;
私有委托方法;
公共网络事务(GenericRequest请求、委托方法)
{
this.request=请求;
这个方法=方法;
}
公共无效发送请求()
{
SocketAsyncEventArgs connectionOperation=新的SocketAsyncEventArgs();
DnsEndPoint hostEntry=新的DnsEndPoint(服务器名、服务器端口);
Socket Socket=新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.Tcp);
connectionOperation.Completed+=新事件处理程序(SocketEventTarget_已完成);
connectionOperation.RemoteEndPoint=hostEntry;
connectionOperation.UserToken=套接字;
尝试
{
ConnectAsync(connectionOperation);
}
捕获(SocketException例外)
{
抛出新的SocketException((int)ex.ErrorCode);
}
}
私有无效SocketEventArgs_已完成(对象发送方,SocketAsyncEventArgs e)
{
开关(如上次操作)
{
案例SocketAsyncOperation。连接:
(e)已完成的程序;
打破
案例SocketAsyncOperation。接收:
处理完毕(e);
打破
案例SocketAsyncOperation。发送:
完成(e);
打破
违约:
抛出新异常(“无效操作已完成”);
}
}
私有void ProcessConnectCompleted(SocketAsyncEventArgs e)
{
如果(e.SocketError==SocketError.Success)
{
byte[]buffer=Encoding.UTF8.GetBytes(request.ToJson()+“\n\r”);
e、 SetBuffer(buffer,0,buffer.Length);
Socket sock=e.UserToken作为Socket;
sock.SendAsync(e);
}
}
私有void ProcessSendCompleted(SocketAsyncEventArgs e)
{
如果(e.SocketError==SocketError.Success)
{
Socket sock=e.UserToken作为Socket;
sock.ReceiveAsync(e);
}
}
私有无效进程ReceiveCompleted(SocketAsyncEventArgs e)
{
如果(e.SocketError==SocketError.Success)
{
字符串dataFromServer=Encoding.UTF8.GetString(e.Buffer,0,e.bytesttransfered);
Socket sock=e.UserToken作为Socket;
sock.Shutdown(SocketShutdown.Send);
sock.Close();
DynamicInvoke方法(dataFromServer);
}
}
}
如何从服务器获取长消息?为了让客户端尝试读取更多数据以查看我是否真正读取了整个消息,我需要更改什么?因为行可能有问题:
stringdatafromserver=Encoding.UTF8.GetString(e.Buffer,0,e.bytesttransfered)只接收部分消息,而不接收整个消息

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

你必须实现一个协议,上面写着“这里有50个字节”或者“这是所有的数据,再见”

ProcessReceiveCompleted()。套接字不能保证“消息”作为一个整体发送,因为该级别上不存在消息。接收的数据量取决于CPU和网络利用率等因素

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

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

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

你必须实现一个协议,上面写着“这里有50个字节”或者“这是所有的数据,再见”

ProcessReceiveCompleted()。套接字不能保证“消息”作为一个整体发送,因为该级别上不存在消息。接收的数据量取决于CPU和网络利用率等因素

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


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

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

[OperationContract(IsOneWay = true)]
void RequestData();
服务器将通过调用单向操作将数据发送回客户端,如:

[OperationContract(IsOneWay = true)]
void SendNewData(byte[] data, bool completed)
客户端将所有数据合并在一起,当接收到完成标志时,它将从服务器注销


要阅读有关双工频道的更多信息,请查看此处:。

如果您使用web服务,则可以使用双工频道。 惠尔
    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
             }
   }
if (messageSizeRemaining > 0)
{
      sock.ReceiveAsync(e);
      return;
}