Saturday, October 15, 2016

Bài 25: Tổng quan về web và TCP/IP

Ngày nay, khi mà internet trở nên phổ biến, các thiết bị đều có thể kết nối mạng thì nhu cầu tạo ra các hệ thống kết nối các thiết bị với nhau để phục vụ cho một mục đích nào đó là cần thiết. Lập trình dịch vụ web là công việc phát triển ứng dụng kết nối giữa các thiết bị với nhau qua môi trường web. 

Trước đây, lập trình web chủ yếu là xây dựng các hệ thống trang web phục vụ nhu cầu tìm kiếm thông tin hoặc trao đổi mua bán. Khi các thế hệ điện thoại thông minh ra đời với tính năng kết nối internet có sẵn, các ứng dụng trên điện thoại không còn bó gọn trong nó nữa mà có thể kết nối với các thiết bị khác để cung cấp nhiều tiện ích hơn cho người dùng. Nhờ đó, nhu cầu xây dựng các ứng dụng có khả năng kết nối và các hệ thống máy chủ phục vụ nhu cầu kết nối qua điện thoại trở nên bùng nổ. Trong loạt bài này, tôi sẽ giới thiệu về lập trình web bằng ngôn ngữ Go.

Lập trình web có 2 nhánh là front-end và back-end:
- Front-end để chỉ phần ứng dụng giao diện đồ họa mà người dùng thấy và tương tác trực tiếp. Với ứng dụng web là giao diện trang web được xây dựng bằng ngôn ngữ HTML kết hợp với CSS, javascript để định dạng và tương tác trang web. Với ứng dụng máy tính hay điện thoại là các ứng dụng viết bằng các ngôn ngữ lập trình chạy trên các hệ điều hành trên máy tính hay điện thoại hoặc các ứng dụng đa nền tảng. Người dùng xem và tương tác trên trang web hoặc trên các ứng dụng.
- Back-end để chỉ phần xử lý các yêu cầu từ trình duyệt hoặc ứng dụng. Phần back-end nghe thì có vẻ đơn giản nhưng để xây dựng nó là rất phức tạp nhất là khi phục vụ cho số lượng lớn người dùng cùng lúc. Đây sẽ là phần chủ yếu được đề cập trong loạt bài này. Phần front-end nếu có chỉ mang tính chất minh họa kết quả. 

Trước khi tìm hiểu về lập trình back-end bằng ngôn ngữ Go chúng ta cùng tìm hiểu về hoạt động trao đổi dữ liệu trên môi trường web bởi những kiến thức cơ bản này giúp ích rất nhiều cho chúng ta trong quá trình xây dựng ứng dụng dịch vụ web.

Thường chúng ta truy cập một trang web bằng cách nhập địa chỉ trang web đó trên thanh địa chỉ của trình duyệt, ví dụ golang.org. Sau một khoảng thời gian ngắn, trang web đó hiển thị ra trên màn hình trình duyệt. Thật sự bên dưới là cả một quá trình trao đổi nhiều bước:
- Đầu tiên, trình duyệt cần xác định server, nơi chứa trang web golang.org nằm ở đâu để gửi yêu cầu. Thực ra các thiết bị tham gia môi trường mạng cũng được đánh địa chỉ như địa chỉ nhà vậy. Người ta đặt tên nó là địa chỉ IP. Làm thế nào trình duyệt tìm ra được địa chỉ IP của server golang.org? Nó nhờ đến hệ thống server DNS. Đó là dịch vụ chuyên phân giải tên miền thành địa chỉ IP qua nhiều cấp độ phủ rộng toàn thế giới. Ví dụ IP của golang.org  mà DNS cung cấp là 216.58.203.49.
- Sau khi có địa chỉ IP thì trình duyệt sẽ gửi yêu cầu trực tiếp đến server chứa trang web. Để gửi được yêu cầu đến server, trình duyệt cần thực hiện các bước kết nối qua bộ giao thức TCP/IP. 
- Lúc này server web golang.org sẽ nhận được yêu cầu trong đó mô tả trình duyệt cần gì và nó muốn nhận phản hồi như thế nào, dưới dạng gì. Sau đó server sẽ gọi bộ phận xử lý tương ứng để tạo ra thông tin cần trả về cho trình duyệt dưới dạng mà trình duyệt hỗ trợ. Phần nội dung mô tả yêu cầu và nội dung phản hồi được đóng gói theo giao thức HTTP. 
- Trình duyệt nhận phản hồi và vẽ lại nội dung lên màn hình trình duyệt cho người dùng xem.
- Kết nối bị đóng lại trừ khi có yêu cầu duy trì từ trình duyệt.

