Xử lý vấn về bộ đệm dữ liệu trong ứng dụng client – server (TCP Socket) Phần 2

0
217

Ở bài viết Xử lý vấn về bộ đệm dữ liệu trong ứng dụng client – server (TCP Socket) Phần 1 đã giới thiệu đến các bạn cách xử lý bằng cách sử dụng các thông điệp với cùng kích thước cố định. Nhưng đây  là một giải pháp lãng phí bởi vì tất cả các thông điệp đều phải cùng kích thước. Nếu các thông điệp nào chưa đủ kích thước thì phải thêm phần đệm vào, gây lãng phí băng thông mạng.

Một giải pháp cho vấn đề cho phép các  thông điệp được gởi với các kích thước khác nhau là gởi kích thước thông điệp kèm với thông điệp. Bằng cách này thiết bị nhận sẽ biết được kích thước của mỗi thông điệp.

Để thực hiện việc này ta sửa đổi phương thức SendData() trong bài viết trước thành phương thức SendVarData :

 private static int SendVarData(Socket s, byte[] data)
    {

        int total = 0;
        int size = data.Length;

        int dataleft = size; int sent;

        byte[] datasize = new byte[4];

        datasize = BitConverter.GetBytes(size);

        sent = s.Send(datasize);
        while (total < size)
        {

            sent = s.Send(data, total, dataleft, SocketFlags.None);

            total += sent;

            dataleft -= sent;

        }
        return total;

    }

Trong phương thức SendVarData(), ta sẽ lấy kích thước của thông điệp và gắn nó vào đầu của thông điệp, kích thước này là một số interger 4 byte. Kích thước tối đa của mỗi thông  điệp này là 65KB. Giá trị interger 4 byte này  đầu tiên  được chuyển thành mảng các byte, hàm GetBytes() của lớp BitConverter được dùng để thực hiện việc này. Mảng kích thước sau đó được gởi đến thiết bị ở xa, sau khi gởi kích thước thông điệp xong, phần chính của thông điệp được gởi đi, kỹ thuật gởi cũng giống như trong ví dụ trước, chúng ta sẽ lặp cho đến khi tất cả các byte đã được gởi.

Bước tiếp theo là tạo ra một phương thức có thể nhận 4 byte kích thước thông điệp và toàn bộ thông điệp. phương thức ReceiveData() trong  bài viết trước được sửa đổi để thực hiện việc này:

    private static byte[] ReceiveVarData(Socket s)
    {
        int total = 0;
        int recv;
        byte[] datasize = new byte[4];

        recv = s.Receive(datasize, 0, 4, 0);
        int size = BitConverter.ToInt32(datasize, 0);
        int dataleft = size;
        byte[] data = new byte[size];
        while (total < size)
        {

            recv = s.Receive(data, total, dataleft, 0);
            if (recv == 0)
            {

                data = Encoding.ASCII.GetBytes("exit ");
                break;

            }

            total += recv;

            dataleft -= recv;

        }
        return data;

    }

Hàm ReceiveVarData() nhận 4 byte đầu tiên của thông điệp và chuyển nó thành giá trị interger bằng phương thức GetInt32() của lớp BitConverter.

