全てのコードが最適な形で書かれている訳ではないことをご了承ください。あくまで自分の実験的なコードです。参考にしたサイトは一番下にまとめて記述しています。
Java
package foo.bar; import java.io.*; import java.net.*; public class HttpClient { public static void main(String args[]){ String host = "hatsukari.2ch.net"; String path = "/news/subject.txt"; int port = 80; String line; Socket socket; BufferedReader reader; BufferedWriter writer; try { socket = new Socket(host, port); reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); writer.write("GET " + path + " HTTP/1.1\r\n"); writer.write("Accept-Encoding: gzip \r\n"); writer.write("Host: " + host + ":" + port + "\r\n"); writer.write("Accept: */*\r\n"); writer.write("Referer: http://hatsukari.2ch.net/news/ \r\n"); writer.write("Accept-Language: ja \r\n"); writer.write("User-Agent: Mozilla/5.0 \r\n"); writer.write("Connection: close \r\n\r\n"); writer.flush(); while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); writer.close(); socket.close(); } catch (UnknownHostException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (IOException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } }
C#
同じくgzipの解凍ができてない上にかなりいい加減
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpClient { class Program { static void Main(string[] args) { //GETリクエストを送信するサーバー名とパス string server = "hatsukari.2ch.net"; //リクエストメッセージを作成する string reqMsg = "GET /news/subject.txt HTTP/1.1 \r\n" + "Accept-Encoding: gzip \r\n" + "Host: hatsukari.2ch.net \r\n" + "Accept: */*\r\n" + "Referer: http://hatsukari.2ch.net/news/ \r\n" + "Accept-Language: ja \r\n" + "User-Agent: Mozilla/5.0 \r\n" + "Connection: close \r\n\r\n"; //文字列をbyte配列に変換 System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis"); byte[] reqBytes = enc.GetBytes(reqMsg); //ホスト名からIPアドレスを取得 System.Net.IPAddress hostadd = System.Net.Dns.Resolve(server).AddressList[0]; System.Net.IPEndPoint ephost = new System.Net.IPEndPoint(hostadd, 80); //Socketの作成 System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket( System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); //接続 sock.Connect(ephost); //リクエストメッセージを送信 sock.Send(reqBytes, reqBytes.Length, System.Net.Sockets.SocketFlags.None); //受信する byte[] resBytes = new byte[1024]; System.IO.MemoryStream mem = new System.IO.MemoryStream(); while (true) { int resSize = sock.Receive(resBytes, resBytes.Length, System.Net.Sockets.SocketFlags.None); if (resSize == 0) break; mem.Write(resBytes, 0, resSize); } string resMsg = enc.GetString(mem.GetBuffer(), 0, (int)mem.Length); mem.Close(); //閉じる sock.Shutdown(System.Net.Sockets.SocketShutdown.Both); sock.Close(); //受信したメッセージを表示する Console.WriteLine(resMsg); } } }
Boostを使ったC++
2011/11/06 gzipの解凍処理を追加…なんかもっとスマートに書く方法あるんじゃないかな?
#include <fstream> #include <iostream> #include <string> #include <boost/asio.hpp> #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> #include <boost/filesystem/fstream.hpp> using namespace std; using namespace boost::asio; namespace fs = boost::filesystem; int main() { // ディレクトリ作成 fs::path dir( "./dat" ); fs::create_directory( dir ); // menu.2ch.net の http サービスに接続 ip::tcp::iostream s( "menu.2ch.net", "http" ); // 送信 s << "GET /bbsmenu.html HTTP/1.0 \r\n"; s << "Accept-Encoding: gzip \r\n"; s << "Host: menu.2ch.net \r\n"; s << "Accept: \r\n"; s << "Referer: http://menu.2ch.net/ \r\n"; s << "Accept-Language: ja \r\n"; s << "User-Agent: Mozilla/5.0 \r\n"; s << "Connection: close \r\n"; s << "\r\n"; s << flush; // 受信 string line; bool flag = false; // gzipのヘッダ作成 char HEX[] = {0x1f,0x8b,0x08,0x00}; // ios::binary はバイナリ形式で出力 fs::ofstream outputfilegzip( dir/"BoardList.gzip", std::ios::binary ); while( getline(s, line) ){ if ( flag ) { // 真の場合 outputfilegzip << line << endl; } else { // 偽の場合 unsigned int loc = line.find( *HEX , 0 ); if( loc != string::npos ) { outputfilegzip << line << endl; flag = true; } } } outputfilegzip.close(); line.clear(); }
win32api風C++
(あとでgzipの変換やらを付け足すつもり…)
// HttpClientWin32.cpp #include <stdio.h> #include <WinSock2.h> #include <string.h> #define _CRT_SECURE_NO_WARNINGS #pragma comment(lib, "C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\Lib\\WinInet.Lib") #pragma comment(lib, "C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\Lib\\WSock32.Lib") int main(){ WSADATA wsaData; LPHOSTENT lpHost; SOCKET s; int nRtn; SOCKADDR_IN sockadd; //やっぱりサーバーは決め打ち char* szServer = "hatsukari.2ch.net"; u_short port = atoi("80"); //受け取ったHTTP通信のボディだけ受け取るための変数 boolean record = false; char szStrRcv[1024]; char *szStr; unsigned int addr; //データ保存先のファイルポインタ FILE *fp; //WinSockの初期化 if (WSAStartup(MAKEWORD(1, 1), &wsaData ) != 0 ){ perror("WSAStartupエラーです\n"); return -1; } //ソケットオープン s = socket(PF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { perror("ソケットをオープンできません\n"); WSACleanup(); return -2; } //名前解決 lpHost = gethostbyname(szServer); if (lpHost == NULL) { addr = inet_addr(szServer); lpHost = gethostbyaddr((char *)&addr, 4, AF_INET); sprintf(szStr, "%sが見つかりません\n", szServer); perror(szStr); WSACleanup(); return -3; } //構造体を用意してやっと接続 memset(&sockadd, 0, sizeof(sockadd)); sockadd.sin_family = AF_INET; sockadd.sin_port = htons(port); sockadd.sin_addr = *((LPIN_ADDR)*lpHost->h_addr_list); if (connect(s, (PSOCKADDR)&sockadd, sizeof(sockadd)) != 0){ perror("サーバーソケットに接続失敗\n"); closesocket(s); WSACleanup(); return -4; } //送りつけるリクエスト文をsprintfで生成 char* szStrBuf = "GET /news/subject.txt HTTP/1.1 \r\nHost: hatsukari.2ch.net \r\nAccept: */*\r\nReferer: http://hatsukari.2ch.net/news/ \r\nAccept-Language: ja \r\nUser-Agent: Mozilla/5.0 \r\nConnection: close \r\n\r\n"; nRtn = send(s, szStrBuf, (int)strlen(szStrBuf), 0); //ダウンロードした文章読み出しループ・gzip形式のファイルに追記する if ((fp = fopen("data.txt", "a+")) == NULL) { printf("ファイルがオープンできんぞコラ\n"); return -5; } while(1) { //szStrRcvが読み出された文字列の本体 memset(szStrRcv, '\0', sizeof(szStrRcv)); nRtn = recv ( s, szStrRcv, (int)sizeof(szStrRcv) - 1, 0); //読みだすものがなくなったらブレーク if ( nRtn == 0 ) break; //エラーが出たらブレーク if ( nRtn == SOCKET_ERROR ) { perror("recvエラーです\n"); break; } //ファイルに追記 if ( record == true ){ fputs(szStrRcv , fp); } //Content-Type: text/plainが文字列として読み出されたらスイッチをオン //if ( strstr( szStrRcv, "Content-Type: text/plain" ) != NULL || record == true ) { // record = true; //} } if ( shutdown(s, SD_BOTH) != 0) { perror("シャットダウンに失敗しました\n"); } closesocket(s); WSACleanup(); fclose(fp); return 0; }
Perl
#!C:\strawberry\perl\bin\perl.exe -w # $Id: http-client.pl,v 1.3 2003/03/23 11:28:03 68user Exp $ # 右のサイトを参考に作成しました http://x68000.q-e-d.net/~68user/net/http-2.html use strict; use Encode qw/ decode /; use Compress::Zlib; # Socket モジュールを使う use Socket; # 接続先ホスト名 my $host = 'hatsukari.2ch.net'; # HTTP プロトコルを使う my $port = getservbyname('http', 'tcp'); # ホスト名を、IP アドレスの構造体に変換 my $iaddr = inet_aton($host) or die "$host は存在しないホストです。\n"; # ポート番号と IP アドレスを構造体に変換 my $sock_addr = pack_sockaddr_in($port, $iaddr); # ソケット生成 socket(SOCKET, PF_INET, SOCK_STREAM, 0) or die "ソケットを生成できません。\n"; # 指定のホストの指定のポートに接続 connect(SOCKET, $sock_addr) or die "$host のポート $portに接続できません。\n"; # ファイルハンドル SOCKET をバッファリングしない select(SOCKET); $|=1; select(STDOUT); # WWW サーバに HTTP リクエストを送る print SOCKET "GET /news/subject.txt HTTP/1.1 \r\n"; print SOCKET "Accept-Encoding: gzip \r\n"; print SOCKET "Host: hatsukari.2ch.net \r\n"; print SOCKET "Accept: */*\r\n"; print SOCKET "Referer: http://hatsukari.2ch.net/news/ \r\n"; print SOCKET "Accept-Language: ja \r\n"; print SOCKET "User-Agent: Mozilla/5.0 \r\n"; print SOCKET "Connection: close \r\n"; print SOCKET "\r\n"; # ヘッダ部分を受け取る while (<SOCKET>){ # 改行のみの行ならループを抜ける m/^\r\n$/ and last; } # 圧縮されたファイルの入れ物 my $buffer; while (my $line = <SOCKET>){ $buffer .= $line } # 表示させる文字列 my $showstr = Compress::Zlib::memGunzip($buffer); my $decode_data = decode ( 'shiftjis' , $showstr ); print $decode_data;
ここで正規表現使ってみたりも面白いよ
# URL 例 http://hatsukari.2ch.net/test/read.cgi/news/1320145754/ my $twochURL = "<a href=\"http://hatsukari.2ch.net/test/read.cgi/news/"; my $endtag = "</a><br>"; $decode_data =~ s/([\d]{10}).dat<>([^\n]+)\n/$twochURL$1\"\/>$2$endtag/gm; #改行コードを <BR>タグに置換える $decode_data =~ s/\r\n/<BR>/g; $decode_data =~ s/\n/<BR>/g; $decode_data =~ s/\r/<BR>/g;
参考サイト
2chのサーバの仕様
スレッドタイトル一覧の取得::monazilla.org
C++ Win32API風
猫でもわかるネットワークプログラミング 第2版 (猫でもわかるプログラミングシリーズ)
- 作者: 粂井康孝
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/02/25
- メディア: 単行本
- 購入: 1人 クリック: 16回
- この商品を含むブログ (11件) を見る
letsboost::asio
Perl
HTTP クライアントを作ってみよう(2)
C#
Socketを使ってHTTPでファイルをダウンロードし表示する: .NET Tips: C#, VB.NET
ホスト名からIPアドレス、IPアドレスからホスト名を取得する: .NET Tips: C#, VB.NET