0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Khám Phá Sức Mạnh Của WebSockets: Nâng Cao Trải Nghiệm Giao Tiếp Web Thời Gian Thực

Đăng vào 3 ngày trước

• 4 phút đọc

Giới Thiệu

WebSocket là một giao thức mạnh mẽ cung cấp kênh truyền thông hai chiều (full-duplex) thông qua một kết nối TCP duy nhất. Với khả năng này, cả máy khách và máy chủ có thể gửi và nhận dữ liệu đồng thời mà không cần bất kỳ yêu cầu nào thêm. Đây là một tính năng nổi bật so với giao thức HTTP truyền thống, nơi các kết nối thường chỉ cho phép một chiều giao tiếp tại một thời điểm.

Cách Thức Hoạt Động Của WebSocket

Quá trình thiết lập một kết nối WebSocket bắt đầu với yêu cầu từ máy khách:

  • Client gửi yêu cầu đến máy chủ với trường Upgrade để chuyển đổi từ giao thức HTTP sang WebSocket.
  • Máy chủ nhận yêu cầu và phản hồi với mã HTTP 101 (Switching Protocols) nếu chấp nhận chuyển đổi.

Cả hai quá trình này tương tự như handshake trong TCP để thiết lập một kết nối. Sau khi kết nối được thiết lập, dữ liệu sẽ được trao đổi giữa client và server thông qua các frame được định nghĩa trong tiêu chuẩn RFC 6455.

Khi kết thúc, một trong hai bên sẽ gửi yêu cầu đóng kết nối.

Những Lợi Ích Của WebSocket Trong Phát Triển Ứng Dụng Web Thời Gian Thực

WebSocket giải quyết nhiều vấn đề khó khăn khi phát triển ứng dụng web thời gian thực với các lợi ích nổi bật so với HTTP truyền thống:

  • Header Nhẹ: Giảm thiểu kích thước dữ liệu truyền tải.
  • Kết Nối Một Chiều: Chỉ cần duy trì một kết nối TCP cho mỗi client.
  • Push Data Từ Máy Chủ: Máy chủ có khả năng đẩy dữ liệu mới tới client mà không cần yêu cầu từ phía client.

Lý Thuyết

Keep Alive

Có thể bạn thắc mắc về khả năng giữ kết nối (keep alive) của WebSocket, trong khi giao thức HTTP thường sẽ đóng kết nối sau khi gửi phản hồi. Cơ chế giữ kết nối được định nghĩa bởi trường keep-alive trong RFC 2616 của HTTP/1.0. Cụ thể, nếu không có yêu cầu nào trong khoảng thời gian quy định, một lệnh yêu cầu rỗng sẽ được gửi để kiểm tra xem bên kia còn hoạt động hay không, và nếu không có phản hồi, kết nối sẽ được đóng.

Tổng Quan Về Giao Thức

Phần tổng quan về giao thức đã được trình bày ở phần trước. Để hiểu rõ hơn, bạn có thể tìm hiểu thêm trong tài liệu về tổng quan giao thức WebSocket.

Cài Đặt WebSocket

Để giúp bạn áp dụng lý thuyết vào thực tiễn, trong phần này, tôi sẽ giới thiệu một cách thực hiện một cơ chế đơn giản sử dụng WebSocket bằng thư viện "github.com/gorilla/websocket" trong Golang.

Máy Chủ

Mã nguồn dưới đây thể hiện cách một server mở kết nối WebSocket để truyền file từ client tới server. Đoạn mã này có thể được áp dụng trong nhiều tình huống khác nhau, chẳng hạn như đồng bộ hóa dữ liệu giữa các node trong một mạng lưới blockchain. Hãy theo dõi mã nguồn kèm bình luận để nắm rõ hơn.

go Copy
package main

import (
	"bufio"
	"fmt"
	"log"
	"net/http"
	"os"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

var filename = "000000000.fdb"

func handlerWS(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()

	fmt.Println("Client connected, start sync data from file " + filename)

	for {
		messageType := websocket.TextMessage

		file, err := os.Open(filename)
		if err != nil {
			log.Fatalf("Failed to open file: %s", err)
		}
		defer file.Close()

		reader := bufio.NewReader(file)
		count := 0

		for {
			data, err := reader.ReadBytes('\n')
			if err != nil {
				if err.Error() == "EOF" {
					log.Println("End of file, close connection")
					closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "Server is closing the connection")
					err = conn.WriteMessage(websocket.CloseMessage, closeMsg)
					return
				}
				log.Fatalf("Failed to read file: %s", err)
			}

			err = conn.WriteMessage(messageType, data)
			if err != nil {
				fmt.Println("len: ", len(data))
				log.Println("Error write message:", err)
				return
			}

			fmt.Printf("Successfully sent %d messages\n", count)
			count++
		}
	}
}

func main() {
	http.HandleFunc("/ws", handlerWS)
	fmt.Println("Server started on localhost:8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}

Client

Client chỉ cần thực hiện nhiệm vụ tạo một kết nối tới server, đọc dữ liệu từ kết nối đó và ghi vào file. Dưới đây là mã nguồn cho client:

go Copy
package main

import (
	"fmt"
	"os"
	"github.com/gorilla/websocket"
)

var filename = "000000000.fdb"

func main() {
	conn, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil)
	if err != nil {
		fmt.Println("Error create Dial:", err)
		panic(err)
	}
	defer conn.Close()

	fmt.Println("Client connected, start sync data from file " + filename)
	count := 0

	for {
		_, p, err := conn.ReadMessage()
		if err != nil {
			if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
				fmt.Println("Close connection, err: ", err)
				return
			}
			fmt.Println("read message from connection fail, err: ", err)
			return
		}

		file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			fmt.Printf("Failed to open file: %s", err)
		}
		defer file.Close()

		_, err = file.Write(p)
		if err != nil {
			fmt.Printf("Failed to write file: %s", err)
		}

		fmt.Printf("Successfully received %d messages\n", count)
		count++
	}
}

Repo: GitHub Repository

Tổng Kết

Bài viết này đã giới thiệu về WebSocket với các đoạn mã minh họa dễ hiểu, giúp bạn thực hành và áp dụng vào các ý tưởng thực tiễn, như việc xây dựng ứng dụng chat hay đồng bộ hóa dữ liệu. Mời các bạn tham khảo và phát triển thêm các ứng dụng sáng tạo của riêng mình!

source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào