Giữ kết nối để gửi nhận chủ động thì hay nhưng quản lý kết nối thì lại tương đối mệt mỏi, đó là lý do tại sao làm ví dụ về socket có vẻ đơn giản nhưng khi xây dựng một socket server lại là cả một núi việc, hiểu rõ vấn đề này EzyPlatform, hay nói chính xác hơn là EzyFox Server đã đóng gói lại việc quản session (phiên) và các nhà phát triển không cần bận tâm, thậm chí là không cần biết đến sự tồn tại của phiên mà chỉ quan tâm đến người dùng.

Những vấn đề của quản lý phiên

Quản lý phiên kết nối socket.png

Phiên (kết nối) là một khái niệm trừu tượng được dùng để nói về thực thể chứa các thông tin kết nối giữa server và client. Với EzyPlatform và EzyFox Server nó được hiện thực hoá bằng giao diện EzySession, và nó có những vấn đề nhất định:

  1. Kết nối cũng là một khái niệm trừu tượng, giữa client và server không thực sự biết rằng chúng có đang giữ kết nối với nhau không.
  2. Trong môi trường thực tế, hiếm khi client sẽ gửi thông báo ngắt kết nối đến server.
  3. Một phiên cũng chiếm một lượng tài nguyên nhất định và cần được giải phóng khi không được dùng nữa.
  4. Reconnect (kết nối lại) rất khó xử lý chung chung được mà phụ thuộc vào từng phần mềm cụ thể.
  5. Một người dùng có nhiều thiết bị, tuy nhiên có những phần mềm ví dụ như trò chơi chỉ cho phép người dùng một thiết bị tại một thời điểm.

Để giải quyết được những vấn đề này EzyPlatform và EzyFox Server có những thiết kế tương đối phức tạp.

Thiết kế các lớp đại diện cho phiên

Các lớp đại diện cho phiên kết nối sẽ được thiết kế như sau:

Quản lý phiên kết nối socket session class.png

Ở đây chúng ta có 3 lớp:

  1. Đầu tiên là giao diện EzySesson. Nó cung cấp các hàm cơ sở để quản lý thông tin phiên kết nối.
  2. Tiếp theo là lớp trừu tượng EzyAbstractSession. Lớp này chứa các trường và các hàm cài đặt cụ thể.
  3. Cuối cùng là lớp EzySimpleSession. Lớp này cũng không làm gì nhiều, nó chỉ bổ sung thêm hàm để lấy ra thông tin của non-blocking I/O channel.

Một số thông tin có trong lớp EzyAbstractSession bao gồm:

  1. id: Là mã của client, được tăng dần đều để đảo bảo không bao giờ bị trùng.
  2. name: Để nhận diện phiên lúc debug, thông tin này cũng là duy nhất.
  3. clientId: Id từ phía client gửi lên, thông tin này cũng không đáng tin cậy nhưng cũng hỗ trợ việc debug.
  4. sessionKey: Là thông tin khoá mã hoá dữ liệu giữa client và server.
  5. channel: Là thông tin kênh kết nối socket.
  6. extensionRequestQueue: Là hàng đợi chứa các yêu cầu chung nhận từ client.
  7. packetQueue: Là thông tin hàng đợi các gói tin cần phản hồi cho client.
  8. ..

Từng thông tin trong một phiên đều rất quan trọng, và mình sẽ viết các bài chi tiết về chúng nhé.

Thiết kế các lớp quản lý phiên

Các phiên được quản lý bởi EzySessionManager với thiết kế như sau:

Quản lý phiên kết nối socket quan ly session.png
  1. Giao diện EzySessionManager chứa các hàm cơ sở cho việc quản lý phiên.
  2. Lớp EzySimpleSessionManager cài đặt việc quản lý phiên, nó có các công việc tương đối nặng nề, đặc biệt là việc phải chạy định kỳ để kiểm tra toàn bộ các phiên xem có phiên nào đã không còn hợp lệ để loại bỏ.
  3. Lớp EzyNioSessionManagerImpl cũng không làm gì nhiều, nó chỉ định rõ kiểu lớp đại diện cho phiên.
  4. Giao diện EzySessionFactory lớp này chứa các hàm cơ sở cho việc khởi tạo ra một đối tượng đại diện cho phiên và cũng chính là ứng dụng của factory design pattern.
  5. Lớp EzyAbstractSessionFactory cài đặt hàm khởi tạo các thông tin cho phiên nhưng vẫn đề chờ hàm tạo phiên vì nó chưa biết chính xác kiểu lớp của phiên, đây cũng chính là ứng dụng của factory method design pattern.
  6. Lớp EzyNioSessionFactory cài đặt hàm để tạo ra đối tượng phiên.