Quá trình này được lặp lại cho đến khi toàn bộ trang web được lấy về bởi vì trong dữ liệu trả về ban đầu có chứa các tài nguyên khác (file hình ảnh, âm thanh, css, v.v...) nên trình duyệt yêu cầu server nhiều lần. Các lần sau thì không cần đến bước xác định địa chỉ nữa vì đã biết rồi. Quy trình trao đổi dữ liệu giữa ứng dụng và dịch vụ web cũng diễn ra tương tự.


Bộ giao thức TCP/IP


Qua ví dụ trên chúng ta có thể thấy là web hoạt động dựa trên bộ giao thức TCP/IP. Dữ liệu được được trao đổi thông qua các tầng giao thức của TCP/IP. Mỗi tầng giải quyết một tập các vấn đề liên quan đến việc truyền tải dữ liệu và cung cấp dịch vụ cho các giao thức tầng trên và sử dụng các dịch vụ của các tầng dưới theo mô hình mở 7 tầng OSI. Tuy nhiên bộ giao thức TCP/IP chỉ gồm 4 tầng trong đó quan trọng nhất là giao thức IP ở tầng mạng, giao thức TCP ở tầng giao vận và giao thức HTTP ở tầng ứng dụng. 

Tại tầng ứng dụng bên gửi, dữ liệu cần truyền được cắt thành từng gói dữ liệu nhỏ rồi gắn thêm phần đầu mô tả giao thức tạo thành một gói tin. Đi xuống các tầng, gói tin sẽ to dần do tại mỗi tầng bên dưới sẽ lấy gói tin tầng trên làm phần thân của gói tin tầng đó, gắn thêm phần đầu là mô tả giao thức sử dụng. Bên phía nhận thì quá trình ngược lại, càng lên tầng trên thì gói tin nhỏ dần do phần đầu được tách ra và xử lý khi qua mỗi tầng. Đến tầng ứng dụng thì phần thân gói tin chính là gói dữ liệu cần truyền. 


Giao thức IP

Giao thức IP (tầng internet, tương đương tầng mạng mô hình OSI) đóng vai trò mang gói tin chuyển từ thiết bị này đến đúng thiết bị khác trong môi trường mạng. Các thiết bị này được đánh địa chỉ là một chuỗi số duy nhất trên toàn thế giới. Có 2 loại địa chỉ IP là IPv4 và IPv6. Hiện tại IPv4 vẫn đang phổ biến nhưng dần cạn kiệt. Địa chỉ IPv4 là 1 chuỗi gồm 4 số, mỗi số 1 byte nên địa chỉ IP có dạng 0.0.0.0 đến 255.255.255.255 (khoảng 4 tỉ địa chỉ). Riêng 3 nhóm IP sau được sử dụng làm địa chỉ trong mạng nội bộ, không thể dùng làm địa chỉ IP trong mạng internet được: 10.0.0.0 – 10.255.255.255, 172.16.0.0 – 172.31.255.255, 192.168.0.0 – 192.168.255.255.

Giao thức TCP

Giao thức tầng giao vận làm nhiệm vụ chuyển dữ liệu từ dịch vụ/ứng dụng trên thiết bị này đến đúng dịch vụ/ứng dụng trên thiết bị khác. Cơ sở xác định đúng dịch vụ/ứng dụng là cổng kết nối (port). Kết hợp với địa chỉ IP ở trên, cặp <địa chỉ IP>:<cổng> đảm bảo xác định duy nhất dịch vụ/ứng dụng kết nối mạng trên một thiết bị.

