1.4 Socket API
Socket API là bộ thư viện lập trình ứng dụng, được sử dụng
nhiều nhất để viết các ứng dụng trên mạng hiện nay.
Giao tiếp giữa ứng dụng và mạng (network-application)
Quan sát hình vẽ sau:
Hình vẽ trên thể hiện một hệ thống gồm: hai host được kết
nối với nhau qua hệ thống mạng của ISP, trên các host có cài đặt các ứng dụng
mạng (app), các ứng dụng mạng sử dụng thành phần giao tiếp (interface) để trao
đổi thông tin với hệ thống mạng.
Thành phần giao tiếp sẽ định nghĩa và cung cấp cách thức để app
có thể trao đổi thông tin với hệ thống mạng, để cuối cùng, app trên máy tính
này có thể “nói chuyện” được với app trên máy tính khác.
Nhờ vào thành phần giao tiếp, ứng dụng chỉ làm việc trực
tiếp với host (hay local host), mà không cần quan tâm tới tổ chức thực sự ở bên
dưới của hệ thống mạng (cơ chế này giúp che dấu sự phức tạp của hệ thống).
Ngược lại, hệ thống mạng cũng không quan tâm tới ứng dụng gì đang chạy ở host
mà chỉ quan tâm tới việc chuyển các gói tin đi tới đúng đích cần tới.
Ứng dụng client-server
Hình vẽ trên minh họa ứng dụng client-server.
Thông qua hệ thống mạng, chương trình client (ứng dụng trên
host client) sẽ gửi yêu cầu (request) tới chương trình server (ứng dụng trên
host server). Khi nhận được yêu cầu, chương trình server sẽ đáp ứng lại
(reply). Đây là một nguyên lý vận hành cơ bản của rất nhiều các ứng dụng trên
mạng. Ví dụ:
- Dịch vụ FTP (send name, get file): client gửi tên tập tin cần lấy, server sẽ gửi về nội dung của tập tin.
- Duyệt web (send URL, get page): client gửi địa chỉ trang web, server sẽ gửi về nội dung của trang web.
- Ứng dụng ping (send message, get message): client gửi gói tin tới server, server sẽ gửi lại gói tin phản hồi.
Socket API cung cấp môi trường lập trình, giúp người lập
trình thuận lợi hơn trong việc xây dựng các ứng dụng mạng. Tất cả các hệ điều
hành và ngôn ngữ lập trình quan trọng hiện nay đều có hỗ trợ socket API. Khởi
nguồn, socket API được nhúng vào hệ điều hành Berkeley (một phiên bản của UNIX) năm 1983.
Socket API cung cấp hai loại dịch vụ mạng: streams và
datagrams
- Streams: truyền có đảm bảo các luồng byte dữ liệu (reliably).
- Datagrams: truyền không đảm bảo các gói dữ liệu rời rạc.
Quan sát ví dụ về socket API.
Ở hình trên, ứng dụng mạng app được cài đặt trên máy host, app sử dụng cấu trúc dữ liệu socket để gắn kết app với hệ thống mạng. Mỗi socket sử dụng một số để phân biệt, gọi là
port number, đây cũng là một dạng địa chỉ. Socket bên trái có port number là 2
và bên phải là 2. Nhờ vào địa chỉ này, cho phép chạy nhiều ứng dụng cùng lúc
trên một host.
Bảng sau cung cấp một số lời gọi API quan trọng của socket.
Tên
|
Ý nghĩa
|
SOCKET
|
Tạo một socket mới.
|
BIND
|
Gắn kết địa chỉ cục bộ của host với socket.
|
LISTEN
|
Chuẩn bị để chấp nhận yêu cầu kết nối
|
ACCEPT
|
Sẵn sàng chấp nhận kết nối.
|
CONNECT
|
Chủ động thiết lập một kết nối.
|
SEND
|
Gửi byte dữ liệu tới ứng dụng khác trên mạng thông qua kết
nối.
|
RECEIVE
|
Nhận byte dữ liệu từ ứng dụng khác trên mạng thông qua kết
nối.
|
CLOSE
|
Đóng kết nối.
|
Quá trình sử dụng socket được minh họa trong hình sau:
Hình trên minh họa quá trình trao đổi thông tin giữa hai máy
tính trên mạng (client, và server) theo thời gian. Chiều mũi tên ngang thể hiện
hướng truyền của dữ liệu, nét đứt thể hiện thông tin điều khiển, nét liền là
truyền dữ liệu thực sự.
Đầu tiên, cần tạo một kết nối giữa client và server
(connect), sau đó client có thể gửi yêu cầu tới server (request), khi nhận được
yêu cầu từ client, server sẽ đáp ứng lại yêu cầu của client (reply), cuối cùng
sau khi hoàn tất việc truyền dữ liệu, hai bên sẽ đóng kết nối (disconnect).
Số thứ tự (từ 1 đến 10) thể hiện thứ tự thực hiện các lời
gọi hàm.
- Lời gọi hàm đầu tiên được thực hiện ở cả client và server là socket, để thiết lập một socket(1) mới cho quá trình giao tiếp.
- Bind(2): giúp đảm bảo khi client kết nối tới server, client sẽ kết nối tới một cổng cụ thể trên server cụ thể. Đây là quá trình thiết lập địa chỉ cho giao tiếp tại đầu cuối.
- Sau đó là listen(3) và accept(4), giúp socket sẵn sàng chấp nhận yêu cầu kết nối từ phía client (giống như ngồi sẵn bên điện thoại cố định để chờ cuộc gọi tới).
- Phía client gửi yêu cầu kết nối tới server, connect(5). (bấm số để thực hiện một cuộc gọi điện thoại)
- Phía server tiếp nhận yêu cầu kết nối, recv(6) (nhấc máy điện thoại lên nghe, sẵn sàng nhận thông tin)
- Khi kết nối đã được thiết lập, quá trình gửi yêu cầu được thực hiện từ phía client, send(7) request.
- Server đáp ứng lại yêu cầu của phía client, send(9) reply.
- Quá trình nhận kết quả được thực hiện tại phía client, recv(8).
- Sau khi hoàn tất quá trình giao tiếp, hai bên sẽ đóng kết nối, close(10).
Chú ý: bước 4 là accept, trong khi connect lại là bước 5,
nghĩa là chấp nhận kết nối trước khi có yêu cầu kết nối? Thực tế, accept là một
khối lệnh, accept thông báo cho hệ thống mạng ở vào trạng thái đợi và chấp nhận
một kết nối (giống như thông báo cho một người tới ngồi gần điện thoại cố định
để chờ có cuộc gọi tới).
Đoạn mã lập trình phía client
socket() //tạo socket
getaddrinfo() //tên server, cổng kết nối
//www.example.com:80
//getaddrinfo
cũng thực hiện việc chuyển đổi địa chỉ dạng
www.example.com sang địa chỉ IP.
connect() //khối lệnh kết nối tới server
…
send() //gửi yêu cầu
recv() //khối lệnh đợi trả lời từ phía server
… //thực
hiện các thao tác trên dữ liệu nhận được từ server
close() //đóng kết nối
Đoạn mã lập trình phía server
socket() //tạo socket
getaddrinfo() //thực hiện việc chuyển đổi qua
lại giữa các loại địa chỉ
bind() //gắn kết port với socket
listen() //chuẩn bị để chấp nhận yêu cầu kết nối
------------------//vòng lặp
{accept() //đợi kết nối [khối lệnh]
...
recv() //đợi yêu cầu từ phía client
…
send() //gửi lại dữ liệu theo yêu cầu từ phía client
---------------------//hết lặp
close() //đóng kết nối
Tham khảo:
[1] Andrew S. Tanenbaum, David J. Wetherall, Computer Networks 5th
edition, 2011
[2] David J. Wetherall, Introduction
to Computer Networks, www.coursera.org,
2013
----------------------
2013/7/17