2012-06-15 2 views
6

私は小さなUDP/protobufトランスミッタとレシーバを構築しました。私は午前中にprotobufのデコードでエラーが発生した理由を追跡しようとしましたが、間違ったデータを送信していたトランスミッタ(Spoke.hs)であることがわかりました。なぜ私のバイトでHaskell/Unpackが乱れているのですか?

コードでは、unpackを使用して、ネットワークパッケージが送信する文字列にLazy.ByteStringsを変換します。 Hoogleではunpackが見つかりました。私が探している関数ではないかもしれませんが、その記述は適切です: "O(n)ByteStringを文字列に変換します。"

長さ(45)Spoke.hsから同じである
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 

:Wiresharkのパケット内のデータがあることを私に示しているが

[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"] 

Spoke.hsは、以下の出力を生成しますとWireshark。

Wiresharkには最後のバイト(値0x01)がなく、中心値のストリームは異なります(Wiresharkでは1バイト大きくなります)。

"65","10","d2","9"(WiresharkのSpoke.hs対65:10:c3:92:09

0x10がDLEなので、おそらくいくつか起こっていることがわかりましたが、理由はわかりません。

私はWiresharkを長年信頼していますが、数十時間しか経験していないので、私はそれが誤りであると仮定しました。

感謝の意を表します。

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

bytestringパッケージのドキュメントでは、 'ByteString'を' [Word8] 'に変換する' unpack'を挙げています。これは 'String'と同じではありません。 'ByteString'はUnicodeデータであるため、' ByteString'と 'String'の間にはいくつかのバイトの違いがあると思いますが、' ByteString'は効率的なバイト配列ですが、 'unpack'は' String'を生成できません。最初の場所。 –

+5

冗長なデータ変換を避けるために、ネットワークバイトストリングを使用できますか? –

+0

@MatthewWalton: 'Data.ByteString.Char8'の' unpack'や遅延型の 'String'が出力されます。彼らはUnicode対応ではありません。 –

答えて

3

私はバイト文字列パッケージリストの参照ドキュメントはStringと同じではありませんByteStringから[Word8]を、変換として解凍します。 ByteStringStringの間にはいくつかのバイトの違いがあると予想しますが、StringはUnicodeデータなので、ByteStringは効率的なバイト配列ですが、unpackは最初にStringを生成できません。

ここでユニコード変換に迷惑をかける可能性があります。少なくとも、基礎となるデータが実際にはなく、あまりうまくいきません。

+0

いいえ、 'unpack :: ByteString - > [Char]'(私はStringが[Char]のエイリアスだと思います)とも言います。 http://hackage.haskell.org/packages/archive/bytestring/latest/doc/html/Data-ByteString-Char8.html#v:unpack – fadedbee

+1

これは 'Data.ByteString.Char8'です。私は' Data 'を探していました。 ByteString.Lazy'。それにもかかわらず、John Lが、Unicode対応ではない質問に関するコメントで指摘したように。 –

+2

これは間違いなくユニコード変換です。 [コードポイントD8はUTF-8でC3 98です](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=d8&mode=hex)。だからこそ0x7Fの下の値は無傷になります。 – rxg

1

toStringfromStringは、unpackpackの代わりにutf8-stringになります。 This blog postは私にとって非常に役に立ちました。

関連する問題