Thực hành lập trình với giao thức mạng

    0

    Yêu cầu với chương trình

    Viết một ứng dụng dòng lệnh đơn giản (console application) theo mô hình client/server đáp ứng các yêu cầu:

    • Client cho phép người dùng nhập một chuỗi ký tự từ bàn phím và gửi chuỗi ký tự cho server;
    • Server nhận chuỗi ký tự, chuyển đổi tất cả ký tự thành dạng in hoa và gửi chuỗi kết quả lại cho client;
    • Client nhận kết quả và hiển thị lại cho người dùng.

    Chuẩn bị solution và project

    Bước 1. Tạo một solution trống trong Visual Studio đặt tên là UdpClientServer

    Bước 2. Tạo hai project kiểu Console Application, một project đặt tên là Client, project kia đặt tên là Server. Sau khi thực hiện, cửa sổ Solution Explorer hiển thị như sau:

    Bước 3. Thiết lập để đồng thời chạy debug cả hai chương trình.

    Do là một ứng dụng mạng với hai thành phần hoạt động song song, mỗi lần debug chúng ta thường phải chạy cả client và server. Thiết lập dưới đây giúp chúng ta nhanh chóng chạy cả hệ thống để debug bằng cách tự động chạy server trước, ngay sau đó sẽ tự chạy client.

    Click phải vào tên solution và chọn Properties. Trong cửa sổ mở ra lựa chọn “Startup Project” (1) => chọn “Multiple startup projects” (2) => chọn giá trị “Start” trong cột “Action” cho từng project (3) => chọn và đẩy project Server lên trên (4). Ấn OK để hoàn tất.

    Nếu ấn F5 (chạy debug), chương trình Server sẽ chạy trước, ngay sau đó chương trình Client sẽ chạy theo.

    Viết code cho Client

    Bước 4. Mở file Program.cs trong project Client và viết code như sau. Chú ý đọc kỹ các comment để nắm được ý nghĩa của từng lệnh.

    using System;
    using System.Net; // để sử dụng lớp IPAddress, IPEndPoint
    using System.Net.Sockets; // để sử dụng lớp Socket
    using System.Text; // để sử dụng lớp Encoding
    Console.Title = "Udp 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ụ Udp
        // lưu ý SocketType của Udp là Dgram (datagram)
        var socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
        // 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.SendTo(sendBuffer, serverEndpoint);
        // endpoint này chỉ dùng khi nhận dữ liệu
        EndPoint dummyEndpoint = new IPEndPoint(IPAddress.Any, 0);
        // nhận mảng byte từ dịch vụ Udp và lưu vào bộ đệm
        // biến dummyEndpoint có nhiệm vụ lưu lại địa chỉ của tiến trình nguồn
        // tuy nhiên, ở đây chúng ta đã biết tiến trình nguồn là Server
        // do đó dummyEndpoint không có giá trị sử dụng
        var length = socket.ReceiveFrom(receiveBuffer, ref dummyEndpoint);
        // 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);
        // đó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}");
    }

    Viết code cho Server

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

    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    Console.Title = "Udp 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 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);
    // yêu cầu hệ điều hành cho phép chiếm dụng cổng 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 udp đến cổng 1308, tiến trình server sẽ nhận được
    // một overload khác của hàm tạo Socket
    // InterNetwork là họ địa chỉ dành cho IPv4
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    socket.Bind(localEndPoint);
    Console.WriteLine($"Local socket bind to {localEndPoint}. Waiting for request ...");
    var size = 1024;
    var receiveBuffer = new byte[size];
    while (true) {
        // biến này về sau sẽ chứa địa chỉ của tiến trình client nào gửi gói tin tới
        EndPoint remoteEndpoint = new IPEndPoint(IPAddress.Any, 0);
        // khi nhận được gói tin nào sẽ lưu lại địa chỉ của tiến trình client
        var length = socket.ReceiveFrom(receiveBuffer, ref remoteEndpoint);
        var text = Encoding.ASCII.GetString(receiveBuffer, 0, length);
        Console.WriteLine($"Received from {remoteEndpoint}: {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.SendTo(sendBuffer, remoteEndpoint);
        Array.Clear(receiveBuffer, 0, size);
    }

    Dịch và chạy thử

    Bước 6. Chạy thử ứng dụng (F5) Chương trình server sẽ chạy trước, chương trình client sẽ chạy ngay sau server.

    Server sẽ viết ra thông báo về IP và giá trị cổng mà nó đang chờ request. Client sẽ yêu cầu người dùng nhập địa chỉ IP và số cổng của server. Vì server đang nghe tất cả các giao diện mạng và client đang chạy trên cùng máy vật lý với server, client có thể sử dụng địa chỉ loopback (127.0.0.1) và số cổng 1308.

    Ảnh chụp màn hình khi ứng dụng hoạt động

    Ảnh chụp màn hình khi ứng dụng hoạt động

    Nhập bất kỳ chuỗi ký tự nào vào dấu nhắc lệnh của client. Ngay sau đó sẽ nhận được kết quả là chuỗi ký tự đã chuyển thành chữ hoa. Để ý rằng mỗi lần Client phát đi một chuỗi ký tự, giá trị cổng của nó lại thay đổi (ở trên là 63004, 63005, 63006).

    Lưu ý, khi Server hoạt động lần điều tiên, hệ điều hành sẽ yêu cầu người dùng cấp phép cho Server chiếm dụng cổng 1308. Nếu chạy Server từ một tài khoản bị hạn chế quyền sẽ không thực hiện được yêu cầu này, và Server sẽ bị đóng lại ngay sau đó. Từ lần hoạt động sau sẽ không cần trả lời cấp phép nữa.

    Theo dõi
    Thông báo của
    guest

    0 Thảo luận
    Phản hồi nội tuyến
    Xem tất cả bình luận