6

小さな UDP/protobuf 送信機と受信機を作成しました。protobuf デコードでエラーが発生した理由を突き止めようと午前中を費やしましたが、正しくないデータを送信していたのは送信機 (Spoke.hs) であることがわかりました。

unpackLazy.ByteStrings をネットワーク パッケージが送信する文字列に変換するために使用されるコード。ホーグルで見つけましunpackた。私が探している関数ではないかもしれませんが、「O(n) ByteString を String に変換する」という説明は適切に見えます。

Spoke.hs は次の出力を生成します。

chris@gigabyte:~/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"]

Wireshark は、パケット内のデータが次のようになっていることを示しています。

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

長さ (45) は、Spoke.hs と Wireshark で同じです。

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

"65","10","d2","9"Spoke.hs65:10:c3:92:09と Wireshark で。

0x10 は DLE であるため、おそらく何らかのエスケープが行われているのではないかと思いましたが、その理由はわかりません。

私は長年 Wireshark を信頼しており、Haskell の経験は数十時間しかないので、コードに問題があると思い込んでいます。

任意の提案をいただければ幸いです。

-- 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 "jdoe@example.com",
  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 ()
4

2 に答える 2

3

バイト文字列パッケージについて私が見るドキュメントには、 unpack を に変換するByteStringものとして記載されていますが[Word8]、これは と同じではありませんString。と の間のバイトの違いが予想されますがByteStringStringこれStringは Unicode データであり、ByteStringは単なる効率的なバイトの配列ですが、そもそもunpackを生成できないはずです。String

したがって、ここで Unicode 変換に違反している可能性があります。または、基になるデータが実際には Unicode ではない場合に、少なくとも何かがそれを Unicode として解釈しており、それがうまく終了することはめったにありません。

于 2012-06-15T15:11:18.900 に答える
1

andの代わりにtoStringand fromStringfrom utf8-stringが必要になると思います。このブログ投稿は私にとって非常に役に立ちました。unpackpack

于 2015-09-09T11:04:03.193 に答える