ページ 1 / 1
改行判定につまづいている
Posted: 2012年5月20日(日) 10:39
by helloworld1853
改行判定に躓いています。
InternetReadFile関数を使わずに
webサイトのソースコードを取得するプログラムを作っているのですが・・・
GETコマンドを送信するとソースコード以外にもヘッダもついてきます。
どうすればいいのか考えた挙句、
ヘッダ部とボディ部との間に改行ができるという特徴を利用して
ボディ部を抽出することにしました。
( もっと簡単な方法があるのであれば教えてください。 )
テストプログラムを作ってみたのですが、
かなりひどく、動作がおかしいです。
そのため みなさまからアドバイスまたはおおまかなプログラムの流れを
教えていただきたいです。
ちなみにGETコマンドを送るソースコードです。
動作確認済みです。
コード:
# pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
WSADATA wsadata;
WSAStartup( 0x0101, &wsadata );
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("125.172.198.97");
addr.sin_port = htons(80);
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 ) {
printf( "can't open http port\n" );
return 0;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n = send( sock, get, strlen(get), 0 );
printf( "send: %d\n", n );
char buf[256];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 ) {
n = recv( sock, buf, sizeof(buf)-1, 0 );
if ( n <= 0 ) break;
buf[ n ] = '\0';
printf( buf );
}
closesocket( sock );
}
Re: 改行判定につまづいている
Posted: 2012年5月20日(日) 10:53
by beatle
helloworld1853 さんが書きました:GETコマンドを送信するとソースコード以外にもヘッダもついてきます。
どうすればいいのか考えた挙句、
ヘッダ部とボディ部との間に改行ができるという特徴を利用して
ボディ部を抽出することにしました。
( もっと簡単な方法があるのであれば教えてください。 )
ヘッダ部とボディ部を分離する方法としては、空行を認識するという方法が正しい方法ですから、helloworld1853さんの考え方は合ってます。
HTTP入門 メッセージ構文
ヘッダとボディの区切りは空行である、というのはHTTPの規格で決まっていることですので、その空行を認識するより簡単であり、かつ規格に合致した方法はないと思います。
Re: 改行判定につまづいている
Posted: 2012年5月20日(日) 11:03
by softya(ソフト屋)
気になる所。
1,応答メッセージのステータス番号はちゃんと判定した方が良いと思います。
2.添付されたコードは改行判定がありませんので問題が把握できません。
3.色々なサイトのアクセスを行うなら文字コードの判定・変換が必須です。
空白改行で判定するのは正しいので、その問題のあるコードを添付して下さい。
Re: 改行判定につまづいている
Posted: 2012年5月20日(日) 12:05
by helloworld1853
テストプログラムなので
エラー処理はつけていません。
このプログラムは一応実行できます。
コード:
# pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
char buf1[256];//この中にボディ部を入れる
int ROOP(char recvbuf[256])//空行判定する自作関数
{
int counter;
int counter1;
for(counter=0;counter!=256;++counter)
{
if(recvbuf[counter]==0x0D)//空行判定(\r)
{
if(recvbuf[counter+1]==0x0A)//空行判定(\n)
{
if(recvbuf[counter+2]==0x0D)//空行判定(\r)
{
if(recvbuf[counter+3]==0x0A)//空行判定(\n)
{
for(counter+4,counter1=0;;++counter,++counter1)
{
if((recvbuf[counter+4])==NULL)//入力されたrecvbufが空になったら
{
buf1[counter1]='\0';
return 0;//
}
buf1[counter1]=recvbuf[counter+4];//buf1にrecvbufを代入
}
}
}
}
}
}
}
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
WSADATA wsadata;
WSAStartup( 0x0101, &wsadata );
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("125.172.198.97");
addr.sin_port = htons(80);
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 ) {
printf( "can't open http port\n" );
return 0;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n = send( sock, get, strlen(get), 0 );
printf( "send: %d\n", n );
char buf[256];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 )//256バイトずつ受信
{
n = recv( sock, buf, sizeof(buf)-1, 0 );
if ( n <= 0 ) break;
ROOP(buf);
buf[ n ] = '\0';
printf( buf1 );
}
closesocket( sock );
}
Re: 改行判定につまづいている
Posted: 2012年5月20日(日) 12:08
by softya(ソフト屋)
実行する前からわかる問題として256バイトのバッファ境界をまたがった場合は、この処理ではちゃんと動きません。
[補足]ブラウザで実行してもサイトのアドレスではページ読み込みエラーとなります。
http://s1.muryo.etowns.net/~yamada_mama_papa/index.html
【さらに追記】
エラー処理はデバッグのためにも必要なのです。
テスト版だから不要というのは無駄にデバッグを困難にするだけだと思います。前回のも無駄に手間が増えていましたよね。
今回のもエラー表示されないのでデバッガでトレースして発覚しましたが、本当に動作確認されましたか?
「今度はバグ報告」
1.256バイトのバッファ境界をまたがった場合は処理できない。
2.ヘッダだけの処理で良いはずが256バイト毎に\r\n\r\nの処理をしている。
3.buf1をクリアしていないのでヘッダが256バイトを超えた時の動作が保証されない。
4.バグじゃないけど戻り値が分かりづらいグローバル変数。
Re: 改行判定につまづいている
Posted: 2012年5月20日(日) 16:24
by helloworld1853
バイナリの比較の仕方は
コード:
recvbuf[counter]==0x0D
であっていますか。
Re: 改行判定につまづいている
Posted: 2012年5月20日(日) 16:35
by softya(ソフト屋)
helloworld1853 さんが書きました:バイナリの比較の仕方は
コード:
recvbuf[counter]==0x0D
であっていますか。
デバッガで動作は確認できると思いますが、0x00から0x7fまでの値ならこの比較方法で問題無いです。
Re: 改行判定につまづいている
Posted: 2012年5月26日(土) 21:51
by helloworld1853
ごめんなさい・・・
返信がずいぶん遅れました。
さて、プログラムはだいぶ改良し
一部を除いて完璧に動作しています。
で問題点とは余計な文字が入ってしまうことです。
わかりやすくするため期待している結果と
実際の結果を載せておきます。
実際の結果
send: 73
http recv data
=========================
空行は26文字目で見つかりました。
ontent-Type: text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//省略
期待している結果
send: 73
http recv data
=========================
空行は26文字目で見つかりました。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//省略
ソースコードを以下に載せます。
コード:
# pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
char body[256];//この中にボディ部を入れる
int check=-1;//checkは空行がすでに見つかっているか判断する
//check==-1のとき、空行はまだ見つかっていない
//check==0のとき、空行はすでに見つかっている
int MYroop(char recvbuf[256])//空行判定する自作関数
{
if(check==0)//空行はすでに見つかっているとき
{
return 0;
}
int recvcounter;
int bodycounter;
for(recvcounter=0;recvcounter!=256;++recvcounter)
{
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
{
if(recvbuf[++recvcounter]==0x0A)//空行判定(\n)
{
if(recvbuf[++recvcounter]==0x0D)//空行判定(\r)
{
if(recvbuf[++recvcounter]==0x0A)//空行判定(\n)
{
for(++recvcounter,bodycounter=0;;++recvcounter,++bodycounter)
{
if((recvbuf[recvcounter])=='\0')//入力されたrecvbufが空になったら
{
printf("空行は%d文字目で見つかりました。\n",recvcounter);
check=0;
body[bodycounter]='\0';
return 0;//
}
body[bodycounter]=recvbuf[recvcounter];//bodyにrecvbufを代入
}
}
}
}
}
}
return -1;
}
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
char ServerName[] = "s1.muryo.etowns.net"; // 接続先のホスト名
char head[] = "GET /~yamada_mama_papa/test.cgi HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n";
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0), &wsadata);
int nErrorStatus;
PHOSTENT phostent; // サーバの情報を指すポインタ
unsigned long ulIPAddress;// サーバのIPアドレス格納変数
nErrorStatus = WSAStartup(wVersionRequested, &wsadata);
if(atexit((void (*)(void))(WSACleanup)))
{ // 終了時にWinSockのリソースを解放
printf("atexit(WSACleanup)失敗\n");
return -1;
}
if(nErrorStatus != 0)
{
printf("初期化失敗です\n");
return -1;
}
else
{
if(LOBYTE( wsadata.wVersion ) == 1
&& HIBYTE( wsadata.wVersion ) == 1)
{ // 要求したバージョンと同一か確認
printf("WinSock初期化成功\n");
}
else
{
printf("WinSock初期化失敗です\n");
return -1;
}
}
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if(sock == INVALID_SOCKET)
{
printf("ソケット作成失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
return -1;
}
// サーバのIPアドレス取得
ulIPAddress = inet_addr(ServerName); // IPアドレス取得
// inet_addr()関数が失敗 ServerNameがホスト名であった場合下の処理に入る
if(ulIPAddress == -1)
{
if( (phostent = gethostbyname(ServerName)) != NULL)
{
ulIPAddress = *((unsigned long *)(phostent->h_addr));
}
else
{
printf("ホストアドレス取得失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock); // ソケットの破棄
return -1;
}
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ulIPAddress;
addr.sin_port = htons(80);
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 )
{
printf( "HTTPポートが開けません。\n" );
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock);
return -1;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n =send( sock, get, strlen(get), 0 );
if(n != SOCKET_ERROR)
{
printf( "send: %d\n", n );
}
else
{
printf("サーバへの送信失敗です\n");
printf("エラー%dが発生しました\n", WSAGetLastError());
shutdown(sock, SD_BOTH); // 送受信を無効にする
closesocket(sock); // ソケットの破棄
return -1;
}
char buf[256];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 )//256バイトずつ受信
{
n = recv( sock, buf, sizeof(buf)-1, 0 );
buf[ n ] = '\0';
if ( n <= 0 )
{
if(check==0)
{
puts("改行判定成功!!!");
}
else
{
puts("結局改行は発見できませんでした。");
}
break;
}
if(MYroop(buf)==0)
{
printf(buf);
}
else
{
printf(body);
}
}
closesocket( sock );
return 0;
}
Re: 改行判定につまづいている
Posted: 2012年5月26日(土) 23:06
by softya(ソフト屋)
「今度はバグ報告」
1.256バイトのバッファ境界をまたがった場合は処理できない。
2.ヘッダだけの処理で良いはずが256バイト毎に\r\n\r\nの処理をしている。
3.buf1をクリアしていないのでヘッダが256バイトを超えた時の動作が保証されない。
4.バグじゃないけど戻り値が分かりづらいグローバル変数。
直っているのは2.3.だけだと思います。
あと前回抜けていましたが受信したサイズが256バイトの保証がないのにMYroopで256バイトとして処理しています。
他にも戻り値の処理とか色々怪しいのでデバッガでちゃんと追いかけることをおすすめします。
Re: 改行判定につまづいている
Posted: 2012年5月26日(土) 23:49
by helloworld1853
>あと前回抜けていましたが受信したサイズが256バイトの保証がないのにMYroopで256バイトとして処理しています。
MYroop関数に
int bufsize=strlen(recvbuf);
を追加し、
for(recvcounter=0;recvcounter!=bufsize;++recvcounter)
にループ部分を修正しました。
で肝心なデバッグなんですが、
恥ずかしいことに デバッグのやり方がわかりません。
今から
http://news.mynavi.jp/articles/2008/08/ ... index.html
を参考にして勉強したいと思います。
このプログラムをデバッグする上でどこの部分を解析したほうがよいでしょうか。
専用のソフトを使ったほうがよいのでしょうか。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 00:18
by softya(ソフト屋)
専用というかVC++があれば十分です。
MYroopの呼び出し元でinputとoutputをまずチェックして異常があれば、MYroop内の処理を1つ1つ確認します。
↑buf,body,check、戻り値などを確認すると言うことです。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 17:49
by helloworld1853
解析した結果、わかった結果は以下のとおりです。
・bodyになにも入っていない
・\r\n\r\nの後の内容が常に'\0'になっていることだけです。
原因がまったくわかりません。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 18:02
by softya(ソフト屋)
helloworld1853 さんが書きました:解析した結果、わかった結果は以下のとおりです。
・bodyになにも入っていない
・\r\n\r\nの後の内容が常に'\0'になっていることだけです。
原因がまったくわかりません。
受信した内容から結果と原因を推測しないとデバッグになりません。
MYroop前のbufと後のbody,check、戻り値はどうなるのが正しくて現状はどうなっているんでしょうか?
次のものを書きだしてください。
(1) 1回目のMYroop前のbuf内容とサイズ
(2) 1回目の予定されるMYroop後のbody,check、戻り値
(3) 1回目の実際のMYroop後のbody,check、戻り値
これが出来たらループ2回目をやってみましょう。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 19:00
by helloworld1853
20,23,26,29,32,35行目にブレークポイントを設置し、
ローカル、自動変数ウィンドウを確認すると
recvbufに入っている値が表示されました。
この後F5( デバッグ再開 )連打をしましたがまったく変わりませんでした。
"HTTP/1.1 200 OK
Date: Sun, 27 May 2012 09:42:23 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
C"
やり方がおかしいのでしょうか。
それとも設置場所が悪いのでしょうか。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 19:13
by softya(ソフト屋)
行番号があっているとして、すくなくとも20行目は直前のforでbufsize回ループすると書いてあるのだから、それだけの回数ループするのでは?それとrecvcounterは、ちゃんと変化しているか確認できますよね。
プログラムの動きを想像しないとデバッグになりませんので、(2)は実際にMYroop内をデバッグする前に理想書くだけだから書けるはずです。MYroop内をデバッグする前に(2)をまず書きだしてください。それと(3)はMYroopから戻るreturnの処で確認できるはずです。細かいの部分のデバッグは(2)や(3)を把握せず闇雲にやっても時期尚早と言うものです。
(1) bufの内容。
"HTTP/1.1 200 OK
Date: Sun, 27 May 2012 09:42:23 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
C"
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 19:37
by へにっくす
helloworld1853 さんが書きました:"HTTP/1.1 200 OK
Date: Sun, 27 May 2012 09:42:23 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
C"
横レスします。
掲示しているURLにアクセスすると、ヘッダ部分は330bytesが返ってきます。以下のような感じ?
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Cache-Control: no-cache
Content-Type: text/html
Date: Sun, 27 May 2012 10:10:20 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
256bytesしか確保していないんだから、空行なんて
見つかるはずがありませんね。
てっとりばやく解決するなら256→512バイトにでも確保するバイト数をあげてみるしかないんじゃないかな。
私ならば行ごとに解析するように処理を変更しますが…
そもそも256バイトずつ区切るのが間違っとると思うので
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 20:20
by helloworld1853
なぜか自然変数ウィンドウ・ローカルウィンドウともに
recvbufの内容しか見れません。
recvcounterの内容すら表示されません。
原因は何でしょう。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 20:32
by softya(ソフト屋)
helloworld1853 さんが書きました:なぜか自然変数ウィンドウ・ローカルウィンドウともに
recvbufの内容しか見れません。
recvcounterの内容すら表示されません。
原因は何でしょう。
リリースビルドしていない限りは大丈夫なはずです。
ウォッチ式の追加も試してみてください。
へにっくす さんが書きました:helloworld1853 さんが書きました:"HTTP/1.1 200 OK
Date: Sun, 27 May 2012 09:42:23 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
C"
横レスします。
掲示しているURLにアクセスすると、ヘッダ部分は330bytesが返ってきます。以下のような感じ?
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Cache-Control: no-cache
Content-Type: text/html
Date: Sun, 27 May 2012 10:10:20 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
256bytesしか確保していないんだから、空行なんて
見つかるはずがありませんね。
てっとりばやく解決するなら256→512バイトにでも確保するバイト数をあげてみるしかないんじゃないかな。
私ならば行ごとに解析するように処理を変更しますが…
そもそも256バイトずつ区切るのが間違っとると思うので
512バイト・バッファを取ってもヘッダがそれを超える恐れは十分にあります。
1行が512バイトに収まる保証も実際にはありません(99%無いとしても)。
なので理想を言えばreallocしたバッファにヘッダを全部貯めこむことですが、それだと難易度が跳ね上がるので悩ましい所です。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 22:15
by helloworld1853
ここでひとつ質問がしたいのですが
一回目のループでヘッダの330バイト中256バイトを取り出し、
空行がなければ取り出した256バイトを無視し、二回目のループへ・・・
二回目のループで空行があれば
空行までのデータ( ヘッダ部の残り )を無視し、
空行後のデータ( ボディ部 )だけを抽出するという
方法ではダメなんですか。
この方法だったら何バイトも対応できそうですけど( あと技術的にも僕にあってそう )
見当違いだったらすみません。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 22:33
by softya(ソフト屋)
helloworld1853 さんが書きました:ここでひとつ質問がしたいのですが
一回目のループでヘッダの330バイト中256バイトを取り出し、
空行がなければ取り出した256バイトを無視し、二回目のループへ・・・
二回目のループで空行があれば
空行までのデータ( ヘッダ部の残り )を無視し、
空行後のデータ( ボディ部 )だけを抽出するという
方法ではダメなんですか。
この方法だったら何バイトも対応できそうですけど( あと技術的にも僕にあってそう )
見当違いだったらすみません。
例えば前半255バイトに\r\nがあって、残り255バイトに残りの\r\nがあったらうまく動きませんよね?
つまり、非常に限定した条件で動くプログラムを組んでしまっています。
サーバーの設定や広告やCGIの機能が変わったり返却されるヘッダやHTMLが変わると動かなくなる可能性が非常に高いのです。
その他にもクリティカルな条件が幾つか有りそうですが、こういうバッファをまたがるデータはプロでもミスが多い部分です。
recv()は1回で何バイトを読みこむか保証されていないので、巨大なバッファにしても意味が無い可能性があります。
なので、ちゃんと組んでおくべきだと思います。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 22:51
by helloworld1853
ありがとうございます。
その可能性があったことに気づきませんでした。
やはりrealloc関数を使いこなせるようにするほうがよいのでしょうか。
それとも今はほかの解決法を使用し、技術を磨いてから後に
reallocを使えるようにするほうがよのでしょうか。
Re: 改行判定につまづいている
Posted: 2012年5月27日(日) 23:37
by softya(ソフト屋)
考えてみました。
いきなりreallocは難しいと思うので、とりあえず4096バイトのバッファ(header_buff)を別に用意してbufの内容をstrcatで貯めこむという方式はどうでしょう。
header_buffをMYroopで処理します。
Re: 改行判定につまづいている
Posted: 2012年5月28日(月) 19:45
by helloworld1853
Re: 改行判定につまづいている
Posted: 2012年5月28日(月) 21:38
by helloworld1853
すみません。
全然関係ない話ですけど
"\"を表示させたいけど
"¥"が表示されてしまいます。
どうすれば"\"が表示されますか。
Re: 改行判定につまづいている
Posted: 2012年5月28日(月) 22:05
by softya(ソフト屋)
(1)ちょっと意味が違うような。単にbufを4096にしたのだったら大間違いというか適当すぎるでしょう。別バッファで4096にしたんですよね?
(2)もし読み込みを4096以内にして全体で4096バイトを超えるのを許容しないプログラムにしたのなら作っているプログラムにどんな意味があるんでしょうか?そんな限定条件で良いんでしょうか?
(3)私の提案したのはヘッダの専用バッファでヘッダだけで4096バイト以内ならOKになる物を作るという意図で書きましたが意図は伝わったでしょうか?
なぜ、今回うまく行っているか前のは何故ダメなのか理解しないと近いうちにどうにもバグが取れなくなる事態が待っていそうです。
(4)今後もプログラムに機能追加していくんですよね?
(5)原因を理解する気はありますか?
(1)から(5)の疑問にお応え下さい。
helloworld1853 さんが書きました:すみません。
全然関係ない話ですけど
"\"を表示させたいけど
"¥"が表示されてしまいます。
どうすれば"\"が表示されますか。
文字コードの問題ですのでSHIFT-JIS以外を使うしかありません。
"\"と"¥"は同じ数値の文字コードですが、日本語文字コードと英語文字コード等では違う文字が表示されます。
Re: 改行判定につまづいている
Posted: 2012年5月28日(月) 22:41
by helloworld1853
(1)に対して・・・
はい。bufとheader_buffは別物です。
256Bずつ受信し、そのデータをheader_buffにstrcatを使っていれています。
(2)に対して・・・
いいえ。4096Bでは足りません。画像も受信し、ファイルに保存する予定なので・・・
(3)に対して・・・
すみません。僕が勘違いをしてしまい変なことをしました。
これからは勝手に自分で事柄を思い込まないように心がけます。
(4)に対して・・・
はい。さまざまな機能をつけていく予定です。
(5)に対して・・・
あります。みなさまが投稿してくれたコメントを
よく読み、理解していく決意です。
まだまだ未熟ですが、今後ともよろしくお願いします。
Re: 改行判定につまづいている
Posted: 2012年5月28日(月) 22:51
by softya(ソフト屋)
分かりました。
で、この掲示板はutf-8の文字コードで表示しているので\が表示されますが、shift-jisは同じ文字コードで¥と表示されますので、無理に変えないほうが楽です。
(2)ヘッダが4096の収まるなら良いんですが不特定サイトにアクセスする前提だと無理が出ます。
あとPerlでcookieやら使い出すと足らなくなる恐れがあります。まぁ、cookie処理までするとクライアントも大変なので止めたおいたほうが良いでしょう。
(3)に関しては勘違いしていたとして、BODY部の問題は直せそうですか?
これは、(5)の問題とも絡みますね。
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 20:58
by helloworld1853
ところで
win32console.exe の 0x76ed15de でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00386000 に書き込み中にアクセス違反が発生しました。
という表示が出てきたのですがここの情報から原因のコードの箇所を突き止めることはできますか。
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 21:06
by softya(ソフト屋)
F5でデバッガ起動中ならその命令で止まるはずですが止まっていませんか?
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 21:15
by helloworld1853
if ( n <= 0 )
でとまっているのですが
どんな例外が考えられますか。
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 21:23
by softya(ソフト屋)
その直前の命令は何ですか?
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 22:10
by トントン
helloworld1853 さんが書きました:if ( n <= 0 )
でとまっているのですが
どんな例外が考えられますか。
例外が発生したとき、bufは意図した通りに使えているのでしょうか?
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 22:17
by helloworld1853
直前の命令は
n = recv( sock, buf, sizeof(buf)-1, 0 );
です。
bufが思い通りに使えているかどうかは今チェックしてみます。
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 22:18
by softya(ソフト屋)
helloworld1853 さんが書きました:直前の命令は
n = recv( sock, buf, sizeof(buf)-1, 0 );
です。
bufが思い通りに使えているかどうかは今チェックしてみます。
ソースコードを貼ってもらったほうが早そうです。
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 22:57
by helloworld1853
コメントをなるべく多くつけました。
流れとしては
256バイトずつ受信し、
MYroopで処理し、
header_buff[headercounter]=recvbuf[recvcounter];でデータを埋め込んでいます。
strcatを使ってのデータの受け渡しをしていません。(一バイトずつ処理しているので・・・)
コード:
#pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
int headercounter=0;//何度もループさせることが予想されるのでheadercounterを設置
//headercounterはMYroopに関係なく動作するのでMYroopの外に書く
char header_buff[4096];
char body[256];//この中にボディ部を入れる
int check=-1;//checkは空行がすでに見つかっているか判断する
//check==-1のとき、空行はまだ見つかっていない
//check==0のとき、空行はすでに見つかっている
int MYroop(char recvbuf[256])//空行判定する自作関数
{
if(check==0)//空行はすでに見つかっているとき
{
return 0;
}
int recvcounter;
for(recvcounter=0;recvcounter!=256;++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
{
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+1]==0x0A)//空行判定(\n)
{
if(recvbuf[recvcounter+1]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+1]==0x0A)//空行判定(\n)
{
check=0;
return 0;//空行に達したら終了
}
}
}
}
header_buff[headercounter]=recvbuf[recvcounter];//空行までのデータ つまりヘッダ部をheader_buffに1バイトずつ入力
}
return -1;
}
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
char ServerName[] = "s1.muryo.etowns.net"; // 接続先のホスト名
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0), &wsadata);
int nErrorStatus;
PHOSTENT phostent; // サーバの情報を指すポインタ
unsigned long ulIPAddress;// サーバのIPアドレス格納変数
nErrorStatus = WSAStartup(wVersionRequested, &wsadata);
if(atexit((void (*)(void))(WSACleanup)))
{ // 終了時にWinSockのリソースを解放
printf("atexit(WSACleanup)失敗\n");
return -1;
}
if(nErrorStatus != 0)
{
printf("初期化失敗です\n");
return -1;
}
else
{
if(LOBYTE( wsadata.wVersion ) == 1
&& HIBYTE( wsadata.wVersion ) == 1)
{ // 要求したバージョンと同一か確認
printf("WinSock初期化成功\n");
}
else
{
printf("WinSock初期化失敗です\n");
return -1;
}
}
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if(sock == INVALID_SOCKET)
{
printf("ソケット作成失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
return -1;
}
// サーバのIPアドレス取得
ulIPAddress = inet_addr(ServerName); // IPアドレス取得
// inet_addr()関数が失敗 ServerNameがホスト名であった場合下の処理に入る
if(ulIPAddress == -1)
{
if( (phostent = gethostbyname(ServerName)) != NULL)
{
ulIPAddress = *((unsigned long *)(phostent->h_addr));
}
else
{
printf("ホストアドレス取得失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock); // ソケットの破棄
return -1;
}
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ulIPAddress;
addr.sin_port = htons(80);
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 )
{
printf( "HTTPポートが開けません。\n" );
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock);
return -1;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n =send( sock, get, strlen(get), 0 );
if(n != SOCKET_ERROR)
{
printf( "send: %d\n", n );
}
else
{
printf("サーバへの送信失敗です\n");
printf("エラー%dが発生しました\n", WSAGetLastError());
shutdown(sock, SD_BOTH); // 送受信を無効にする
closesocket(sock); // ソケットの破棄
return -1;
}
char buf[256];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 )//256バイトずつ受信
{
n = recv( sock, buf, sizeof(buf)-1, 0 );
if ( n <= 0 )//#######ここでとまっている#######
{
if(check==0)
{
puts("改行判定成功!!!");
}
else
{
puts("結局改行は発見できませんでした。");
}
break;
}
buf[ n ] = '\0';
MYroop(buf);
}
printf(header_buff);
closesocket( sock );
return 0;
}
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 23:08
by softya(ソフト屋)
header_buffの4096バイトのバッファを超過してメモリを破壊しています。ガードして下さい。
あと、そもそも256バイト時の問題を何も解決しないままのコードですので、ちゃっんとデバッグして下さい。
次の理由を調べて下さい。
1.header_buffにちゃんと累積されない。
2.bufをまたがる\r\n\r\nの問題が残ったまま。
※ この2つはできうる限り調べて必ず回答して下さい。
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 23:26
by helloworld1853
>1.header_buffにちゃんと累積されない。
設計ミスでした。
空行判定の箇所を以下に変更しました。
コード:
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+1]==0x0A)//空行判定(\n)
{
if(recvbuf[recvcounter+2]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+3]==0x0A)//空行判定(\n)
またヘッダが4096バイトを超えたときのために
コード:
if(headercounter==4096)
{
puts("ヘッダが4096バイトを超えています。");
return -1;
}
という処理も追加しました。
>2.bufをまたがる\r\n\r\nの問題が残ったまま。
この問題は明日に必ず解決します。
ちなみに上記の修正を加えたプログラムの動作結果は下記のとおりです。
"HTTP/1.1 200 OK
Date: Sun, 27 May 2012 09:42:23 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
C"
Re: 改行判定につまづいている
Posted: 2012年5月29日(火) 23:42
by softya(ソフト屋)
1.についてはソコではないです。
どちらかと言うと2.の問題です。
※ 現にヘッダの途中でprintfが止まっていますよね。
[補足]
分かりやすくするためにbufを8バイト、recvサイズを7バイトにして動作を追いかけてみてください。
#define BUF_SIZE (8)
char buf[ BUF_SIZE];
としてサイズ変更に耐えられやすいプログラムに変えましょう。
Re: 改行判定につまづいている
Posted: 2012年5月30日(水) 23:05
by helloworld1853
http://s1.muryo-de.mydns.jp/~yamada_mam ... source.cpp
ここにソースコードをのせておきます。
bufをまたがる\r\n\r\nの問題を解決しようとしましたが
大幅な変更を加えたせいか、うまく動作しません。
自分なりにデバッグしたところ、プログラムの設計に原因があるようなので
直します。
なにかアドバイス(もう少しソースコードを整理したほうがよいなど)があれば
お願いします。
Re: 改行判定につまづいている
Posted: 2012年5月30日(水) 23:16
by softya(ソフト屋)
そのためのheader_buffなんですよ。ここにヘッダを集積させれば一発で検索できるって仕組みのためのものです。
header_buffの件でうまくバッファを結合できない様ですので8バイトのバッファにして動作を確認してみたら分かりやすよ。と提案しましたがそれもスルーされた様なので何が問題だったのでしょうか?説明して頂けると助かります。
[追記]
通信系のものを作るのならバッファ問題は避けて通れないので問題点をちゃんと理解して下さい。
バッファの動作を1バイトづつ紙に書いてみるって手もあります。8バイトならさほど難しくないですよ。
全部の状態をシミュレートをしなくてよいので最初の2回と\r\n\r\nの近辺で起こりえるバリエーションを網羅するだけです。
Re: 改行判定につまづいている
Posted: 2012年5月30日(水) 23:27
by helloworld1853
スルーしたのではなく
\r\n\r\nの問題も同時に解決できるのではないかと考え修正を加えてしまっただけでした。
認識が甘かったです。
Re: 改行判定につまづいている
Posted: 2012年5月30日(水) 23:41
by helloworld1853
softyaさんがおっしゃったとおりに
修正し、実行したところ
HTTP/1.
とだけ表示されます。
もう少し調べてみないとわかりませんが
MYroopに原因があるようです。
原因がわかる方お願いします。
また、なぜサイズを変えただけでプログラムの反応がこんなにも違うのですか。
Re: 改行判定につまづいている
Posted: 2012年5月30日(水) 23:47
by softya(ソフト屋)
helloworld1853 さんが書きました:softyaさんがおっしゃったとおりに
修正し、実行したところ
HTTP/1.
とだけ表示されます。
もう少し調べてみないとわかりませんが
MYroopに原因があるようです。
原因がわかる方お願いします。
また、なぜサイズを変えただけでプログラムの反応がこんなにも違うのですか。
大したバイト数じゃないので1バイトづつデバッガで動きを追いかけてみましょう。その為にコンパクトにしたのです。
テキストファイルにMYroopでのrecvcounterとheadercounterとheader_buffとbufの内容を1バイトづつ書き写してbufの2回目の処理の2バイト目まで書きだしてみてください。
[補足] 変化しないものは最初しか書かなくて良いです。それとheader_buffとbufの中身は16進数で書いてもらったほうが良いかも。
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 18:50
by helloworld1853
デバッグした結果です。
headercounter 0 int
recvcounter 0 int
recvbuf 0x0018fd9c "HTTP/1." char *
header_buff 0x013b3380 "" char [4096]
header_buff 0x013b3380 "H" char [4096]
header_buff 0x013b3380 "HT" char [4096]
header_buff 0x013b3380 "HTT" char [4096]
header_buff 0x013b3380 "HTTP" char [4096]
header_buff 0x013b3380 "HTTP/" char [4096]
header_buff 0x013b3380 "HTTP/1" char [4096]
header_buff 0x013b3380 "HTTP/1." char [4096]
headercounter 8 int
recvcounter 8 int//以後ずっと変わらず
recvcounter 0 int//以後ずっと変わらず
recvbuf 0x003bf88c "1 200 O" char *//以後ヘッダ8バイトずつ読み込まれていく
header_buff 0x01263380 "HTTP/1." char [4096]//以後ずっと変わらず
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 18:58
by nullptr
関係あるのか知りませんが、WSAStartupを二回呼んでいるのはなぜ?
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 18:59
by softya(ソフト屋)
helloworld1853 さんが書きました:デバッグした結果です。
headercounter 0 int
recvcounter 0 int
recvbuf 0x0018fd9c "HTTP/1." char *
header_buff 0x013b3380 "" char [4096]
header_buff 0x013b3380 "H" char [4096]
header_buff 0x013b3380 "HT" char [4096]
header_buff 0x013b3380 "HTT" char [4096]
header_buff 0x013b3380 "HTTP" char [4096]
header_buff 0x013b3380 "HTTP/" char [4096]
header_buff 0x013b3380 "HTTP/1" char [4096]
header_buff 0x013b3380 "HTTP/1." char [4096]
headercounter 8 int
recvcounter 8 int//以後ずっと変わらず
recvcounter 0 int//以後ずっと変わらず
recvbuf 0x003bf88c "1 200 O" char *//以後ヘッダ8バイトずつ読み込まれていく
header_buff 0x01263380 "HTTP/1." char [4096]//以後ずっと変わらず
少し分からり辛いですが、なぜこうなるか推測できますか?
あと読み込みって8バイトですか?本当に?
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 19:01
by softya(ソフト屋)
新月獅子 さんが書きました:関係あるのか知りませんが、WSAStartupを二回呼んでいるのはなぜ?
本当ですね。見逃していました。
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 21:41
by helloworld1853
>あと読み込みって8バイトですか?本当に?
7バイトでした。
あと
WSAStartup(MAKEWORD(2,0), &wsadata);
WSAStartup(MAKEWORD(1,1), &wsadata);
どちらのほうがいいのでしょうか。
より多くのパソコンに対応できるほうがいいです。
この問題の原因ですが、
if(recvbuf[recvcounter+3]==0x0A)
らへんに問題があると思いました。
たとえばrecvcounterが5だったら
recvbuf[8]という存在しない配列を
判定することになり
プログラムがおかしくなると
思いました。
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 21:50
by softya(ソフト屋)
7バイトですね。1バイトでも違うと大問題ですから思い込みは危険です。
それとrecvcounterが5だったらif(recvbuf[recvcounter+3]==0x0A)は危険ですね。それは間違いないのですが実は別の問題があります。
問題を明確にするために
コード:
#if 0
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+1]==0x0A)//空行判定(\n)
{
if(recvbuf[recvcounter+1]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+1]==0x0A)//空行判定(\n)
{
check=0;
return 0;//空行に達したら終了
}
}
}
}
#endif
で機能を一時的に無効にしてheader_buffの問題から片づけましょう。
どういう問題があるでしょうか?
return -1;で戻るときのheader_buff、headercounter、recvcounterの値に注目して下さい。
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 22:28
by helloworld1853
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+1]==0x0D)//空行判定(\n)
if(recvbuf[recvcounter+2]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+3]==0x0D)//空行判定(\n)
にしたほうがよいという意味ですか。
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 22:32
by softya(ソフト屋)
helloworld1853 さんが書きました:if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+1]==0x0D)//空行判定(\n)
if(recvbuf[recvcounter+2]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+3]==0x0D)//空行判定(\n)
にしたほうがよいという意味ですか。
recvbuf[recvcounter]の改行チェックは一旦忘れて他のことに目を向けましょうって事です。
#if 0~#endifで囲まれたソースコードは無効になるので、そう提案させて頂きました。
と言うか最新のコードはどうなっているんでしょうか?
【追記】
あと忘れてましたがWinsockは2.0で良いです。Windows98時代からありますから。
Re: 改行判定につまづいている
Posted: 2012年5月31日(木) 22:42
by helloworld1853
すみません。
気なっていたので・・・
最新のソースコードは
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+1]==0x0D)//空行判定(\n)
if(recvbuf[recvcounter+2]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+3]==0x0D)//空行判定(\n)
です。これ以外の変更は特にありません。
あと、
recvbuf 0x00000003 <不適切な Ptr> char *
とはどういう意味ですか。
Re: 改行判定につまづいている
Posted: 2012年6月01日(金) 00:00
by softya(ソフト屋)
helloworld1853 さんが書きました:すみません。
気なっていたので・・・
最新のソースコードは
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+1]==0x0D)//空行判定(\n)
if(recvbuf[recvcounter+2]==0x0D)//空行判定(\r)
if(recvbuf[recvcounter+3]==0x0D)//空行判定(\n)
です。これ以外の変更は特にありません。
0x0D 0x0A 0x0D 0x0A じゃないと改行コード\r\n\r\nじゃないですよ。
helloworld1853 さんが書きました:
あと、
recvbuf 0x00000003 <不適切な Ptr> char *
とはどういう意味ですか。
recvbufのポインタ値が不正って事です。正常なアドレスを指していませんよね。
Re: 改行判定につまづいている
Posted: 2012年6月01日(金) 16:28
by helloworld1853
>recvbufのポインタ値が不正って事です。正常なアドレスを指していませんよね。
これが原因でしょうか。
正直recvcounterとheadercounterがうまくデバッグできないので原因がよくわかりませんけど・・・
(recvcounterとheadercounterがともにずっと0です。
たぶんうまくデバッグできなかったんだろうと思いました。
なので
printf("%d\n"recvcounter);
などの処理を追加し、
確かめたところ正常な動作をしていました。少なくとも僕が見た感じでは・・・)
Re: 改行判定につまづいている
Posted: 2012年6月01日(金) 22:31
by softya(ソフト屋)
動作を書きだしてみてください。
いえ、こうしましょう。下記を埋めて下さい。2バッファまでです。
手書きでも良いし、この形式でprintfしてもらっても良いです。printfするときは文字(%c)だけでなく16進数(%02x)も表示して下さい。
コード:
[0][1][2][3][4][5][6][7][8][9][A][B][C][D][E][F]
--------------------------------------------------------------------------------
header_buff [H][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ] headercounter = 0
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 09:48
by へにっくす
softya(ソフト屋) さんが書きました:recvbuf[recvcounter]の改行チェックは一旦忘れて他のことに目を向けましょうって事です。
#if 0~#endifで囲まれたソースコードは無効になるので、そう提案させて頂きました。
と言うか最新のコードはどうなっているんでしょうか?
おそらく
が最新コードなのでしょうかね
のぞくと、何だかピントはずれですね
コード:
int MYroop(void)//空行判定する自作関数
{
if(check==0)//空行はすでに見つかっているとき
{
return 0;
}
for(;recvcounter!=sizeof(buf);++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
{
if(CHECKforMYroop==-1)
{
return 0;
}
else if(CHECKforMYroop==0)
{
forMYroop();
//CHECKforMYroop=0;
}
else if(CHECKforMYroop==1)
{
forMYroop1();
//CHECKforMYroop=0;
}
else if(CHECKforMYroop==2)
{
forMYroop2();
//CHECKforMYroop=0;
}
else if(CHECKforMYroop==3)
{
forMYroop3();
//CHECKforMYroop=0;
}
else
{
puts("異常事態が起きました。");
}
if(headercounter==4096)
{
printf("ヘッダが4096バイトを超えています。\n");
return -1;
}
header_buff[headercounter]=buf[recvcounter];//空行までのデータ つまりヘッダ部をheader_buffに1バイトずつ入力
}
return -1;
}
空行判定を関数にしても無意味です。とゆーか、しない方が賢明です。
よけいにわかりづらい。笑
softyaさんが言いたいのは、空行判定の部分は削除して、
いったんheader_buffにヘッダ部分が収まるかを確認せよと言ってるのです。
とりあえず以下のような感じかな?
コード:
int MYroop(void)//空行判定する自作関数
{
if(check==0)//空行はすでに見つかっているとき
{
return 0;
}
for(;recvcounter!=sizeof(buf);++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
{
#if 0 // デバッグのため、改行部分は無視
if(CHECKforMYroop==-1)
{
return 0;
}
else if(CHECKforMYroop==0)
{
forMYroop();
//CHECKforMYroop=0;
}
else if(CHECKforMYroop==1)
{
forMYroop1();
//CHECKforMYroop=0;
}
else if(CHECKforMYroop==2)
{
forMYroop2();
//CHECKforMYroop=0;
}
else if(CHECKforMYroop==3)
{
forMYroop3();
//CHECKforMYroop=0;
}
else
{
puts("異常事態が起きました。");
}
#endif
if(headercounter==4096)
{
printf("ヘッダが4096バイトを超えています。\n");
return -1;
}
header_buff[headercounter]=buf[recvcounter];//空行までのデータ つまりヘッダ部をheader_buffに1バイトずつ入力
}
return -1;
}
ヒントを言うと、recvcounterはbufのサイズ分なのだから、0に初期化するところがなければなりません。どこでしなければならないか?
がんばってください
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 22:16
by helloworld1853
softyaさん、へにっくすさん ありがとうございます。
ちなみに
http://s1.muryo-de.mydns.jp/~yamada_mam ... source.cpp
は最新ではありません。
このソースコードは\r\n\r\nが256Bをまたがった場合の対策を自分なりに作ったものです。
しかし、将来実装しなければいけないものなのでこちらのソースコードも
時間があればもう少し修正します。
さて結果なのです。
softyaさんがおっしゃった表示方法とは少し違いますが
結果を表示します。
左からheader_buff[headercounter],headercounter,header_buff[headercounter]の16進数を
表示しています。
WinSock初期化成功
send: 73
http recv data
=============================
header_buff[H] headercounter = 0 header_buffの16進数 = [48]
header_buff[T] headercounter = 1 header_buffの16進数 = [54]
header_buff[T] headercounter = 2 header_buffの16進数 = [54]
header_buff[P] headercounter = 3 header_buffの16進数 = [50]
header_buff[/] headercounter = 4 header_buffの16進数 = [2f]
header_buff[1] headercounter = 5 header_buffの16進数 = [31]
header_buff[.] headercounter = 6 header_buffの16進数 = [2e]
header_buff[ ] headercounter = 7 header_buffの16進数 = [00]
header_buff
headercounter = 8 header_buffの16進数 = [73]
header_buff[1] headercounter = 9 header_buffの16進数 = [31]
header_buff[.] headercounter = 10 header_buffの16進数 = [2e]
header_buff[m] headercounter = 11 header_buffの16進数 = [6d]
header_buff headercounter = 12 header_buffの16進数 = [75]
header_buff[r] headercounter = 13 header_buffの16進数 = [72]
header_buff[y] headercounter = 14 header_buffの16進数 = [79]
header_buff[o] headercounter = 15 header_buffの16進数 = [6f]
header_buff[ ] headercounter = 7 header_buffの16進数 = [00]
が原因のような気がします。
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 22:20
by helloworld1853
へにっくすさん すみません。
回答し忘れました。
>ヒントを言うと、recvcounterはbufのサイズ分なのだから、0に初期化するところがなければなりません。どこでしなければならないか?
for(;recvcounter!=sizeof(buf);++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
を
for(recvcounter=0;recvcounter!=sizeof(buf);++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
ですか。
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 22:27
by softya(ソフト屋)
そうです。
header_buff[ ] headercounter = 7 header_buffの16進数 = [00]
が問題ですね。
ただ、その後の文字も出鱈目な気がします。
何故こうなるのか推測はできますか?
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 22:43
by helloworld1853
見当違いかもしれませんが
何かがオーバーフロー
したと思いました。
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 22:50
by softya(ソフト屋)
helloworld1853 さんが書きました:見当違いかもしれませんが
何かがオーバーフロー
したと思いました。
MYroopの処理でご自分でこうなる様に書いているんですが、何故だかわかりませんか?
※ 決してオーバーフローしているわけではなく別の理由です。
header_buff[ ] headercounter = 7 header_buffの16進数 = [00]
の部分には本来は何が入るべきでしょうか?
意図した本来の動作は?
[補足]
これを入れてみてください。なお、改行コードは誤動作します。
printf( "header_buff[%d]=%c(%02x) ← recvbuf[%d]=%c(%02x)\n", headercounter, header_buff[headercounter], header_buff[headercounter], recvcounter, recvbuf[recvcounter], recvbuf[recvcounter] );
あと、BUF_SIZEを極端に2にしてみると分かりやすいかも知れません。
Re: 改行判定につまづいている
Posted: 2012年6月02日(土) 23:25
by へにっくす
helloworld1853 さんが書きました:>ヒントを言うと、recvcounterはbufのサイズ分なのだから、0に初期化するところがなければなりません。どこでしなければならないか?
for(;recvcounter!=sizeof(buf);++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
を
for(recvcounter=0;recvcounter!=sizeof(buf);++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
ですか。
その通りです。
まあ最新でないと言うことなので、他のコメントは避けます。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 00:57
by helloworld1853
ありがとうございます。
n = recv( sock, buf, sizeof(buf)-1, 0 );
を
n = recv( sock, buf, sizeof(buf), 0 );
になおした結果正しく動作しました。
これであっていますか。
ちなみにHTTP/1.1の後は
s1.muryo.etowns.net GET /~yamada_mama_papa/index.html HTTP/1.0 \nHost: s1.muryo.etowns.net \n \n
が表示されます。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 09:17
by softya(ソフト屋)
helloworld1853 さんが書きました:ありがとうございます。
n = recv( sock, buf, sizeof(buf)-1, 0 );
を
n = recv( sock, buf, sizeof(buf), 0 );
になおした結果正しく動作しました。
これであっていますか。
いいえ、それこそオーバーフローです。
元に戻して下さい。
そうするとマズイので-1したのでは無いですか?
それとも意味がわからずに-1したのでしょうか?
helloworld1853 さんが書きました:
ちなみにHTTP/1.1の後は
s1.muryo.etowns.net GET /~yamada_mama_papa/index.html HTTP/1.0 \nHost: s1.muryo.etowns.net \n \n
が表示されます。
ちがいます。
ここまで気づかないとすると困りましたね。
printf( "header_buff[%d]=%c(%02x) ← recvbuf[%d]=%c(%02x)\n", headercounter, header_buff[headercounter], header_buff[headercounter], recvcounter, recvbuf[recvcounter], recvbuf[recvcounter] );
の結果を教えて下さい。
あとBUF_SIZE 2にした場合も。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 10:04
by へにっくす
softya(ソフト屋) さんが書きました:MYroopの処理でご自分でこうなる様に書いているんですが、何故だかわかりませんか?
※ 決してオーバーフローしているわけではなく別の理由です。
header_buff[ ] headercounter = 7 header_buffの16進数 = [00]
の部分には本来は何が入るべきでしょうか?
意図した本来の動作は?
この質問に答えずに、なぜ
helloworld1853 さんが書きました:n = recv( sock, buf, sizeof(buf)-1, 0 );
を
n = recv( sock, buf, sizeof(buf), 0 );
になおした結果正しく動作しました。
の部分に行くのか理由を教えて。
貴方は理解しているつもりでしょうが、こちらには
全然そこに至った経緯が分からないので、その理解が正しいのか判定できません。
あと、正しく動作したと結論付けた理由も教えて。
#何だかどんどん悪い方向へ行っている気がします。…
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 15:17
by helloworld1853
[訂正]正しく動作した
というのはとんでもない見間違いでした。
過去3件のとんでもない僕のコメントは水に流してください。
結果を確認したところrecvcounterがおかしいことに気づきました。
早速
for(recvcounter=0;recvcounter<BUF_SIZE-1 ;++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
にソースコードを直し、
動作をチェックしました。
結果を下に残します。
WinSock初期化成功
send: 73
http recv data
=============================
header_buff[0]=H(48) ← recvbuf[0]=H(48)
header_buff[1]=T(54) ← recvbuf[0]=T(54)
header_buff[2]=T(54) ← recvbuf[0]=T(54)
header_buff[3]=P(50) ← recvbuf[0]=P(50)
header_buff[4]=/(2f) ← recvbuf[0]=/(2f)
header_buff[5]=1(31) ← recvbuf[0]=1(31)
header_buff[6]=.(2e) ← recvbuf[0]=.(2e)
header_buff[7]=1(31) ← recvbuf[0]=1(31)
header_buff[8]= (20) ← recvbuf[0]= (20)
header_buff[9]=2(32) ← recvbuf[0]=2(32)
header_buff[10]=0(30) ← recvbuf[0]=0(30)
header_buff[11]=0(30) ← recvbuf[0]=0(30)
header_buff[12]= (20) ← recvbuf[0]= (20)
header_buff[13]=O(4f) ← recvbuf[0]=O(4f)
header_buff[14]=K(4b) ← recvbuf[0]=K(4b)
(0d) ← recvbuf[0]=
header_buff[16]=
(0a) ← recvbuf[0]=
(0a)
header_buff[17]=D(44) ← recvbuf[0]=D(44)
header_buff[18]=a(61) ← recvbuf[0]=a(61)
header_buff[19]=t(74) ← recvbuf[0]=t(74)
header_buff[20]=e(65) ← recvbuf[0]=e(65)
header_buff[21]=:(3a) ← recvbuf[0]=:(3a)
header_buff[22]= (20) ← recvbuf[0]= (20)
header_buff[23]=S(53) ← recvbuf[0]=S(53)
header_buff[24]=u(75) ← recvbuf[0]=u(75)
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 15:26
by softya(ソフト屋)
そうですね。限定的にはOKです。
ただ、recvが必ずBUF_SIZE-1のサイズを返すと思っているのなら大きな勘違いです。可変する前提で組んでみてください。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 16:39
by helloworld1853
int recvsize;//送信するときも受信するときも変数nを使うとまずい気がするので設置
というグローバル変数を設置し,
recvsize = recv( sock, buf,BUF_SIZE-1, 0 );//nの代わりにrecvsizeを設置
MYroop内のループを
for(recvcounter=0;recvcounter<recvsize ;++recvcounter,++headercounter)
に変更しました。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 16:45
by softya(ソフト屋)
これでheader_buffにはちゃんとヘッダが貯まると思います。
で、今度はヘッダの終わりを検知しないと行けません。
一番簡単な方法は、毎回MYroopの最後にheader_buffに溜まった全てを0~headercounterまでループして\r\n\r\nを探し出す方法です。
効率的には無駄ですが確実なのでこれを行なってみてください。
ちなみにBUF_SIZEは256とか512にしておいてくださいね。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 17:09
by helloworld1853
関数を作りました。
この関数は空行を探します。
コード:
int Mysearch()
{
int headercounter_MYsearch;
int header_buff_size = sizeof(header_buff);
for(headercounter_MYsearch = 0;headercounter_MYsearch<=header_buff_size;++headercounter_MYsearch)
{
if(header_buff[headercounter_MYsearch]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+1]==0x0A)//空行判定(\n)
{
if(header_buff[headercounter_MYsearch+2]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+3]==0x0A)//空行判定(\n)
{
check=0;
real_header_buff[headercounter_MYsearch] = '\0';
return 0;//空行に達したら終了
}
}
}
}
real_header_buff[headercounter_MYsearch]=header_buff[headercounter_MYsearch];
}
return 0;
}
動作結果
WinSock初期化成功
send: 73
http recv data
=============================
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
ヘッダが4096バイトを超えています。
結局改行は発見できませんでした。
HTTP/1.1 200 OK
Date: Sun, 03 Jun 2012 08:06:41 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_
ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
Content-Type: text/html続行するには何かキーを押してください . . .
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 17:13
by softya(ソフト屋)
なにか全体がどうなっているか不明なので全体を添付して下さい。
あと、int header_buff_size = sizeof(header_buff);だとデータが無効な部分も検索すると思いますが。
ヘッダが4096バイト固定なわけはないので。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 18:17
by helloworld1853
ソースコードです。
新たに
int header_buff_size = sizeof(header_buff);
を
int header_buff_size = strlen(header_buff);
に変更しました。
コード:
#pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#define BUF_SIZE (256)
int recvcounter;
int recvsize;
int headercounter=0;//何度もループさせることが予想されるのでheadercounterを設置
//headercounterはMYroopに関係なく動作するのでMYroopの外に書く
char real_header_buff[4096];
char header_buff[4096];
//char body[256];//この中にボディ部を入れる
int check=-1;//checkは空行がすでに見つかっているか判断する
//check==-1のとき、空行はまだ見つかっていない
//check==0のとき、空行はすでに見つかっている
int Mysearch()
{
int headercounter_MYsearch;
int header_buff_size = strlen(header_buff);
for(headercounter_MYsearch = 0;headercounter_MYsearch<=header_buff_size;++headercounter_MYsearch)
{
if(header_buff[headercounter_MYsearch]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+1]==0x0A)//空行判定(\n)
{
if(header_buff[headercounter_MYsearch+2]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+3]==0x0A)//空行判定(\n)
{
check=0;
real_header_buff[headercounter_MYsearch] = '\0';
return 0;//空行に達したら終了
}
}
}
}
real_header_buff[headercounter_MYsearch]=header_buff[headercounter_MYsearch];
}
return 0;
}
int MYroop(char recvbuf[BUF_SIZE])//空行判定する自作関数
{
if(check==0)//空行はすでに見つかっているときまたは4096バイトを超えたとき
{
return 0;
}
for(recvcounter=0;recvcounter<recvsize ;++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
{
# if 0
if(recvbuf[recvcounter]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+1]==0x0A)//空行判定(\n)
{
if(recvbuf[recvcounter+2]==0x0D)//空行判定(\r)
{
if(recvbuf[recvcounter+3]==0x0A)//空行判定(\n)
{
check=0;
return 0;//空行に達したら終了
}
}
}
}
#endif
if(headercounter==4096)
{
//puts("ヘッダが4096バイトを超えています。");
check=0;
return -1;
}
header_buff[headercounter]=recvbuf[recvcounter];//空行までのデータ つまりヘッダ部をheader_buffに1バイトずつ入力
//printf("header_buff");
//printf( "header_buff[%d]=%c(%02x) ← recvbuf[%d]=%c(%02x)\n", headercounter, header_buff[headercounter], header_buff[headercounter], recvcounter, recvbuf[recvcounter], recvbuf[recvcounter] );
//Sleep(1000);
}
return -1;
}
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
char ServerName[] = "s1.muryo.etowns.net"; // 接続先のホスト名
WORD wVersionRequested = MAKEWORD(1,1);
WSADATA wsadata;
//WSAStartup(MAKEWORD(2,0), &wsadata);
int nErrorStatus;
PHOSTENT phostent; // サーバの情報を指すポインタ
unsigned long ulIPAddress;// サーバのIPアドレス格納変数
nErrorStatus = WSAStartup(wVersionRequested, &wsadata);
if(atexit((void (*)(void))(WSACleanup)))
{ // 終了時にWinSockのリソースを解放
printf("atexit(WSACleanup)失敗\n");
return -1;
}
if(nErrorStatus != 0)
{
printf("初期化失敗です\n");
return -1;
}
else
{
if(LOBYTE( wsadata.wVersion ) == 1
&& HIBYTE( wsadata.wVersion ) == 1)
{ // 要求したバージョンと同一か確認
printf("WinSock初期化成功\n");
}
else
{
printf("WinSock初期化失敗です\n");
return -1;
}
}
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if(sock == INVALID_SOCKET)
{
printf("ソケット作成失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
return -1;
}
// サーバのIPアドレス取得
ulIPAddress = inet_addr(ServerName); // IPアドレス取得
// inet_addr()関数が失敗 ServerNameがホスト名であった場合下の処理に入る
if(ulIPAddress == -1)
{
if( (phostent = gethostbyname(ServerName)) != NULL)
{
ulIPAddress = *((unsigned long *)(phostent->h_addr));
}
else
{
printf("ホストアドレス取得失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock); // ソケットの破棄
return -1;
}
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ulIPAddress;
addr.sin_port = htons(80);
//sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 )
{
printf( "HTTPポートが開けません。\n" );
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock);
return -1;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n =send( sock, get, strlen(get), 0 );
if(n != SOCKET_ERROR)
{
printf( "send: %d\n", n );
}
else
{
printf("サーバへの送信失敗です\n");
printf("エラー%dが発生しました\n", WSAGetLastError());
shutdown(sock, SD_BOTH); // 送受信を無効にする
closesocket(sock); // ソケットの破棄
return -1;
}
char buf[BUF_SIZE];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 )//256バイトずつ受信
{
recvsize = recv( sock, buf,BUF_SIZE-1, 0 );
if ( recvsize <= 0 )//#######ここでとまっている#######
{
if(check==0)
{
puts("改行判定成功!!!");
}
else
{
puts("結局改行は発見できませんでした。");
}
break;
}
buf[ recvsize ] = '\0';
MYroop(buf);
}
puts("1");
Mysearch();
printf(real_header_buff);
closesocket( sock );
return 0;
}
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 18:26
by softya(ソフト屋)
やはりと言うか、タイミングが問題ですね。
MysearchとMYroopはセットで使って下さい。このタイミングでヘッダ識別しないと意味が無いので。
あと調べるのが主なので
real_header_buff[headercounter_MYsearch]=header_buff[headercounter_MYsearch];
のコピーはいらないです。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 18:43
by へにっくす
MysearchとMYroopをセットにできたら、もう一度ソースを掲示した方がよいと思いますよ。
===
ヘッダーの取り出しはあと少し。これが終わったら今度は本題であるボディ部の取り出しですね。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 18:49
by helloworld1853
たとえば
header_buffから範囲を指定して
printfで表示できるようにする関数はありますか。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 18:53
by softya(ソフト屋)
printf("%13s",header_buff);とかすれば途中までは表示できます。
開始ポイントはポインタ演算なのでheader_buff+nで開始位置を調整します。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 21:04
by helloworld1853
>MysearchとMYroopをセットにできたら、もう一度ソースを掲示した方がよいと思いますよ。
207行目のMysearch();
を205行目MYroopの直後に移動しただけで修正が終わってしまいました。(これはセットしたといいますか。)
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 21:53
by softya(ソフト屋)
helloworld1853 さんが書きました:>MysearchとMYroopをセットにできたら、もう一度ソースを掲示した方がよいと思いますよ。
207行目のMysearch();
を205行目MYroopの直後に移動しただけで修正が終わってしまいました。(これはセットしたといいますか。)
本当に問題がないのでしょうか?
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 22:37
by helloworld1853
あとはreal_header_buffの修正ですよね。
ほかにもあるのならばコメントお願いします。
修正した後、ソースコードをすべて載せます。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 22:40
by softya(ソフト屋)
helloworld1853 さんが書きました:あとはreal_header_buffの修正ですよね。
ほかにもあるのならばコメントお願いします。
修正した後、ソースコードをすべて載せます。
header_buffがあるならreal_header_buffは不要です。
それとちゃんとヘッダの終わりを見つけて、\0を適切な場所に入れてくれればOKです。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 22:44
by helloworld1853
最終ソースコードです。
動作確認済み
コード:
#pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#define BUF_SIZE (256)
int recvcounter;
int recvsize;
int headercounter=0;//何度もループさせることが予想されるのでheadercounterを設置
//headercounterはMYroopに関係なく動作するのでMYroopの外に書く
int headercounter_MYsearch;
char header_buff[4096];
int check=-1;//checkは空行がすでに見つかっているか判断する
//check==-1のとき、空行はまだ見つかっていない
//check==0のとき、空行はすでに見つかっている
int Mysearch()
{
int header_buff_size = strlen(header_buff);
for(headercounter_MYsearch = 0;headercounter_MYsearch<=header_buff_size;++headercounter_MYsearch)
{
if(header_buff[headercounter_MYsearch]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+1]==0x0A)//空行判定(\n)
{
if(header_buff[headercounter_MYsearch+2]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+3]==0x0A)//空行判定(\n)
{
check=0;
header_buff[headercounter_MYsearch] = '\0';
return 0;//空行に達したら終了
}
}
}
}
}
return 0;
}
int MYroop(char recvbuf[BUF_SIZE])//空行判定する自作関数
{
if(check==0)//空行はすでに見つかっているときまたは4096バイトを超えたとき
{
return 0;
}
for(recvcounter=0;recvcounter<recvsize ;++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
{
if(headercounter==4096)
{
puts("ヘッダが4096バイトを超えています。");
check=0;
return -1;
}
header_buff[headercounter]=recvbuf[recvcounter];//空行までのデータ つまりヘッダ部をheader_buffに1バイトずつ入力
}
return -1;
}
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
char ServerName[] = "s1.muryo.etowns.net"; // 接続先のホスト名
WORD wVersionRequested = MAKEWORD(1,1);
WSADATA wsadata;
//WSAStartup(MAKEWORD(2,0), &wsadata);
int nErrorStatus;
PHOSTENT phostent; // サーバの情報を指すポインタ
unsigned long ulIPAddress;// サーバのIPアドレス格納変数
nErrorStatus = WSAStartup(wVersionRequested, &wsadata);
if(atexit((void (*)(void))(WSACleanup)))
{ // 終了時にWinSockのリソースを解放
printf("atexit(WSACleanup)失敗\n");
return -1;
}
if(nErrorStatus != 0)
{
printf("初期化失敗です\n");
return -1;
}
else
{
if(LOBYTE( wsadata.wVersion ) == 1
&& HIBYTE( wsadata.wVersion ) == 1)
{ // 要求したバージョンと同一か確認
printf("WinSock初期化成功\n");
}
else
{
printf("WinSock初期化失敗です\n");
return -1;
}
}
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if(sock == INVALID_SOCKET)
{
printf("ソケット作成失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
return -1;
}
// サーバのIPアドレス取得
ulIPAddress = inet_addr(ServerName); // IPアドレス取得
// inet_addr()関数が失敗 ServerNameがホスト名であった場合下の処理に入る
if(ulIPAddress == -1)
{
if( (phostent = gethostbyname(ServerName)) != NULL)
{
ulIPAddress = *((unsigned long *)(phostent->h_addr));
}
else
{
printf("ホストアドレス取得失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock); // ソケットの破棄
return -1;
}
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ulIPAddress;
addr.sin_port = htons(80);
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 )
{
printf( "HTTPポートが開けません。\n" );
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock);
return -1;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n =send( sock, get, strlen(get), 0 );
if(n != SOCKET_ERROR)
{
printf( "send: %d\n", n );
}
else
{
printf("サーバへの送信失敗です\n");
printf("エラー%dが発生しました\n", WSAGetLastError());
shutdown(sock, SD_BOTH); // 送受信を無効にする
closesocket(sock); // ソケットの破棄
return -1;
}
char buf[BUF_SIZE];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 )//256バイトずつ受信
{
recvsize = recv( sock, buf,BUF_SIZE-1, 0 );
if ( recvsize <= 0 )
{
if(check==0)
{
puts("改行判定成功!!!");
}
else
{
puts("結局改行は発見できませんでした。");
}
break;
}
buf[ recvsize ] = '\0';
MYroop(buf);
Mysearch();
}
printf("%s",header_buff);
closesocket( sock );
return 0;
}
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 22:48
by softya(ソフト屋)
ソースコードだけでなく、動作報告も欲しいのですが未完成な部分は置いておいて狙い通り動いてるんでしょうか?
私ではなくhelloworld1853さんが把握していなければいけない問題なんですよ。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 22:51
by helloworld1853
動作結果はバッチしだと思います。
WinSock初期化成功
send: 73
http recv data
=============================
改行判定成功!!!
HTTP/1.1 200 OK
Date: Sun, 03 Jun 2012 13:50:00 GMT
Server: Apache/1.3.33 (Unix) (Vine/Linux) mod_throttle/3.1.2 mod_layout/3.2 mod_gzip/1.3.26.1a mod_
ssl/2.8.22 OpenSSL/0.9.7d
X-Powered-By: ModLayout/3.2
Cache-Control: no-cache
Connection: close
Content-Type: text/html続行するには何かキーを押してください . . .
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 22:58
by softya(ソフト屋)
そうですね。ここまではOKだと思います。
グローバル変数多数でメンテナンス性がやっかいなプログラムではありますがそれは今後のhelloworld1853さんの課題です。
さて、ヘッダが判定できたので直後からボディ部です。
今回の場合は、いきなりヘッダ部の終わりで一度受信が中断しているものが私のところでは受信されましたが、いつもこうなるとは限りません。
ボディ部とヘッダを分離する処理を組みましょう。
header_buff[headercounter_MYsearch] = '\0';
と代入している所から+4のところがボディ部のスタート点となります。
そこからすぐボディ部が始まるか次の受信から始まるかは運次第なので両方共に耐えらる組み方をして下さい。
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 23:17
by helloworld1853
-----------削除しました。-----------
Re: 改行判定につまづいている
Posted: 2012年6月03日(日) 23:26
by helloworld1853
まったく関係ないし どうでもいい話ですが
最新記事を僕が書いたのですが
なぜかsoftyaさんのままになっています。
phpにあまり詳しくないのですがたぶんバグだと思います。
たぶんこのコメントをのせたら直ると思います。
なのでこのコメントを無視してください。
Re: 改行判定につまづいている
Posted: 2012年6月04日(月) 00:19
by softya(ソフト屋)
helloworld1853 さんが書きました:softyaさんがおっしゃる
"すぐボディ部が始まる"
プログラムの組み方はわかるのですが、
"次の受信から始まる"
場合のプログラムの流れを教えてください。
次のrecvから始まるので、今回のrecvしたbufにはヘッダしか含まれていない場合があると言うことです。
なのでbody処理をスキップするが正解です。あるいは0バイトして処理するですね。
Re: 改行判定につまづいている
Posted: 2012年6月04日(月) 23:42
by へにっくす
今のソースはヘッダ部をバッファに入れてるだけだから、今度はボディ部ですね。
header_buffと同じように
body_buffを作ってみるとか?
checkで空行かどうかをいれてるから、
その判定で格納場所(header_buffかbody_buff)を切り替えられるでしょ
Re: 改行判定につまづいている
Posted: 2012年6月08日(金) 21:16
by helloworld1853
風邪を引いてしまいまして
だいぶ期間があきましたが、
完成しました。
最近風邪がはやっているようなので皆様もお気をつけてください。
さて、softyaさん、へにっくすさんのアドバイスをこのプログラムに生かさせていただきました。
ボディ部が0バイト、1バイトのページとindex.htmlにおいて動作確認済みです。
コード:
#pragma comment(lib, "ws2_32.lib")
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#define BUF_SIZE (256)
int recvcounter;
int recvsize;
int headercounter=0;//何度もループさせることが予想されるのでheadercounterを設置
//headercounterはMYroopに関係なく動作するのでMYroopの外に書く
int headercounter_MYsearch;
char header_buff[4096];
char body_buff[4096];
int body_buff_counter=0;
int check=-1;//checkは空行がすでに見つかっているか判断する
//check==-1のとき、空行はまだ見つかっていない
//check==0のとき、空行はすでに見つかっている
int Mysearch()
{
int header_buff_size = strlen(header_buff);
for(headercounter_MYsearch = 0;headercounter_MYsearch<=header_buff_size;++headercounter_MYsearch)
{
if(check == 0)
{
body_buff[body_buff_counter] = header_buff[headercounter_MYsearch];
++body_buff_counter;
}
if(check == -1)
{
if(header_buff[headercounter_MYsearch]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+1]==0x0A)//空行判定(\n)
{
if(header_buff[headercounter_MYsearch+2]==0x0D)//空行判定(\r)
{
if(header_buff[headercounter_MYsearch+3]==0x0A)//空行判定(\n)
{
check=0;
header_buff[headercounter_MYsearch] = '\0';
headercounter_MYsearch += 3;
if(headercounter_MYsearch == header_buff_size)//ここからが空行直後にボディ部が始まる場合のときの対策
{ //もし現在のカウンタ位置が受信したデータ位置の最後だったら
return 0; //強制終了
}
}
}
}
}
}
}
printf("%s",body_buff);
return 0;
}
int MYroop(char recvbuf[BUF_SIZE])//空行判定する自作関数
{
for(recvcounter=0;recvcounter<recvsize ;++recvcounter,++headercounter)//何度もループさせることが予想されるのでheadercounterを設置
{
if(headercounter==4096)
{
return -1;
}
header_buff[headercounter]=recvbuf[recvcounter];//
}
return 0;
}
int main( void )
{
int sock, ret;
struct sockaddr_in addr;
char ServerName[] = "s1.muryo.etowns.net"; // 接続先のホスト名
WORD wVersionRequested = MAKEWORD(1,1);
WSADATA wsadata;
//WSAStartup(MAKEWORD(2,0), &wsadata);
int nErrorStatus;
PHOSTENT phostent; // サーバの情報を指すポインタ
unsigned long ulIPAddress;// サーバのIPアドレス格納変数
nErrorStatus = WSAStartup(wVersionRequested, &wsadata);
if(atexit((void (*)(void))(WSACleanup)))
{ // 終了時にWinSockのリソースを解放
printf("atexit(WSACleanup)失敗\n");
return -1;
}
if(nErrorStatus != 0)
{
printf("初期化失敗です\n");
return -1;
}
else
{
if(LOBYTE( wsadata.wVersion ) == 1
&& HIBYTE( wsadata.wVersion ) == 1)
{ // 要求したバージョンと同一か確認
printf("WinSock初期化成功\n");
}
else
{
printf("WinSock初期化失敗です\n");
return -1;
}
}
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if(sock == INVALID_SOCKET)
{
printf("ソケット作成失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
return -1;
}
// サーバのIPアドレス取得
ulIPAddress = inet_addr(ServerName); // IPアドレス取得
// inet_addr()関数が失敗 ServerNameがホスト名であった場合下の処理に入る
if(ulIPAddress == -1)
{
if( (phostent = gethostbyname(ServerName)) != NULL)
{
ulIPAddress = *((unsigned long *)(phostent->h_addr));
}
else
{
printf("ホストアドレス取得失敗です。\n");
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock); // ソケットの破棄
return -1;
}
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ulIPAddress;
addr.sin_port = htons(80);
ret = connect( sock, (struct sockaddr *)&addr, sizeof addr );
if ( ret < 0 )
{
printf( "HTTPポートが開けません。\n" );
printf("エラー%dが発生しました。\n", WSAGetLastError());
closesocket(sock);
return -1;
}
char get[] = "GET /~yamada_mama_papa/index.html HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n\r\n";
int n;
n =send( sock, get, strlen(get), 0 );
if(n != SOCKET_ERROR)
{
printf( "send: %d\n", n );
}
else
{
printf("サーバへの送信失敗です\n");
printf("エラー%dが発生しました\n", WSAGetLastError());
shutdown(sock, SD_BOTH); // 送受信を無効にする
closesocket(sock); // ソケットの破棄
return -1;
}
char buf[BUF_SIZE];
printf( "http recv data\n" );
printf( "=============================\n" );
while ( 1 )//256バイトずつ受信
{
recvsize = recv( sock, buf,BUF_SIZE-1, 0 );
if ( recvsize <= 0 )
{
if(check==0)
{
puts("改行判定成功!!!");
}
else
{
Mysearch();
if(check == 0)
{
puts("改行判定成功!!!");
}
else
{
puts("結局改行は発見できませんでした。");
}
}
break;
}
buf[ recvsize ] = '\0';
if(check==-1)//空行がまだ発見されていなければ
{
if(MYroop(buf)==-1)//4096バイトを超えたら
{
Mysearch();
}
}
if(check==0)//空行がすでに発見されていれば・・・
{
printf("%s",buf);
}
}
closesocket( sock );
return 0;
}
Re: 改行判定につまづいている
Posted: 2012年6月08日(金) 21:39
by softya(ソフト屋)
OKだと思います。
とりあえずご苦労様でした。
今後も機能追加するなら、
(1)グローバル変数を止めて引数と戻り値で処理する。
(2)無駄な処理を無くす。
(3)strcatなどの標準ライブラリを利用すること考える。
をご検討下さいね。
Re: 改行判定につまづいている
Posted: 2012年6月08日(金) 21:48
by helloworld1853
長い間ありがとうございます。
とりあえずプログラムも動作したので
ここで終わりにしたいと思います。
本当にありがとうございました。