Có 2 loại giao thức giao vận phổ biến trong bộ giao thức TCP/IP là giao thức hướng kết nối TCP (Transmission Control Protocol) và giao thức phi kết nối UDP (User Datagram Protocol):
- Để truyền dữ liệu theo giao thức TCP, ứng dụng máy A yêu cầu kết nối đến ứng dụng máy B. Sau khi ứng dụng máy B chấp nhận kết nối thì 2 bên có thể trao đổi dữ liệu qua lại. Kết nối kết thúc khi một trong 2 bên ngắt kết nối. 
- Với giao thức UDP, các bên không cần thiết lập kết nối trước mà có thể gửi dữ liệu ngay với địa chỉ IP và cổng dịch vụ của máy bên kia được khai báo trong mỗi lần gửi dữ liệu. 

Ưu điểm của TCP là đảm bảo kết nối nên dữ liệu ít bị thất lạc khi trao đổi và đến đúng thứ tự nhưng tốn thời gian mở kết nối và chi phí duy trì kết nối. Ngược lại kết nối UDP có khả năng thất lạc dữ liệu và các gói tin đến không đúng thứ tự nhưng việc trao đổi nhanh, gọn. Thông thường các trao đổi dữ liệu lớn, đòi hỏi cao như dịch vụ web thì sẽ dùng TCP còn các trao đổi đòi hỏi nhanh, dữ liệu trao đổi nhỏ, chấp nhận mất như dịch vụ chat thì dùng UDP.


Giao thức HTTP


HTTP, viết tắt của HyperText Transfer Protocol, là giao thức dùng để mô tả dữ liệu trong môi trường web. Đây là giao thức vận hành theo mô hình yêu cầu (request) - phản hồi (response) hay còn gọi là mô hình khách (client) - chủ (server). Trong đó trình duyệt đóng vai trò client yêu cầu server trả lời. Bản thân server không thể tự liên lạc đến client.

Giao thức HTTP theo mô hình không trạng thái, nghĩa là server không lưu trạng thái client nên dù cùng client kết nối thì server cũng không biết được là từ cùng một nơi. Tuy nhiên vấn đề này được giải quyết bằng cookie, session hoặc token để duy trì trạng thái mà chúng ta sẽ tìm hiểu sau.


Cấu trúc gói dữ liệu giao thức HTTP


