簡體   English   中英

TCPClient和TCPListener-NetworkStream-消息順序

[英]TCPClient and TCPListener - NetworkStream - order of messages

我有一個關於通過TCP類發送和接收消息的順序的簡單問題,我找不到100%的答案,而且我的英語還不夠好。

如果我有以下示例:

服務器:

        IPAddress IP = IPAddress.Parse("127.0.0.1");
        int Port = 13000;

        TcpListener Server = new TcpListener(IP, Port);
        TcpClient Client = Server.AcceptTcpClient();
        NetworkStream Stream = Client.GetStream();

        Stream.Write(Buffer1, 0, 4);
        //random time
        Stream.Write(Buffer2, 0, 4);
        //random time
        Stream.Write(Buffer3, 0, 4);

和客戶:

        TCPClient Client = new TcpClient("127.0.0.1", 13000);
        NetworkStream Stream = Client.GetStream();

        Stream.Read(A, 0, 4);
        //random time
        Stream.Read(B, 0, 4);
        //random time
        Stream.Read(C, 0, 4);

是否100%確定我會得到A = Buffer1,B = Buffer2,C = Buffer3?

不能保證每個NetworkStream.Write操作都將對應於NetworkStream.Read操作,該操作將返回已寫入流中的確切數據。 這是TcpListner和TcpClient連接的一個簡單示例:

public class NetworkUtils{

    //Client
    TcpClient client = null;
    int port = 40555;
    string serverIpAddress = "127.0.0.1";
    public Mutex mut = new Mutex();
    int byteToExpecting = 0;
    int savedBufferOffset = 0;
    Byte[] saveDataBuffer = new Byte[20000];
    NetworkStream stream;

    public string ServerIpAddress
    {
        get { return serverIpAddress; }
        set { serverIpAddress = value;}
    }

    string lastSentMsg = String.Empty;
    public string LastSentMsg
    {
        get { return lastSentMsg; }
        set { lastSentMsg = value;}
    }

    //Server
    string clientMsg = String.Empty;
    public string ClientMsg
    {
        get { return clientMsg; }
    }
    public void ClearClientMsg()
    {
        clientMsg = String.Empty;
    }

    TcpListener server=null;

    private string errMsg = String.Empty;
    public string ErrMsg
    {
        get { return errMsg; }
        set { errMsg = value;}
    }

    void ConnectToServer()
    {
        client = new TcpClient(serverIpAddress, port);  
    }

    public bool ClientSendMsg(string message)
    {
        try{

            ConnectToServer();

            Byte[] lengthByteArr = IntToByteArr(message.Length);
            client.GetStream().Write(lengthByteArr, 0, lengthByteArr.Length);

            Byte[] data = Encoding.ASCII.GetBytes(message);
            client.GetStream().Write(data, 0, data.Length);

            client.GetStream().Close();
        }
        catch (Exception e) 
        {
            errMsg = e.Message;
        }

        return errMsg.Length == 0;
    }

    public bool LaunchServer() {
        try {
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");
            server = new TcpListener(localAddr, port);
            server.Start();
            ListenToClients();
        }
        catch(Exception e)
        {
            server.Stop();
        }

        return errMsg.Length == 0;
    }

    void ProcessInformation(IAsyncResult result)
    {
        try{

            TcpClient client;
            client = server.EndAcceptTcpClient(result);
            stream = client.GetStream();
            stream.BeginRead(saveDataBuffer, 0, sizeof(Int32), new AsyncCallback(callbackGetHeadrer), null);
            ListenToClients ();
        }
        catch(Exception e)
        {
            errMsg = e.Message;
            server.Stop();
        }
    }

    void callbackGetHeadrer (IAsyncResult asyncResult) { 
        int lenToRead = stream.EndRead(asyncResult);

        savedBufferOffset = 0;
        byteToExpecting = ByteArrToInt (saveDataBuffer);
        saveDataBuffer = new byte[byteToExpecting];
        stream.BeginRead (saveDataBuffer, 0, byteToExpecting, callback, null);
    }

    void callback (IAsyncResult asyncResult) { 

        int lenToRead = stream.EndRead(asyncResult);

        byteToExpecting -= lenToRead;
        savedBufferOffset += lenToRead;

        /*No one is gurentee that the 'lenToRead' will be correspanding to NetworkStream.Write execution order.
        We need to keep read from the stream until we will get waht we are expecting accrding 'byteToExpecting'
        So here we are keep calling 'stream.BeginRead'.*/
        if (byteToExpecting > 0) {
            stream.BeginRead (saveDataBuffer, savedBufferOffset, byteToExpecting, callback, null);
        } 
        else{
            mut.WaitOne();
            clientMsg = System.Text.Encoding.ASCII.GetString(saveDataBuffer,0, saveDataBuffer.Length);
            mut.ReleaseMutex();

            savedBufferOffset = 0;
            stream.Close();
            client.Close();
        }
    }

    bool ListenToClients()
    {
        try{
            server.BeginAcceptTcpClient( new AsyncCallback( ProcessInformation), server);
        }
        catch(Exception e)
        {
            errMsg = e.Message;
            server.Stop();
        }

        return errMsg.Length == 0;
    }

    public Byte[] IntToByteArr(Int32 intValue)
    {
        byte[] intBytes = BitConverter.GetBytes(intValue);

        if (BitConverter.IsLittleEndian)
            Array.Reverse(intBytes);
        return intBytes;
    }

    public Int32 ByteArrToInt(Byte[] intByteArr)
    {
        Int32 Int32_NUM_OF_BYTES = 4;
        Byte[] buffer = new Byte[Int32_NUM_OF_BYTES];

        for (int i = 0; i < Int32_NUM_OF_BYTES; ++i)
            buffer [i] = intByteArr [i];

        if (BitConverter.IsLittleEndian)
            Array.Reverse (buffer);

        return BitConverter.ToInt32 (buffer, 0);
    }
}

請注意,“ callbackGetHeadrer”負責獲取我們期望接收的數據大小。 稍后,我們將繼續使用'stream.BeginRead'從流中讀取數據,直到獲得關於'stream.Write'操作序列的期望值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM