Lưu ý: Đây là một số giải thích và mã giả về cách triển khai một máy chủ rất tầm thường có thể xử lý các thông báo WebSocket đến và đi theo định dạng khung cuối cùng. Nó không bao gồm quá trình bắt tay. Hơn nữa, câu trả lời này đã được thực hiện cho mục đích giáo dục; nó không phải là một triển khai đầy đủ tính năng.
Đặc điểm kỹ thuật (RFC 6455)
Gửi tin nhắn
(Nói cách khác, máy chủ → trình duyệt)
Các khung bạn đang gửi cần được định dạng theo định dạng khung WebSocket. Để gửi tin nhắn, định dạng này như sau:
- một byte chứa loại dữ liệu (và một số thông tin bổ sung nằm ngoài phạm vi của một máy chủ tầm thường)
- một byte chứa độ dài
- hai hoặc tám byte nếu độ dài không vừa với byte thứ hai (byte thứ hai sau đó là mã cho biết có bao nhiêu byte được sử dụng cho độ dài)
- dữ liệu thực tế (thô)
Byte đầu tiên sẽ là 1000 0001
(hoặc 129
) cho một khung văn bản.
Byte thứ hai có bit đầu tiên được đặt thành 0
vì chúng tôi không mã hóa dữ liệu (không bắt buộc phải mã hóa từ máy chủ đến máy khách).
Cần phải xác định độ dài của dữ liệu thô để gửi độ dài byte một cách chính xác:
- nếu
0 <= length <= 125
, bạn không cần thêm byte
- nếu
126 <= length <= 65535
, bạn cần thêm hai byte và byte thứ hai là126
- nếu
length >= 65536
, bạn cần tám byte bổ sung và byte thứ hai là127
Độ dài phải được chia thành các byte riêng biệt, có nghĩa là bạn sẽ cần phải dịch chuyển bit sang phải (với số lượng là tám bit), và sau đó chỉ giữ lại tám bit cuối cùng bằng cách thực hiện AND 1111 1111
(chính là 255
).
Sau (các) byte độ dài là dữ liệu thô.
Điều này dẫn đến mã giả sau:
bytesFormatted[0] = 129
indexStartRawData = -1 // it doesn't matter what value is
// set here - it will be set now:
if bytesRaw.length <= 125
bytesFormatted[1] = bytesRaw.length
indexStartRawData = 2
else if bytesRaw.length >= 126 and bytesRaw.length <= 65535
bytesFormatted[1] = 126
bytesFormatted[2] = ( bytesRaw.length >> 8 ) AND 255
bytesFormatted[3] = ( bytesRaw.length ) AND 255
indexStartRawData = 4
else
bytesFormatted[1] = 127
bytesFormatted[2] = ( bytesRaw.length >> 56 ) AND 255
bytesFormatted[3] = ( bytesRaw.length >> 48 ) AND 255
bytesFormatted[4] = ( bytesRaw.length >> 40 ) AND 255
bytesFormatted[5] = ( bytesRaw.length >> 32 ) AND 255
bytesFormatted[6] = ( bytesRaw.length >> 24 ) AND 255
bytesFormatted[7] = ( bytesRaw.length >> 16 ) AND 255
bytesFormatted[8] = ( bytesRaw.length >> 8 ) AND 255
bytesFormatted[9] = ( bytesRaw.length ) AND 255
indexStartRawData = 10
// put raw data at the correct index
bytesFormatted.put(bytesRaw, indexStartRawData)
// now send bytesFormatted (e.g. write it to the socket stream)
Nhận tin nhắn
(Nói cách khác, trình duyệt → máy chủ)
Các khung bạn thu được có định dạng sau:
- một byte chứa loại dữ liệu
- một byte chứa độ dài
- hai hoặc tám byte bổ sung nếu độ dài không vừa với byte thứ hai
- bốn byte là mặt nạ (= khóa giải mã)
- dữ liệu thực tế
Byte đầu tiên thường không quan trọng - nếu bạn chỉ gửi văn bản, bạn chỉ đang sử dụng kiểu văn bản. Nó sẽ là 1000 0001
(hoặc 129
) trong trường hợp đó.
Byte thứ hai và hai hoặc tám byte bổ sung cần một số phân tích cú pháp, vì bạn cần biết có bao nhiêu byte được sử dụng cho độ dài (bạn cần biết dữ liệu thực bắt đầu từ đâu). Bản thân độ dài thường không cần thiết vì bạn đã có dữ liệu.
Bit đầu tiên của byte thứ hai luôn luôn 1
có nghĩa là dữ liệu bị che (= được mã hóa). Tin nhắn từ máy khách đến máy chủ luôn bị che. Bạn cần loại bỏ bit đầu tiên bằng cách thực hiện secondByte AND 0111 1111
. Có hai trường hợp mà byte kết quả không đại diện cho độ dài vì nó không vừa với byte thứ hai:
- một byte thứ hai của
0111 1110
hoặc 126
, có nghĩa là hai byte sau được sử dụng cho độ dài
- một byte thứ hai của
0111 1111
hoặc 127
, có nghĩa là tám byte sau được sử dụng cho độ dài
Bốn byte mặt nạ được sử dụng để giải mã dữ liệu thực tế đã được gửi. Thuật toán giải mã như sau:
decodedByte = encodedByte XOR masks[encodedByteIndex MOD 4]
đâu encodedByte
là byte gốc trong dữ liệu, encodedByteIndex
là chỉ số (độ lệch) của byte đếm từ byte đầu tiên của dữ liệu thực , có chỉ mục 0
. masks
là một mảng chứa bốn byte mặt nạ.
Điều này dẫn đến mã giả sau để giải mã:
secondByte = bytes[1]
length = secondByte AND 127 // may not be the actual length in the two special cases
indexFirstMask = 2 // if not a special case
if length == 126 // if a special case, change indexFirstMask
indexFirstMask = 4
else if length == 127 // ditto
indexFirstMask = 10
masks = bytes.slice(indexFirstMask, 4) // four bytes starting from indexFirstMask
indexFirstDataByte = indexFirstMask + 4 // four bytes further
decoded = new array
decoded.length = bytes.length - indexFirstDataByte // length of real data
for i = indexFirstDataByte, j = 0; i < bytes.length; i++, j++
decoded[j] = bytes[i] XOR masks[j MOD 4]
// now use "decoded" to interpret the received data
1000 0001
(129) cho một khung văn bản? Spec nói nói:%x1 denotes a text frame
. Vì vậy, nó phải là0000 0001
(0x01
), hoặc?