Quá trình gửi và nhận một tin nhắn khác nhau giữa các tiêu chuẩn TCP và WebSocket. Bên dưới, chúng tôi giải thích quá trình này chi tiết cho cả hai loại kết nối.
Để gửi tin nhắn qua kết nối TCP, hãy thực hiện các bước sau:
Chuyển đổi tin nhắn Protobuf thành một mảng byte (sử dụng mã hóa Protobuf) bằng cách sử dụng SDK Google Protocol Buffer chính thức cho ngôn ngữ lập trình bạn chọn.
Lấy độ dài của mảng được tạo trong bước 1. Tạo một mảng byte mới từ số nguyên này. Đảo ngược mảng byte mới.
Nối mảng byte mới và mảng byte chứa tin nhắn Protobuf gốc.
Gửi mảng nối đến luồng kết nối.
Các ví dụ bên dưới minh họa cách các bước này được thực hiện trong các SDK Open API chính thức.
client=Client(EndPoints.PROTOBUF_LIVE_HOSTifhostType.lower()=="live"elseEndPoints.PROTOBUF_DEMO_HOST,EndPoints.PROTOBUF_PORT,TcpProtocol)request=ProtoOAApplicationAuthReq()# Can be any messagedeferred=client.send(request)
Ví dụ Python
Sử dụng Twisted, ví dụ Python thực hiện gần như các thao tác giống như ví dụ C#. client.send(request) có thể được giải thích như sau.
123
request=ProtoOAApplicationAuthReq()# Can be any messagerequestAsString=request.SerializeToString()# This method is a part of the Google Protobuf SDKrequestAsInt32String=struct.pack("!H",len(requestAsString))# The message is concatenated with the reversed array
Để gửi tin nhắn, SDK Python sử dụng phương thức Protocol.transport.write().
Tất cả các SDK Open API dựa trên thực thi không đồng bộ, có nghĩa là chúng không chờ tin nhắn đến mà thay vào đó phản ứng với các tin nhắn đến động. Kết quả là, việc nhận một tin nhắn thường được thực hiện thông qua các trình xử lý sự kiện
Để đọc một tin nhắn, bạn sẽ phải thực hiện một chuỗi hành động đảo ngược các bước cần thiết để gửi tin nhắn.
Nhận bốn byte đầu tiên của một mảng byte (hãy nhớ, chúng biểu thị độ dài tin nhắn). Đảo ngược bốn byte này và chuyển đổi chúng thành một số nguyên.
Đọc X lượng byte từ một luồng trong đó X là số nguyên bạn đã nhận được trong bước 1.
Sử dụng SDK Google Protobuf để giải tuần tự hóa tin nhắn thành một ProtoMessage hợp lệ.
Sử dụng trường payloadType của đối tượng ProtoMessage để tìm kiểu thực tế của nó. Thông qua SDK Google Protobuf, chuyển đổi ProtoMessage thành một đối tượng của kiểu ProtoOA... cần thiết.
Các đoạn mã bên dưới minh họa cách các SDK Open API chính thức tiếp cận việc đọc tin nhắn.
_tcpClient=newTcpClient{LingerState=newLingerOption(enable:true,10)};await_tcpClient.ConnectAsync(Host,Port).ConfigureAwait(continueOnCapturedContext:false);SslStream_sslStream=newSslStream(_tcpClient.GetStream(),leaveInnerStreamOpen:false);await_sslStream.AuthenticateAsClientAsync(Host).ConfigureAwait(continueOnCapturedContext:false);privateasyncvoidReadTcp(CancellationTokencancellationToken){byte[]dataLength=newbyte[4];byte[]data=null;try{while(!IsDisposed){intnum=0;do{intcount=dataLength.Length-num;intnum2=num;num=num2+await_sslStream.ReadAsync(dataLength,num,count,cancellationToken).ConfigureAwait(continueOnCapturedContext:false);if(num==0){thrownewInvalidOperationException("Remote host closed the connection");}}while(num<dataLength.Length);intlength=GetLength(dataLength);if(length<=0){continue;}data=ArrayPool<byte>.Shared.Rent(length);num=0;do{intcount2=length-num;intnum2=num;num=num2+await_sslStream.ReadAsync(data,num,count2,cancellationToken).ConfigureAwait(continueOnCapturedContext:false);if(num==0){thrownewInvalidOperationException("Remote host closed the connection");}}while(num<length);ProtoMessageprotoMessage=ProtoMessage.Parser.ParseFrom(data,0,length);ArrayPool<byte>.Shared.Return(data);OnNext(protoMessage);}}catch(ExceptioninnerException){if(data!=null){ArrayPool<byte>.Shared.Return(data);}ReceiveExceptionexception=newReceiveException(innerException);OnError(exception);}}privateintGetLength(byte[]lengthBytes){Span<byte>span=lengthBytes.AsSpan();span.Reverse();returnBitConverter.ToInt32(span);}
Ví dụ Python
Trong ví dụ Python, tất cả các thao tác với byte khi nhận tin nhắn được xử lý bởi phương thức dataReceived() như được hiển thị bên dưới.
1 2 3 4 5 6 7 8 910111213141516
defdataReceived(self,recd):""" Convert int prefixed strings into calls to stringReceived. """self.recvd=self.recvd+recdwhilelen(self.recvd)>=self.prefixLengthandnotself.paused:length,=struct.unpack(self.structFormat,self.recvd[:self.prefixLength])iflength>self.MAX_LENGTH:self.lengthLimitExceeded(length)returniflen(self.recvd)<length+self.prefixLength:breakpacket=self.recvd[self.prefixLength:length+self.prefixLength]self.recvd=self.recvd[length+self.prefixLength:]self.stringReceived(packet)
Để gửi tin nhắn qua kết nối WebSocket, hãy thực hiện các hành động sau:
Tuần tự hóa tin nhắn thành bất kỳ định dạng dữ liệu phù hợp nào (ví dụ: một chuỗi).
Thêm tin nhắn đã tuần tự hóa vào hàng đợi gửi của bạn.
Các ví dụ bên dưới minh họa cách các hành động này được thực hiện trong các SDK Open API chính thức.
SDK C# sử dụng lớp WebsocketClient là một phần của gói Websocket.Client. Như được hiển thị bên dưới, phương thức WebsocketClient.Send() hoạt động như sau.
Trước khi đăng ký, SDK .NET phân tích tin nhắn thành một tin nhắn Protobuf. Các đăng ký cần thiết được thêm vào phần thân của callback ConnectWebSocket().