Chương trình Server gởi và nhận thông điệp cùng với kích thước

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class VarTcpSrvr
{

    private static int SendVarData(Socket s, byte[] data)
    {

        int total = 0; int size = data.Length; int dataleft = size; int sent;
        byte[] datasize = new byte[4];

        datasize = BitConverter.GetBytes(size);

        sent = s.Send(datasize);
        while (total < size)
        {

            sent = s.Send(data, total, dataleft, SocketFlags.None);

            total += sent;

            dataleft -= sent;

        }
        return total;

    }

    private static byte[] ReceiveVarData(Socket s)
    {
        int total = 0;
        int recv;
        byte[] datasize = new byte[4];

        recv = s.Receive(datasize, 0, 4, 0);
        int size = BitConverter.ToInt32(datasize, 0);
        int dataleft = size;
        byte[] data = new byte[size];
        while (total < size)
        {

            recv = s.Receive(data, total, dataleft, 0);
            if (recv == 0)
            {

                data = Encoding.ASCII.GetBytes("exit ");




                break;
            }

            total += recv;

            dataleft -= recv;

        }
        return data;

    }

    public static void Main()
    {

        byte[] data = new byte[1024];
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);
        Socket newsock = new Socket(AddressFamily.InterNetwork,
        SocketType.Stream, ProtocolType.Tcp);

        newsock.Bind(ipep);

        newsock.Listen(10);
        Console.WriteLine("Dang cho Client ket noi den...");
        Socket client = newsock.Accept();
        IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
        Console.WriteLine("Da ket noi voi client {0} tai port {1}",

                        newclient.Address, newclient.Port);
        string welcome = "Hello client";

        data = Encoding.ASCII.GetBytes(welcome);
        int sent = SendVarData(client, data);
        for (int i = 0; i < 5; i++)
        {
            data = ReceiveVarData(client);
            Console.WriteLine(Encoding.ASCII.GetString(data));

        }

        Console.WriteLine("Dong ket noi voi Client {0}", newclient.Address);

        client.Close();

        newsock.Close();

    }

}

Chương trình Client gởi và nhận thông điệp cùng với kích thước

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;
class VarTcpClient
{

    private static int SendVarData(Socket s, byte[] data)
    {

        int total = 0;
        int size = data.Length;

        int dataleft = size; int sent;

        byte[] datasize = new byte[4];

        datasize = BitConverter.GetBytes(size);

        sent = s.Send(datasize);
        while (total < size)
        {

            sent = s.Send(data, total, dataleft, SocketFlags.None);

            total += sent;

            dataleft -= sent;

        }
        return total;

    }

    private static byte[] ReceiveVarData(Socket s)
    {
        int total = 0;
        int recv;
        byte[] datasize = new byte[4];

        recv = s.Receive(datasize, 0, 4, 0);
        int size = BitConverter.ToInt32(datasize, 0);
        int dataleft = size;
        byte[] data = new byte[size];
        while (total < size)
        {

            recv = s.Receive(data, total, dataleft, 0);
            if (recv == 0)
            {

                data = Encoding.ASCII.GetBytes("exit ");
                break;

            }

            total += recv;

            dataleft -= recv;

        }
        return data;

    }

    public static void Main()
    {
        byte[] data = new byte[1024];
        int sent;

        IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);



        Socket server = new Socket(AddressFamily.InterNetwork,
        SocketType.Stream, ProtocolType.Tcp);

        try
        {

            server.Connect(ipep);

        }

        catch (SocketException e)
        {

            Console.WriteLine("Khong the ket noi voi server");

            Console.WriteLine(e.ToString());

            return;
        }

        data = ReceiveVarData(server); string stringData = Encoding.ASCII.GetString(data);
        Console.WriteLine(stringData);

        string message1 = "Day la thong diep dau tien";

        string message2 = "Thong diep ngan";

        string message3 = "Thong diep nay dai hon cac thong diep khac";

        string message4 = "a";

        string message5 = "Thong diep cuoi cung";

        sent = SendVarData(server, Encoding.ASCII.GetBytes(message1));

        sent = SendVarData(server, Encoding.ASCII.GetBytes(message2));

        sent = SendVarData(server, Encoding.ASCII.GetBytes(message3));

        sent = SendVarData(server, Encoding.ASCII.GetBytes(message4)); sent = SendVarData(server, Encoding.ASCII.GetBytes(message5));
        Console.WriteLine("Dang ngat ket noi voi server...");

        server.Shutdown(SocketShutdown.Both);

        server.Close();

    }

}  

Trên đây là cách thứ hai để giải quyết vấn đề bộ đệm dữ liệu trong ứng dụng client – server. Một cách khác để gởi các thông điệp với kích thước khác nhau là sử dụng các hệ thống đánh dấu sẽ được giới thiệu ở bài viết tiếp theo! Chúc các bạn thành công!

LEAVE A REPLY

Please enter your comment!
Please enter your name here