Thực hành: Lập trình socket Tcp cơ bản

    0

    Tương tự như đối với socket Udp, chúng ta cũng bắt đầu tiếp xúc với socket Tcp thông qua thực hiện một bài thực hành. Bài thực hành này cũng có chung yêu cầu với bài thực hành đã thực hiện đối với socket Udp: xây dựng một bộ ứng dụng theo mô hình client/server cho phép biến đổi một chuỗi ký tự người dùng nhập thành dạng chữ in hoa.

    Sơ đồ flowchart của bài toán này như sau:

    Sơ đồ flowchart các bước khi lập trình với Tcp socket
    Sơ đồ flowchart các bước khi lập trình với Tcp socket

    Bước 1. Tạo một Solution trống đặt tên là TcpSocket

    Bước 2. Xây dựng lần lượt hai project thuộc kiểu Console App trong solution trên với tên gọi lần lượt là Server và Client.

    Bước 3. Thiết lập để có thể debug đồng thời cả hai chương trình, trong đó Server sẽ khởi động trước.

    Bước 4. Mở file Program.cs của Client và viết code như sau:

    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    
    namespace Client
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                Console.Title = "Tcp Client";
    
                // yêu cầu người dùng nhập ip của server
                Console.Write("Server IP address: ");
                var serverIpStr = Console.ReadLine();
                // chuyển đổi chuỗi ký tự thành object thuộc kiểu IPAddress
                var serverIp = IPAddress.Parse(serverIpStr);
    
                // yêu cầu người dùng nhập cổng của server
                Console.Write("Server port: ");
                var serverPortStr = Console.ReadLine();
                // chuyển chuỗi ký tự thành biến kiểu int
                var serverPort = int.Parse(serverPortStr);
    
                // đây là "địa chỉ" của tiến trình server trên mạng
                // mỗi endpoint chứa ip của host và port của tiến trình
                var serverEndpoint = new IPEndPoint(serverIp, serverPort);
    
                var size = 1024; // kích thước của bộ đệm
                var receiveBuffer = new byte[size]; // mảng byte làm bộ đệm            
    
                while (true)
                {
                    // yêu cầu người dùng nhập một chuỗi
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.Write("# Text >>> ");
                    Console.ResetColor();
                    var text = Console.ReadLine();
    
                    // khởi tạo object của lớp socket để sử dụng dịch vụ Tcp
                    // lưu ý SocketType của Tcp là Stream 
                    var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                    // tạo kết nối tới Server
                    socket.Connect(serverEndpoint);   
    
                    // biến đổi chuỗi thành mảng byte
                    var sendBuffer = Encoding.ASCII.GetBytes(text);
    
                    // gửi mảng byte trên đến tiến trình server
                    socket.Send(sendBuffer);
                    // không tiếp tục gửi dữ liệu nữa
                    socket.Shutdown(SocketShutdown.Send);
    
                    // nhận mảng byte từ dịch vụ Tcp và lưu vào bộ đệm                    
                    var length = socket.Receive(receiveBuffer);
    
                    // chuyển đổi mảng byte về chuỗi
                    var result = Encoding.ASCII.GetString(receiveBuffer, 0, length);
    
                    // xóa bộ đệm (để lần sau sử dụng cho yên tâm)
                    Array.Clear(receiveBuffer, 0, size);
    
                    // không tiếp tục nhận dữ liệu nữa
                    socket.Shutdown(SocketShutdown.Receive);
    
                    // đóng socket và giải phóng tài nguyên
                    socket.Close();
    
                    // in kết quả ra màn hình
                    Console.WriteLine($">>> {result}");
    
                }
            }
        }
    }
    

    Bước 5. Mở file Program.cs của Server và viết code như sau:

    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    
    namespace Server
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                Console.Title = "Tcp Server";
    
                // giá trị Any của IPAddress tương ứng với Ip của tất cả các giao diện mạng trên máy
                var localIp = IPAddress.Any;
                // tiến trình server sẽ sử dụng cổng tcp 1308
                var localPort = 1308;
                // biến này sẽ chứa "địa chỉ" của tiến trình server trên mạng
                var localEndPoint = new IPEndPoint(localIp, localPort);
    
                // tcp sử dụng đồng thời hai socket: 
                // một socket để chờ nghe kết nối, một socket để gửi/nhận dữ liệu
                // socket listener này chỉ làm nhiệm vụ chờ kết nối từ Client
                var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // yêu cầu hệ điều hành cho phép chiếm dụng cổng tcp 1308
                // server sẽ nghe trên tất cả các mạng mà máy tính này kết nối tới
                // chỉ cần gói tin tcp đến cổng 1308, tiến trình server sẽ nhận được
                listener.Bind(localEndPoint);
                // bắt đầu lắng nghe chờ các gói tin tcp đến cổng 1308
                listener.Listen(10);
                Console.WriteLine($"Local socket bind to {localEndPoint}. Waiting for request ...");
    
                var size = 1024;
                var receiveBuffer = new byte[size];
    
                while (true)
                {
                    // tcp đòi hỏi một socket thứ hai làm nhiệm vụ gửi/nhận dữ liệu
                    // socket này được tạo ra bởi lệnh Accept
                    var socket = listener.Accept();
                    Console.WriteLine($"Accepted connection from {socket.RemoteEndPoint}");
    
                    // nhận dữ liệu vào buffer
                    var length = socket.Receive(receiveBuffer);
                    // không tiếp tục nhận dữ liệu nữa
                    socket.Shutdown(SocketShutdown.Receive);
                    var text = Encoding.ASCII.GetString(receiveBuffer, 0, length);
                    Console.WriteLine($"Received: {text}");
    
                    // chuyển chuỗi thành dạng in hoa
                    var result = text.ToUpper();
    
                    var sendBuffer = Encoding.ASCII.GetBytes(result);
                    // gửi kết quả lại cho client
                    socket.Send(sendBuffer);
    
                    Console.WriteLine($"Sent: {result}");
    
                    // không tiếp tục gửi dữ liệu nữa
                    socket.Shutdown(SocketShutdown.Send);
    
                    // đóng kết nối và giải phóng tài nguyên
                    Console.WriteLine($"Closing connection from {socket.RemoteEndPoint}rn");
                    socket.Close();
    
                    Array.Clear(receiveBuffer, 0, size);
                }
            }
        }
    }
    

    Chúng ta có thể để ý, code của cả Client và Server đều tái sử dụng phần khung của nội dung thực hành 1 Udp nhưng thay thế phần truyền thông Udp bằng Tcp. So sánh với code của thực hành 1 Udp để thấy được sự khác biệt.

    Bước 6. Dịch và chạy thử hệ thống

    Ảnh chụp màn hình chương trình tcp client/server

    Chương trình Client về hình thức bề ngoài không có gì khác biệt so với chương trình viết ở phần thực hành 1 của Udp. Tuy nhiên, phần truyền thông đã thay đổi hoàn toàn. Trong phần tiếp theo chúng ta sẽ phân tích code của Client và Server để hiểu được cách lập trình với socket Tcp.

    Bình luận

    avatar
      Đăng ký theo dõi  
    Thông báo về