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:
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
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.
[wpdm_package id=’10372′]