2012-01-05
■[Haskell] 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しましょう。
日本語はまだ表示できていません。
参考:
haskell hostname resolve - 今日も明日もググったー
hGetContents と hClose - zknxの日記
追記 2012/01/05 15:11:
shelarcyさんからアドバイスいただいたので、deepseqで書き換えてみました。
|
@cpp_akira hGetContents したデータを取得するには、length 関数ではなく deepseq パッケージの Control.Depseq モジュールで提供されている関数を使うと良いですよ。 URL 2012-01-05 15:02:19 via YoruFukurou to @cpp_akira |
|
2012-01-05 15:03:45 via YoruFukurou to @cpp_akira |
|
@cpp_akira deepseq パッケージは Haskell Platform で提供されているので、利用するのにそんなに手間もかかりませんし。 URL 2012-01-05 15:07:11 via YoruFukurou to @cpp_akira |
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
- 27 http://t.co/Ck0jqPlk
- 8 http://d.hatena.ne.jp/tt_clown/20111222/cpp11_advent_calendar
- 8 http://www.google.co.jp/url?sa=t&rct=j&q=C++0X&source=web&cd=2&ved=0CDoQFjAB&url=http://d.hatena.ne.jp/faith_and_brave/20100201/1264997004&ei=TFwFT4yAKLCZiQfchbHSAQ&usg=AFQjCNH88RBKcb3sclAw9QXAhYQ7tCzg4A&sig2=M0ev4Hq7Rh8JHINeBZrE4w
- 8 http://www.google.co.jp/url?sa=t&rct=j&q=c++ timer.wait&source=web&cd=6&ved=0CFsQFjAF&url=http://d.hatena.ne.jp/faith_and_brave/20110325/1301036992&ei=9HgGT-GGBZCZmQWgoYCfCA&usg=AFQjCNHK27Bi7vLgGSv87mjr0s1KH80skA
- 8 http://www.google.co.jp/url?sa=t&rct=j&q=presentmodalviewcontroller&source=web&cd=2&ved=0CDMQFjAB&url=http://d.hatena.ne.jp/faith_and_brave/20110112/1294799495&ei=VjsFT_6zJ8HQrQez_dTcDw&usg=AFQjCNEvikozqbzol84D_Hoi3ZnBfA35Uw
- 4 http://t.co/xP7xs8qH
- 3 http://d.hatena.ne.jp/rainlib/20100814/1281796673
- 3 http://sarudeki.maiway.jp/forum/topic/368
- 3 http://www.google.co.jp/hws/search?hl=ja&client=fenrir&channel=&adsafe=off&safe=off&q=utf8+CFile&lr=all&btnG.x=0&btnG.y=0
- 3 http://www.google.co.jp/reader/view/?hl=ja