Hatena::ブログ(Diary)

Faith and Brave - C++で遊ぼう このページをアンテナに追加 RSSフィード Twitter

2012-01-05

[] Networkモジュールを使ってGET

Haskell でソケット通信をやってみる - yasuabe blog


このエントリを見て、簡単そうだったので遊んでみました。

httpでGETをするだけですが、こんな感じで書けました。

import Network
import System.IO

getCommand :: String -> IO String
getCommand hostName = withSocketsDo $ do
        hSetBuffering stdout NoBuffering
        soc <- connectTo hostName (PortNumber 80)
        hSetBuffering soc LineBuffering
        hPutStr soc $ "GET /index.html HTTP/1.1\nHost:" ++ hostName ++ "\n\n"
        result <- hGetContents soc
        length result `seq` hClose soc
        hClose soc
        return result

main = getCommand "www.boost.org" >>= putStrLn
HTTP/1.1 200 OK

Date: Wed, 04 Jan 2012 09:05:47 GMT

Server: Apache/2.0.52 (Red Hat)

Accept-Ranges: bytes

Transfer-Encoding: chunked

Content-Type: text/html



38b

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <meta name="generator" content=
  "HTML Tidy for Windows (vers 1st November 2003), see www.w3.org" />

  <title>Boost C++ Libraries</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="icon" href="/favicon.ico" type="image/ico" />
  <link rel="stylesheet" type="text/css" href="/style-v2/section-welcome.css" />
  <!--[if IE 7]> <style type="text/css"> body { behavior: url(/style-v2/csshover3.htc); } </style> <![endif]-->
  <meta name="google-site-verification" content="mpr2HgFpodnbF_8fv4qXd9roIClVwtX3C-Kd3F6r61w" />
</head>

<!--
Note: Editing website content is documented at:
http://www.boost.org/development/website_updating.html
-->
...

いろいろ試行錯誤しました。

まず、名前解決はどうやるのかを調べたら、connectToの中でやってたので、URLを直指定でOKでした。

それと、受信したデータをどうやって関数の戻りにするかで悩みました。hGetContentsで受信したデータは遅延評価されてるので、接続を閉じてしまうとうまくデータがとれなくなってしまいます。

なので、hGetContentsしたデータにlength関数をかませてeofまで評価して、それから接続を閉じています。

それと、ここではエラー処理を書いていませんが、接続に失敗したらconnectToは例外を投げます。catchしましょう。


日本語はまだ表示できていません。


参考:

Network - Hackage

Network.Socket - Hackage

haskell hostname resolve - 今日も明日もググったー

hGetContents と hClose - zknxの日記

Haskell でネットワーク - zyxwvの日記


追記 2012/01/05 15:11:

shelarcyさんからアドバイスいただいたので、deepseqで書き換えてみました。

import Network
import System.IO
import Control.DeepSeq

getCommand :: String -> IO String
getCommand hostName = withSocketsDo $ do
        hSetBuffering stdout NoBuffering
        soc <- connectTo hostName (PortNumber 80)
        hSetBuffering soc LineBuffering
        hPutStr soc $ "GET /index.html HTTP/1.1\nHost:" ++ hostName ++ "\n\n"
        result <- hGetContents soc
        result `deepseq` hClose soc
        return result

main = getCommand "www.boost.org" >>= putStrLn

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/faith_and_brave/20120105/1325742887