TCPClient和TCPListener - NetworkStream - 消息的顺序

时间:2016-11-25 08:11:19

标签: c# tcpclient tcplistener networkstream

我有一个简单的问题,关于通过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?

1 个答案:

答案 0 :(得分:0)

无法保证每次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'操作的顺序。