2012-06-15 29 views
6

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() 
+1

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. –

+5

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? –

+0

@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ù. –

Trả lời

3

Các tài liệu tôi thấy cho các danh sách gói bytestring giải nén như chuyển đổi một ByteString-[Word8], mà không phải là giống như một String. Tôi mong đợi một số khác biệt byte giữa ByteStringString vì dữ liệu Unicode là ByteString chỉ là một mảng hiệu quả của byte, nhưng unpack không thể tạo ra một String ngay từ đầu.

Vì vậy, bạn có thể bị lỗi khi chuyển đổi Unicode tại đây, hoặc ít nhất một cái gì đó giải thích nó như Unicode khi dữ liệu cơ bản thực sự không và hiếm khi kết thúc tốt.

+0

Không, nó cũng nói 'giải nén :: ByteString -> [Char]' (Tôi nghĩ String là một bí danh cho [Char]). http://hackage.haskell.org/packages/archive/bytestring/latest/doc/html/Data-ByteString-Char8.html#v:unpack – fadedbee

+1

Đó là 'Data.ByteString.Char8' - Tôi đang tìm trong 'Dữ liệu. ByteString.Lazy'. Tuy nhiên, như John L đã chỉ ra trong các ý kiến ​​về câu hỏi mà vẫn không nhận thức được Unicode. –

+2

Đó chắc chắn là chuyển đổi Unicode: ví dụ: [điểm mã D8 là C3 98 trong UTF-8] (http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=d8&mode=hex). Đó là lý do tại sao bất kỳ giá trị nào dưới 0x7F đều không bị ảnh hưởng. – rxg

1

Tôi nghĩ bạn sẽ muốn toStringfromString từ utf8-string thay vì unpackpack. This blog post rất hữu ích cho tôi.

Các vấn đề liên quan