- Gói dữ liệu yêu cầu (request) gồm 3 thành phần: dòng yêu cầu (request line), phần đầu (header) và phần thân (body):

 + Dòng yêu cầu gồm phương thức yêu cầu, đường dẫn URL, giao thức và phiên bản của giao thức. Ví dụ: GET http://golang.org/ HTTP/1.1
  * Có nhiều phương thức yêu cầu khác nhau nhưng có 4 phương thức chính là POST, GET, PUT và DELETE. Bốn phương thức này ứng với 4 nhu cầu trong tương tác giữa client và server là tạo mới dữ liệu (POST), lấy dữ liệu (GET), cập nhật dữ liệu (PUT) và xóa dữ liệu (DELETE). Trong tiếng Anh, 4 nhu cầu này viết tắt là CRUD (Create, Read, Update, Delete). 
  * Giao thức và phiên bản: giao thức là HTTP. Phiên bản có 1.0, 1.1 và 2. Trong đó phổ biến nhất là 1.1.
 + Phần đầu: Các trường khai báo theo cấu trúc <tên>:<giá trị1>, <giá trị 2>, ...<giá trị n><dấu xuống đầu dòng>. Bản thân mỗi giá trị có thể là cặp <tên>:<giá trị>. Giữa phần đầu và phần thân có 1 dòng trống.

  • Host: tên miền và cổng theo định dạng <tên miền>:<cổng>. Nếu là cổng 80 thì có thể bỏ và khai báo chỉ còn lại <tên miền>. Ví dụ: Host: golang.org:80 hoặc golang.org.
  • Connection: mô tả loại kết nối. Ở HTTP/1.0, giá trị mặc định là "close", nghĩa là server sẽ đóng kết nối sau khi gửi phản hồi về cho client. Nên nếu muốn server không đóng kết nối sau khi hoàn tất phản hồi, chúng ta cần khai báo giá trị là "keep-alive". Ngược lại ở HTTP/1.1, giá trị mặc định là "keep-alive", muốn đóng kết nối sau khi gửi phản hồi, ta phải khai báo là "close". Ví dụ: Connection: keep-alive
  • User-agent: chứa thông tin về ứng dụng trên client gửi yêu cầu, có thể là trình duyệt hoặc ứng dụng. Chúng ta có thể dùng thông tin này để phân loại thiết bị cũng như nắm phiên bản ứng dụng đang sử dụng khi cần. Ví dụ: User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) 
  • Accept: mô tả loại nội dung nó hỗ trợ. Cấu trúc: <loại>/<loại con> [q=<giá trị chấp nhận từ 0 đến 1>]. Ví dụ: Accept: text/plain
  • Accept-Charset: mô tả loại bảng mã ký tự hỗ trợ. Cấu trúc: <mã> [q=<giá trị chấp nhận từ 0 đến 1>]. Ví dụ: Accept-Charset: utf-8
  • Accept-Encoding: mô tả loại nén (mã hóa) dữ liệu hỗ trợ. Ví dụ: Accept-Encoding: gzip, deflate
  • Accept-Language: mô tả loại ngôn ngữ hỗ trợ. Chúng ta có thể dùng thông tin này để cung cấp đúng nội dung cho máy khách theo ngôn ngữ đã chọn. Ví dụ: Accept-Language: en-US
  • Authorization: chứa thông tin xác thực truy cập. Đây là nơi khai báo thông tin chứng thực khi sử dụng kiểu chứng thực bằng token. Ví dụ: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
  • Cookie: chứa thông tin định danh client. Trường này sử dụng khi sử dụng chứng thực người dùng theo session/cookie. Ví dụ: Cookie: $Version=1; Skin=new;
  • Content-Length: chứa kích thước phần thân, tính theo byte. Ví dụ 300
  • Content-Type: loại nội dung của phần thân, kiểu MIME. Ví dụ: Content-Type: application/x-www-form-urlencoded
  • Cache-Control: mô tả loại cache. Cache là khái niệm lưu trữ những thông tin hay dùng đến để khi cần thì có dùng ngay. Ví dụ: Cache-Control: no-cache
  • Date: ngày giờ theo múi giờ 0. Thông tin này cần trong trường hợp thời gian ảnh hưởng đến việc hiển thị dữ liệu. Ví dụ nếu thời gian trên máy khách sai thì dữ liệu trả về có thể hiển thị không như mong muốn. Ví dụ: Date: Thu, 23 Sep 2016 08:12:31 GMT
  • Và các trường ít phổ biến khác.

 + Phần thân thường là dữ liệu gửi kèm hoặc có thể bỏ trống.

Ví dụ gói dữ liệu yêu cầu khi truy cập golang.org trên trình duyệt chrome: 
GET http://golang.org/ HTTP/1.1
Host: golang.org
Connection: close
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/53.0.2785.116
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
Cache-Control: no-cache
Accept-Language: de,en;q=0.7,en-us;q=0.3

