Trong bài học này chúng ta sẽ xem xét vấn đề trung tâm của lập trình mạng: socket. Trong các bài học trước chúng ta đã xem xét chi tiết các vấn đề của ứng dụng mạng. Tất cả các vấn đề đó giúp chúng ta định hình vị trí của ứng dụng mạng trong toàn hệ thống. Để tạo ra ứng dụng mạng chúng ta phải sử dụng đến socket giúp ứng dụng tương tác với dịch vụ mạng của hệ thống.
Đang xem: Winsock là gì, khái niệm socket, winsock, lập trình socket
Lập trình với socket là nền tảng cho việc phát triển tất cả các loại phần mềm có sử dụng dịch vụ truyền thông mạng, cho phép chúng ta sử dụng các dịch vụ truyền thông mạng mà hệ thống cung cấp. Trong phần này chúng ta sẽ xem xét chi tiết khái niệm và vị trí của socket.
Như đã học trong các bài trước, các ứng dụng mạng đều bao gồm các cặp tiến trình và quá trình truyền thông giữa chúng. Bất kỳ thông điệp nào truyền đi từ một tiến trình tới tiến trình còn lại phải đi qua mạng. Dữ liệu từ tiến trình tới dịch vụ truyền thông phải đi qua một đối tượng trung gian gọi là socket.
Góc nhìn truyền thông
Khi nhìn nhận từ khía cạnh truyền thông (đường đi của thông tin), socket có thể được hình dung như là một cánh cửa ngăn cách giữa chương trình ứng dụng (thuộc toàn quyền của người lập trình) và ngăn xếp giao thức mạng (thuộc quyền quản lý của hệ điều hành).
Dữ liệu do chương trình tạo ra đi xuyên qua cánh cửa này để đến thế giới mạng, nơi nó sẽ được truyền tới nơi cần đến. Ở chiều ngược lại, dữ liệu từ mạng có thể đi xuyên qua cánh cửa này để tới được chương trình, nơi nó sẽ được xử lý.
Đường đi của dữ liệu từ ứng dụng qua socket tới mạng
Một khi dữ liệu đã đi xuyên qua cánh cửa này, người lập trình sẽ không kiểm soát được nữa mà hoàn toàn do các giao thức mạng nhào nặn để làm sao có thể truyền đi qua mạng một cách tốt nhất. Người lập trình chỉ có khả năng lựa chọn loại dịch vụ vận chuyển dữ liệu theo nhu cầu. Cụ thể hơn người lập trình chỉ có thể lựa chọn dịch vụ TCP hoặc dịch vụ UDP, đồng thời cung cấp tham số để các dịch vụ này phục vụ việc vận chuyển dữ liệu theo yêu cầu của mình.
Góc nhìn mô hình mạng
Nhìn từ ứng dụng, socket là giao diện giữa ứng dụng và dịch vụ tầng giao vận trên mỗi máy. Trong mô hình mạng TCP/IP, socket có thể xem như giao diện giữa tầng ứng dụng và tầng chuyển vận.
Người phát triển ứng dụng có toàn quyền kiểm soát phía tầng ứng dụng của socket nhưng không thể kiểm soát phía tầng giao vận của socket. Ở phía tầng giao vận, người phát triển ứng dụng chỉ có thể lựa chọn giao thức của tầng này và điều chỉnh một vài tham số (kích thước tối đa của bộ nhớ đệm, kích thước tối đa của các segment dữ liệu).
Quan hệ tiến trình – socket – dịch vụ TCP trên thiết bị đầu cuối
Trong hai cách nhìn nhận trên, socket đóng vai trò điểm đầu và điểm cuối của quá trình truyền thông mạng, cũng như phân tách giữa tiến trình (chương trình ứng dụng) và dịch vụ vận chuyển của mạng.
So sánh một cách hình tượng, mỗi tiến trình có thể so sánh với một ngôi nhà, còn socket chính là cửa của ngôi nhà đó, và môi trường mạng truyền dữ liệu tương tự như một dịch vụ chuyển phát nhanh đặt ở ngay cửa của ngôi nhà.
Góc nhìn lập trình
Đối với người lập trình ứng dụng, socket có thể được hình dung là một giao diện lập trình ứng dụng (API) để gọi tới các chương trình con của hệ điều hành.
Trong các bài trước chúng ta đã nhắc tới giao thức TCP hay giao thức UDP. Về bản chất, TCP hay UDP đều là những chương trình được tích hợp sẵn trong các hệ điều hành hiện đại.
Tương tự như các chương trình hệ thống khác, TCP hay UDP (và cả IP) cũng cung cấp API để người lập trình có thể sử dụng được các chương trình này.
Khi học lập trình socket, chúng ta sẽ nhìn nhận khái niệm socket chủ yếu theo góc nhìn này. Việc học lập trình socket khi đó thực chất là việc học làm việc với các API của hệ thống để gọi các dịch vụ truyền thông.
Socket API đầu tiên được xây dựng bởi đại học Berkeley cho hệ điều hành BSD nên thường được gọi là BSD socket hay Berkeley socket. Sau đó Microsoft tham khảo và tạo ra các socket API dành cho hệ điều hành windows, gọi là windows socket, hay thường gọi tắt là winsock.
Winsock là bộ API tiêu chuẩn để lập trình mạng trong windows. Cũng vì lý do này mà các hàm socket API trên các hệ điều hành hiện nay đều có tên gọi gần giống nhau. Nắm bắt được cách lập trình với socket API trên một nền tảng này có thể dễ dàng tiếp cận với các nền tảng khác.
Phân loại socket
Do có 2 loại dịch vụ hỗ trợ trao đổi dữ liệu qua mạng như đã nói, socket cũng được chia làm 2 loại chủ yếu:
Socket để sử dụng dịch vụ TCP, gọi là TCP socket: Bởi vì TCP cung cấp dịch vụ truyền dữ liệu theo một liên kết ảo giữa hai tiến trình, TCP socket còn được gọi là socket hướng kết nối (connection-oriented socket). Do dữ liệu truyền theo liên kết TCP được hình dung như một chuỗi byte liên tục, loại socket này còn có một tên gọi khác là socket hướng dòng (stream socket).Socket để sử dụng dịch vụ UDP, gọi là UDP socket: Do UDP không tạo liên kết mà truyền dữ liệu theo các gói (datagram) độc lập, UDP socket được còn được gọi là socket phi liên kết (connectionless socket) hay dgram socket.
Đối với người phát triển ứng dụng hệ thống còn một loại socket nữa, gọi là socket thô (raw socket). Loại socket này cho phép gọi thẳng đến chương trình IP mà bỏ qua TCP hoặc UDP.
Xem thêm: Tìm Hiểu Về Tattoo Nghĩa Là Gì ? (Từ Điển Anh Tattoo Là Gì
Bình thường, dữ liệu sau khi đến chương trình IP sẽ được chuyển tiếp lên chương trình TCP hay UDP, sau đó mới được chuyển tới ứng dụng. Khi sử dụng socket thô, ta có thể bỏ qua TCP/UDP mà trực tiếp nhận gói tin “thô” từ IP. Loại socket này giúp chúng ta phát triển một số ứng dụng đặc biệt như ping, trace route.
Lập trình socket
Các hệ điều hành đầu tiên của Microsoft (như MS-DOS và các phiên bản đầu của Microsoft Windows) có cung cấp khả năng kết nối mạng nhưng rất hạn chế, chủ yếu dựa trên NetBIOS. Trên thực tế, tại thời điểm đó, Microsoft không cung cấp hỗ trợ cho ngăn xếp giao thức TCP / IP.
Một số nhóm và nhà cung cấp thương mại (như nhóm PC / IP tại MIT, FTP Software, Sun Microsystems, Ungermann-Bass và Excelan) đã giới thiệu các sản phẩm TCP / IP cho MS-DOS, ở dạng một bộ phận của gói phần cứng / phần mềm . Khi Windows 2.0 được phát hành, một số nhóm khác (như Distinct và NetManage) cũng tham gia cung cấp TCP / IP cho Windows.
Một vấn đề rất lớn gặp phải là mỗi nhà cung cấp lại sử dụng bộ API của riêng mình mà không có một mô hình lập trình tiêu chuẩn thống nhất. Đến năm 1991, Martin Hall của JSB Software (sau này đổi tên thành Stardust Technologies) đề xuất Windows Sockets API và trở thành tiêu chuẩn cho lập trình ứng dụng mạng trong Windows.
Winsock
Windows Sockets API (WSA), sau rút gọn thành Winsock, là mộtđặc tả kỹ thuật xác định cách phần mềm mạng trong Windows truy cập các dịch vụmạng, đặc biệt là TCP / IP. Winsock định nghĩa giao diện chuẩn giữa ứng dụng (vídụ chương trình FTP client hoặc trình duyệt web) và ngăn xếp giao thức TCP / IPbên dưới. Winsock API được đặt trong file winsock.dll (16 bit) hoặc wsock32.dll(32 bit) trong thư mục hệ thống.
Windows Sockets định nghĩa hai giao diện:
API cho các nhà phát triển phần mềm ứng dụng, và SPI cho các nhà phát triển phần mềm hệ thống (để thêm các giao thức mới vào hệ thống). API đảm bảo cho ứng dụng có thể hoạt động với cài đặt của giao thức (protocol implementation) từ bất kỳ nhà cung cấp phần mềm mạng nào.SPI đảm bảo cho một cài đặt của giao thức phù hợp có thể được thêm vào hệ thống Windows, và nếu một ứng dụng tuân thủ API thì có thể sử dụng được giao thức mới. Tuy nhiên, hiện nay SPI rất hiếm được sử dụng do trong tất cả các phiên bản Windows gần đây, Microsoft đã hỗ trợ đầy đủ ngăn xếp giao thức TCP / IP và không có nhiều người quan tâm xây dựng các giao thức khác với TCP / IP.
Code và thiết kế của Windows Socket dựa trên tham khảo BSD Socket và cung cấp chức năng bổ sung để API tuân thủ theo mô hình lập trình Windows. Windows Sockets API bao gồm gần như tất cả các tính năng của BSD Socket API. Do đó, khi nắm được kỹ thuật lập trình với một bộ socket API có thể dễ dàng tiếp cận với các bộ socket API khác.
Ngoài ra, nhiều công cụ phát triển phần mềm ứng dụng hiện đại cũng tạo ra các “vỏ bọc” (wrapper) riêng xung quanh bộ socket API để đơn giản hóa và nâng cao hiệu quả trong phát triển các phần mềm ứng dụng mạng.
Hạn chế của lập trình winsock
Như trên vừa trình bày, winsock là bộ API tiêu chuẩn để lậptrình mạng trong windows. Tuy nhiên, việc lập trình ứng dụng với winsock có nhữngkhó khăn nhất định.
Thứ nhất, các API hệ thống thường rất phức tạp với rất nhiều tham số gây khó khăn cho việc lập trình. Để đảm bảo tính linh hoạt, mỗi API đều chứa rất nhiều tham số, sử dụng nhiều kiểu dữ liệu hỗ trợ, cũng như có rất nhiều loại “magic constant”. Lập trình với socket API cũng không ngoại lệ.
Thư hai, việc gọi đến các API của hệ thống thường chỉ phù hợp khi lập trình với một số ngôn ngữ và công nghệ nhất định. Ví dụ khi sử dụng C/C++/Delphi xây dựng ứng dụng native cho windows sẽ dễ dàng truy cập các API này hơn. Tuy nhiên, sử dụng các ngôn ngữ và công cụ bậc “không cao” như C/C++ làm tăng thời gian phát triển ứng dụng (giảm năng suất).
Các công nghệ phát triển ứng dụng hiện đại thường hạn chế việc truy xuất trực tiếp đến các API của hệ thống. Thay vào đó, các công nghệ này thường tạo ra các “vỏ bọc” (wrapper) để giúp người lập trình gọi đến các API của hệ thống một cách dễ dàng hơn.
Ví dụ, trong công nghệ windows form của .Net framework, thay vì để người dùng trực tiếp gọi tới các API để vẽ ra giao diện đồ họa, .NET tạo ra các wrapper xung quanh các API này, .NET sau đó sẽ giúp người dùng gọi các API tương ứng để vẽ ra giao diện đồ họa.
Lập trình socket trong .NET framework
Đối với socket API, .NET framework cũng tạo ra các lớp wrapper để giúp người lập trình gọi các hàm của TCP hay UDP mà không cần tiếp xúc trực tiếp với socket API. Qua đó giúp người lập trình tiếp tục sử dụng mô hình lập trình mạnh, đơn giản, hiệu quả của .NET framework trong việc lập trình truyền thông.
.NET framework cũng có những hỗ trợ khác (không riêng) cho lập trình mạng, bao gồm: giao diện luồng dữ liệu (stream), trình tự hóa dữ liệu (serialization), biến đổi dữ liệu (data conversion), lập trình bất đồng bộ (asynchronous programming), lập trình đa luồng (multi-threading programming), tạo bộ đệm (caching), bảo mật (socket security, crypto-stream).
Các hỗ trợ này đóng vai trò đặc biệt quan trọng khi xây dựng thành phần server và cài đặt giao thức. Tất cả các vấn đề này sẽ lần lượt được trình bày chi tiết trong các bài học tương ứng của tài liệu.
Trong khuôn khổ bài giảng này, chúng ta sẽ chỉ nghiên cứu cách lập trình socket trên .NET framework với ngôn ngữ C#. Các nguyên tắc cơ bản của lập trình socket là tương tự nhau mặc dù sử dụng các công cụ khác nhau. Nắm bắt được cách lập trình socket trên .NET có thể hoàn toàn dễ dàng tiếp cập lập trình socket, ví dụ, trên Java, hay Python, Rubi, v.v..
Xem thêm: Thất Vọng Là Gì – 10 Câu Nói Hay Về Sự Thất Vọng Khiến Bạn Cô Đơn
Lưu ý rằng đây là một tài liệu chuyên về lập trình mạng với .NET framework, không phải là một tài liệu về lập trình C#. Chúng ta sẽ không đề cập đến các vấn đề cơ bản của lập trình C# ở đây. Để có thể theo dõi các ví dụ của bài giảng, các bạn cần nắm vững ngôn ngữ lập trình C#, kỹ thuật lập trình hướng đối tượng trong C#, cách lập trình với các thư viện của .NET framework, cũng như một số kỹ thuật lập trình .NET nâng cao.