Tôi đã xây dựng bộ phát và bộ thu UDP/protobuf nhỏ. Tôi đã dành buổi sáng cố gắng để theo dõi lý do tại sao giải mã protobuf đã được sản xuất lỗi, chỉ để thấy rằng đó là máy phát (Spoke.hs) đã được gửi dữ liệu không chính xác.Tại sao Haskell/unpack rối tung với byte của tôi?
Mã được sử dụng unpack
để chuyển Lazy.ByteStrings thành Chuỗi mà gói Mạng sẽ gửi. Tôi đã tìm thấy unpack
trong Hoogle. Nó có thể không phải là hàm tôi đang tìm kiếm, nhưng mô tả của nó có vẻ phù hợp: "O (n) Chuyển đổi một ByteString thành một String."
Spoke.hs xuất ra như sau:
[email protected]:~/Dropbox/haskell-workspace/hub/dist/build/spoke$ ./spoke
45
45
["a","8","4a","6f","68","6e","20","44","6f","65","10","d2","9","1a","10","6a","64","6f","65","40","65","78","61","6d","70","6c","65","2e","63","6f","6d","22","c","a","8","35","35","35","2d","34","33","32","31","10","1"]
Trong khi Wireshark cho tôi thấy rằng các dữ liệu trong gói là:
0a:08:4a:6f:68:6e:20:44:6f:65:10:c3:92:09:1a:10:6a:64:6f:65:40:65:78:61:6d:70:6c:65:2e:63:6f:6d:22:0c:0a:08:35:35:35:2d:34:33:32:31:10
Chiều dài (45) là như nhau từ Spoke.hs và Wireshark.
Wireshark thiếu byte cuối cùng (giá trị Ox01) và luồng giá trị trung tâm khác nhau (và lớn hơn một byte trong Wireshark).
"65","10","d2","9"
trong Spoke.hs vs 65:10:c3:92:09
trong Wireshark.
Vì 0x10 là DLE, tôi nghĩ rằng có thể có một số lần thoát đang diễn ra, nhưng tôi không biết tại sao.
Tôi có nhiều năm tin tưởng vào Wireshark và chỉ có vài chục giờ trải nghiệm Haskell, vì vậy tôi đã giả định rằng đó là mã có lỗi.
Bất kỳ đề xuất nào được đánh giá cao.
-- Spoke.hs:
module Main where
import Data.Bits
import Network.Socket -- hiding (send, sendTo, recv, recvFrom)
-- import Network.Socket.ByteString
import Network.BSD
import Data.List
import qualified Data.ByteString.Lazy.Char8 as B
import Text.ProtocolBuffers.Header (defaultValue, uFromString)
import Text.ProtocolBuffers.WireMessage (messageGet, messagePut)
import Data.Char (ord, intToDigit)
import Numeric
import Data.Sequence ((><), fromList)
import AddressBookProtos.AddressBook
import AddressBookProtos.Person
import AddressBookProtos.Person.PhoneNumber
import AddressBookProtos.Person.PhoneType
data UDPHandle =
UDPHandle {udpSocket :: Socket,
udpAddress :: SockAddr}
opensocket :: HostName --^Remote hostname, or localhost
-> String --^Port number or name
-> IO UDPHandle --^Handle to use for logging
opensocket hostname port =
do -- Look up the hostname and port. Either raises an exception
-- or returns a nonempty list. First element in that list
-- is supposed to be the best option.
addrinfos <- getAddrInfo Nothing (Just hostname) (Just port)
let serveraddr = head addrinfos
-- Establish a socket for communication
sock <- socket (addrFamily serveraddr) Datagram defaultProtocol
-- Save off the socket, and server address in a handle
return $ UDPHandle sock (addrAddress serveraddr)
john = Person {
AddressBookProtos.Person.id = 1234,
name = uFromString "John Doe",
email = Just $ uFromString "[email protected]",
phone = fromList [
PhoneNumber {
number = uFromString "555-4321",
type' = Just HOME
}
]
}
johnStr = B.unpack (messagePut john)
charToHex x = showIntAtBase 16 intToDigit (ord x) ""
main::IO()
main =
do udpHandle <- opensocket "localhost" "4567"
sent <- sendTo (udpSocket udpHandle) johnStr (udpAddress udpHandle)
putStrLn $ show $ length johnStr
putStrLn $ show sent
putStrLn $ show $ map charToHex johnStr
return()
Tài liệu tôi thấy cho gói ưu tiên liệt kê 'giải nén' khi chuyển đổi một' ByteString' thành '[Word8]', không giống với 'Chuỗi'. Tôi mong đợi một số khác biệt byte giữa 'ByteString' và' String' vì 'String' là dữ liệu Unicode trong khi' ByteString' chỉ là một mảng có hiệu quả của byte, nhưng 'unpack' không thể tạo ra một' Chuỗi' trong địa điểm đầu tiên. –
Bạn có thể sử dụng tính năng ngắt kết nối mạng để tránh chuyển đổi dữ liệu dư thừa không? –
@MatthewWalton: 'unpack' từ' Data.ByteString.Char8' hoặc biến thể lười, xuất 'Chuỗi'. Họ không phải là nhận thức Unicode mặc dù. –