当我运行代码时:
import Control.Applicative
import Control.Concurrent
import Control.Monad
import Network.Socket
import System.Environment
import System.IO
import Numeric (showHex)
import qualified System.ByteOrder as BO
import qualified Data.ByteString as B
import Data.ByteString (toStrict)
import Data.ByteString.Conversion (toByteString)
import Data.Word (Word16)
prettyPrint :: B.ByteString -> String
prettyPrint = concatMap ((\x -> "0x"++x++" ") . flip showHex "") . B.unpack
main :: IO ()
main = withSocketsDo $ do
port <- toEnum . read . head <$> getArgs
newSocket <- socket AF_INET Stream defaultProtocol
setSocketOption newSocket ReuseAddr 1
bindSocket newSocket $ SockAddrInet port iNADDR_ANY
listen newSocket 2
runServer echo newSocket
runServer :: (String -> String) -> Socket -> IO()
runServer f s = forever $ do
(usableSocket,_) <- accept s
forkIO $ interactWithSocket f usableSocket
interactWithSocket :: (String -> String) -> Socket -> IO()
interactWithSocket f s = do
handle <- socketToHandle s ReadWriteMode
forever $ f <$> recv handle 1024 >>= process >> putStrLn (prettyPrint msg)
process :: ByteString -> IO ()
process input = let command = B.take 2 $ B.take 2 input in
putStrLn (prettyPrint)
我得到输出:
0x1 0x11 0x80 0x5 0x0 0x0 0x0 0x0
0x80 0x5
按预期运行
uspip --tcp-port 1024 list -r localhost
后。
但是当我用替换主要功能时
main = putStrLn $ prettyPrint $ toStrict (toByteString (BO.toBigEndian (fromInteger 0x8005) :: Word16))
我得到输出:
0x31 0x34 0x30 0x38
注意我正在尝试编写一个 https://docs.kernel.org/usb/usbip_protocol.html 服务器。
因此,我需要能够将命令代码(如 0x8005)存储在常量中,以便了解正在接收哪些命令。
问题是你正在使用
toByteString
...这是一台漂亮的打印机,所以你正在检查漂亮的打印输出;参见实现),只是转发到word16Dec
这里,用word16Dec 0x0580 == "1408" -- (== "\x31\x34\x30\x38")
。
您可以首先构建正确的字节串,而不是尝试构建整数并尝试转换字节串:
-- using ByteString string literals requires OverloadedStrings
B.pack [0x80, 0x05] == "\x80\x05"
作为补充说明,在整数文字上使用
toBigEndian
是没有意义的。无论您所在系统的本机字节顺序如何,整数文字都已经以大端方式编写,因此如果您碰巧在小端系统上,您所做的就是翻转字节。
考虑使用谷物库。
Data.Serialize.Put> runPut (putWord16be 0x8005) == "\x80\x05"
True