Khi đã có những thành phần cần thiết bây giờ chúng ta có thể đi giải quyết các vấn đề đã được liệt kê ở trên.

Giải quyết các vấn đề

Chúng ta sẽ lần lượt giải quyết các vấn đề.

Giải quyết vấn đề thông tin kết nối.

Để client và server luôn biết về sự tồn tại của nhau thì EzyPlatform và EzyFox Server duy trì yêu cầu ping/pong giữa client và server, client sẽ là người chủ động gọi ping và server phản hồi về pong. Nếu một phiên quá lâu không nhận được ping từ client thì khi định kỳ thanh tra EzySimpleSessionManager sẽ loại bỏ phiên idle quá lâu.

Giải quyết vấn đề client không gửi ngắt kết nối đến server.

Vẫn là dùng ping/pong sẽ giải quyết được vấn đề này. Server sẽ tự chủ động loại bỏ phiên, giải phóng các tài nguyên của phiên sau một khoảng thời gian. Đối với các phiên không gửi yêu cầu đăng nhập trong một khoảng thời gian cũng sẽ bị EzySimpleSessionManager coi là không hợp lệ và bị loại bỏ.

Giải quyết vấn đề giải phóng tài nguyên

EzyPlatform và EzyFox sẽ xoá bỏ hoàn toàn các thông tin của một phiên chứ không giữ lại, vậy cho nên đối với các dữ liệu quan trọng, nhà phát triển sẽ cần lưu vào cơ sở dữ liệu để tránh mất mát. Như bạn có thể thấy ở trên mỗi phiên lại quản lý dữ liệu ở trong các hàng đợi của riêng mình, nên việc giải phóng tài nguyên cũng rất đơn giản là chỉ cần giải phóng phiên là xong.

Giải quyết vấn đề reconnect

Hồi đầu mới viết EzyFox Server mình cũng đã cố gắng giải quyết triệt để vấn đề kết nối lại theo một cách chung nhất nhưng không thành công do có những vấn đề về bảo mật và nghiệp vụ của mỗi phần mềm lại khác nhau. Vậy nên EzyFox Server giải quyết một phần bằng cách sinh ra khái niệm EzyUser mà mình sẽ giải thích ở bài sau để cho phép thay thế phiên, còn về mặt dữ liệu reconnect thì sẽ có nhiều cách để cách nhà phát triển gửi về cho client được.

Một người dùng có nhiều thiết bị

Mỗi một thiết bị sẽ được đại diện bởi một phiên, vì mỗi phiên có id riêng nên không trùng nhau, vì vậy việc quản lý nhiều phiên cũng tương đối dễ dàng, tuy nhiên cũng thông qua khái niệm EzyUser mà mình sẽ viết trong bài sau, mình sẽ giải thích chi tiết hơn về việc cách giải quyết với nhiều thiết bị kết nối đồng thời và việc chỉ cho phép một thiết bị được kết nối tại một thời điểm nhé.

Tổng kết

Quản lý phiên là một bài toán khó, nó đòi hỏi EzyPlatform phải đưa ra một thiết kế tỉ mỉ vì nếu không có một thiết kế tốt sẽ dẫn đến xử lý không tốt đồng nghĩa với việc sẽ có memory leak và bộ nhớ sẽ bị đầy nhanh chóng. Cũng thông qua việc quản lý phiên này EzyPlatform sẽ giải quyết được những vấn đề học búa trong lập trình socket, đóng gói chúng lại để các nhà phát triển sẽ không cần phải bận tâm về các vấn đề này nữa.