- Gói dữ liệu phản hồi (response) cũng gồm 3 thành phần: dòng trạng thái, phần đầu và phần thân:
 + Dòng trạng thái gồm giao thức và phiên bản, mã trạng thái và nội dung trạng thái phản hồi. Mã trạng thái có 5 nhóm: 1xx: thông tin, 2xx: thành công, 3xx: chuyển hướng, 4xx: lỗi phía client, 5xx: lỗi phía server. Ví dụ: HTTP/1.1 200 OK
 + Phần đầu: cấu trúc tương tự như phần đầu gói dữ liệu yêu cầu, gồm các trường:

  • Server: thông tin ứng dụng máy chủ và phiên bản. Ví dụ: Server: Apache/2.4.1 (Unix)
  • Date: ngày giờ theo múi giờ GMT-0. Giờ máy chủ luôn phải chuẩn nên đây là cơ sở để máy khách cập nhật lại nếu cần.
  • Location: khai báo URL mới trong trường hợp cần chuyển hướng hoặc khi tạo một đối tượng mới.
  • Set-Cookie: khai báo cookie đã thiết lập cho máy khách. Ví dụ: Set-Cookie: UserID=hungpham; Max-Age=3600; Version=1
  • Transfer-Encoding: mô tả loại mã hóa dữ liệu gửi cho máy khách: chunked, compress, deflate, gzip, identity. Ví dụ: Transfer-Encoding: chunked
  • Content-Type, Content-Length, Connection
  • Và các trường khác.

 + Phần thân: nội dung cần trả về cho client, có thể là nội dung file HTML cho trình duyệt hiển thị trang web hoặc các loại file khác.
Ví dụ nội dung máy chủ golang.org trả về:
HTTP/1.1 200 OK
Server: nginx/1.0.8
Date:Date: Tue, 30 Oct 2012 04:14:25 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 90
// Dòng trống
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content= "text/html; charset=utf-8">... // phần thân

Địa chỉ URL


URL, viết tắt của Uniform Resource Locator là thông tin mô tả xác định tài nguyên trên internet. Tên miền golang.org là URL ở mức đơn giản. Thực tế URL đầy đủ các thành phần sẽ bao gồm: 
<giao thức>://<địa chỉ máy chủ>:<cổng>/<đường dẫn>/?<chuỗi truy vấn>#<dấu trang>
- Giao thức: http, https, ftp, v.v...
- Địa chỉ máy chủ: Tên miền hoặc địa chỉ IP
- Cổng: Mặc định web dùng cổng 80 (thường được hiểu ngầm và loại bỏ khi khai báo) nhưng nếu dùng cổng khác thì cần phải khai báo rõ ràng. Thường chúng ta phải chọn cổng lớn hơn 1024 và không chọn các cổng đã dùng cho các dịch vụ phổ biến.
- Đường dẫn: đường dẫn đến các tài nguyên trên máy chủ, mỗi cấp ngăn nhau bởi dấu /
- Chuỗi truy vấn: dữ liệu gửi đến máy chủ theo dạng: 
<tham số 1>=<giá trị 1>&<tham số 2>=<giá trị 2>&...&<tham số n>=<giá trị n>
- Dấu trang: Vị trí trong trang web được đánh dấu để nhảy nhanh đến.
Ví dụ sau là URL đến phần tổng quan của package net/http trên trang web golang.org: https://golang.org/pkg/net/http/#pkg-overview

Hy vọng qua bài này, các bạn nắm được những kiến thức tổng quan về hoạt động web và bộ giao thức TCP/IP. Trong bài tới chúng ta sẽ tìm hiểu về cách xây dựng một web server bằng ngôn ngữ Go.


Tóm tắt:
- Web hoạt động theo mô hình TCP/IP với bộ ba giao thức: IP (tầng mạng), TCP (phần giao vận) và HTTP (tầng ứng dụng). IP đảm bảo gói tin đến đúng thiết bị nhận. TCP đảm bảo gói tin đến đúng dịch vụ nhận. HTTP đảm bảo dữ liệu truyền được hiểu chính xác giữa các loại thiết bị.
- IP là địa chỉ xác định thiết bị trong môi trường mạng. IPv4 gồm chuỗi 4 số 1 byte chạy từ 0.0.0.0 đến 255.255.255.255
- Giao thức TCP mở kết nối trước khi truyền dữ liệu nên đảm bảo thứ tự và tính toàn vẹn gói tin. UDP gửi gói tin mà không cần mở kết nối nên tỉ lệ thất lạc cao nhưng bù lại nhanh hơn TCP.
- Phần đầu gói tin HTTP chứa nhiều trường quan trọng ảnh hưởng đến việc xử lý dữ liệu nên cần đặc biệt chú ý.

No comments:

Post a Comment