HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2015
0628
NoaHSPSOCKでダウンロードしたデータにごみがよくつきます32解決


Noa

リンク

2015/6/28(Sun) 23:08:37|NO.69881

HSPでhspsockを使いダウンローダーのようなスクリプトを書いているのですが変な数字などが入ります.
例えば
http://www.onionsoft.net/ではウェブページ本体の前にfe7や1456,後ろに0が入り
http://www.yahoo.co.jp/ではウェブページ本体の前にdee,後ろに0が入りさらにその後ろになぞの文字が入ります.
これらは何なのでしょうか.またどうすればこれらのごみが入らないようにできますか.


#include "hspsock.as" #define PORT 80 //HTTPポート #define TMPSIZE 512 //一時領域のサイズ #define SOCKETN 0 //ソケット番号 sdim servername,256//サーバーの名前 sdim filepath,256//アクセスするファイルパス sdim url,256 sdim sdata sdim data dim error /* 0=正常 1=サーバー接続失敗 4=URLパースエラー */ dim tmp,3 *main url="about:blank" input url,ginfo_winx-40,20 mesbox sdata, ginfo_winx, ginfo_winy-40, 4 pos ginfo_winx-40, 0:objsize 40,20 button "→", *download stop *download if url="about:blank"{ objprm 1,"" color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "" stop } color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "お待ちください" error=0 dim tmp,3 tmp.2=strlen(url) //URLパース /* tmp.0=サーバー名とファイルパスの分け目 tmp.1=プロトコル名の文字数 tmp.2=URLの文字数 */ tmp.0=instr(url,,"://") if tmp.0==-1{ error=4 dialog "プロトコルが判別できません",1 stop }else{ if strmid(url,0,tmp.0)=="http"{ tmp.1=7 }else{ error=4 dialog "プロトコルはhttp1.1にしか対応していません",1 stop } } tmp.0=instr(url,tmp.1,"/") if tmp.0==-1{ tmp.0=tmp.2 url+="/"//ドメイン名の後のスラッシュを省略されていた場合にスラッシュをつける tmp.2++ }else{ tmp.0+=tmp.1 } memset servername,,256:memset filepath,,256//初期化 memcpy servername,url,tmp.0-tmp.1,,tmp.1 memcpy filepath,url,tmp.2-tmp.0,,tmp.0 sdim data,TMPSIZE sockopen SOCKETN,servername,PORT//サーバーに接続 if stat==0{ sockput "GET "+filepath+" HTTP/1.1\nHost:"+servername+"\n\n", SOCKETN//問い合わせ tmp.0=0//受信済サイズ tmp.1=0//タイムアウトの回数 repeat -1,1 memexpand data,cnt*TMPSIZE sockgetb data, tmp.0, TMPSIZE , SOCKETN if stat==0{ tmp.1++ if tmp.1==20 : break//0.2秒間受信しなければタイムアウト continue cnt } tmp.0+=stat wait 1 loop sdim sdata,tmp.0 sdata=data sdim data color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes ""+tmp.0+"バイト受信しました" }else{ error=1 color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "サーバーに接続できません" stop } sockclose SOCKETN objprm 1,sdata sdim sdata stop



この記事に返信する


totori

リンク

2015/6/29(Mon) 12:54:14|NO.69882

http://www.tohoho-web.com/ex/http.htm#chunk
チャンク形式じゃないですかね?
HTTP1.0で要求すれば、チャンク形式にはならなそう。



kanamaru

リンク

2015/6/29(Mon) 18:37:48|NO.69884

僕だったらこのぐらいならゴミを消すプログラムを作りますけど。
totoriさん、Transfer-Encodingを別のものにすれば、
HTTP1.1でも解決すると思います。
さて、自分で言っときながらいざ変換処理を書いてみたら
エラーが発生してしまいました。
エラー付ですが、
参考程度に乗せときます。

string="" mesbox string,640,240 button "convert",*c stop *c string2="" chunt=0 split string,"\n",ss ac=0 foreach ss if ss(ac)="":break ac++ await 1 loop *main byte=int("$"+ss(ac+1)) chunt++ sss="" sss2="" cc=0 repeat sss+=ss(ac+2+cc) if (cnt=0){sss2=ss(ac+2+cc)}else{sss2="\n"+ss(ac+2+cc)} if strlen(sss)=byte:break cc++ await 1 loop ac=ac+3+cc if (strlen(ss)-chunt!ac):goto *main objprm 0,sss2
長いプログラムですいません。
アルゴリズムを説明すると、
1、まず入力されたサーバーから返ってきた文字列を1行ずつ分ける
2.空行まで飛ばす(レスポンスヘッダとhttpヘッダを切り取るため)
3.切り取った一行めの16進法文字列を数字に変換
4.3で求めたバイト数だけ配列に代入
5.1で作った配列の長さ-3の回数=4の長さかどうか調べる
  成り立つようであれば4と同時に作っていた完成文字列を入力ボックスに表示
  成り立たなければ3に戻る
といった感じです。
アルゴリズムはいいと思うんですけど。
丸投げですいません。
誰かがエラーを修正して役立てることを期待しています。
最後に、長文ですいません。
そしてエラーが発生するようなプログラムですいません。



Noa

リンク

2015/6/29(Mon) 23:24:49|NO.69890

スクリプトを直してみました.
一応エラーはなくなり結果はちゃんとしています.
sdim string,1024*64//単純化するためにメモリは一括確保
mesbox string,640,240 button "convert",*c stop *c //string2="" chunt=0 split string,"\n",ss ac=0 foreach ss if ss(ac)="":break ac++ await 1 loop //この時点でac+1行目が空白 sdim sss repeat if ss(ac)==""{ byte=int("$"+ss(ac+1))//チャンクの数字をbyteに代入(チャンクの前に空行があるとき) cc=0 }else{ byte=int("$"+ss(ac))//(チャンクと本文の間に空行がないとき cc=-1 } if byte==0:break//チャンクが0であればデータの終わりを意味するため後ろについてくるのは無視 chunt++ //sss=0 sdim sss2,byte //cc=0 repeat //sss+=ss(ac+2+cc) if (cnt=0){ sss2=ss(ac+2+cc) }else{ sss2+="\n"+ss(ac+2+cc) } objprm 0,sss2 if strlen(sss2)=byte:break cc++ //await 1 loop sss+=sss2//求めたチャンクとチャンクの間の部分をつなげる ac=ac+3+cc if length(ss)==ac:break loop objprm 0,sss
でもこうするとたまたまファイルが同じようになっていた場合に正常に処理できない気がして不安です.
またhttp1.0ではチャンクはなくなりますが後ろにやはりごみがつきます.Content-Lengthで処理しようにもチャンクがContent-Lengthと同じような働きのためかチャンクがついてくるページではContent-Lengthがありません.なのでチャンクとたまたまファイルが同じようになっていた場合を区別する方法かhttp1.0でごみなしで通信する方法を教えてください.
また名前がNoapでなくNoaになっていましたが自分が混乱するのでNoaのままにします.
あとホームページ(というほどでもありませんが)のURLを書いたつもりがリンクが変なことになっています.掲示板にはhttps://から始まるURLのホームページは対応していないのでしょうか.



Noa

リンク

2015/6/29(Mon) 23:53:13|NO.69891

言葉下手なので分かりにくい文章になったので補足

今はじめてhttpの規格書をみました.
ダウンローダーをつくることが目標なのでバイナリにも対応させる予定なのでnotegetbを使っています.
http1.1の規格書の32ページの24行目にから26行目にContent-Lengthとチャンクは混ぜたらだめとかいてありました.

質問

13行目から19行目にはサーバーがhttp1.1互換だとわかっていなければちゃんとリクエストにContent-Lengthのヘッダーをつけないといけないとなっていますが逆(クライアントのほうがhttp1.0で要求してきたときにサーバー側はhttp1.0としてContent-Lengthをつけて返す)は規格にないのでしょうか.
kanamaruさんのおっしゃっていたTransfer-Encodingはクライアント側でどうすれば指定できますか.



Noa

リンク

2015/6/30(Tue) 00:46:58|NO.69892

"Transfer-Encodingはクライアント側でどうすれば指定できますか"というのはチャンクを使用する場合にTransfer-Encoding: chunkedならばContent-Lengthにしてほしい場合は後ろの部分を何にすればいいのですかという意味です.
Transfer-Encoding: Content-Lengthだとサーバー側がわからないと返してきました.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6などをみてTransfer-Encoding: Identifyなどにしてもだめでした.TE:でもだめでした.
https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-response-headerなどもみました.



Noa

リンク

2015/6/30(Tue) 00:59:05|NO.69893

ますます自分でもわからなくなってきたので質問をまとめますと

http1.0で通信する場合絶対にContent-Lengthをつけてもらうにはどうするか

http1.1で通信する場合ヘッダのTransfer-Encoding:(TE:)にどのような値をつけるとチャンクではなくContent-Lengthで返してもらえるか

の2つです



Noa

リンク

2015/6/30(Tue) 01:01:55|NO.69894

あと

チャンクとたまたまチャンクと似たようになっているファイルをどう区別して処理を分けるか

です
一人で大量に書きこんですみません



foho

リンク

2015/6/30(Tue) 02:42:32|NO.69895

>チャンクとたまたまチャンクと似たようになっているファイルをどう区別して処理を分けるか
質問の意味がよく分からないんですが。
たまたまチャンクと似たようになっているファイルってなんでしょう?
レスポンスヘッダにTransfer-Encoding: chunkedが含まれていればチャンクだとわかりますし、逆にそれ以外にファイルの内容などでチャンクだと判断することはできないとおもいますが。

>http1.0で通信する場合絶対にContent-Lengthをつけてもらうにはどうするか
>http1.1で通信する場合ヘッダのTransfer-Encoding:(TE:)にどのような値をつけるとチャンクではなくContent-Lengthで返してもらえるか
この答えはわかりませんが
>http1.0ではチャンクはなくなりますが後ろにやはりごみがつきます
これはあなたのスクリプトに原因があると思います。
一番最初の質問にあるスクリプトを実行するとやはりゴミがついていますし。
ヌル文字を考慮してなんじゃないかと思います。



foho

リンク

2015/6/30(Tue) 02:57:44|NO.69896

99行目に問題がありますね。

dim sdata,tmp.0 sdata=data sdim data ↓ sdim sdata,tmp.0+1 memcpy sdata,data,tmp.0 sdim data



Noa

リンク

2015/6/30(Tue) 15:47:02|NO.69901

fohoさんありがとうございます.そこはあとで直そうと思い直すのを忘れていたところです.でもtmp.0+1と1を足さなくても受信したファイルにすでにテキストならヌル文字ががついているはずなのでわざわざヌル文字を足さなくてもいいと思います.
チャンクとそれによく似たファイルを見分けるというのは確かにヘッダで見分けられます.なぜか昨日はそこまで思えなく,そのことに今日気がついて書きこみました.意味のない質問をしてすみません.
ヌル文字でゴミを分けるというのは最初そうしようと思いましたがそれではバイナリであった場合には処理できないと思いやめにしました.具体的にはContent-Lengthがヘッダにない状態でバイナリを受信した場合バイナリと後ろのゴミを分けられないということです.



Noa

リンク

2015/6/30(Tue) 15:49:16|NO.69902

とりあえずヘッダでチャンクがついているかみわけてそれで処理をチャンクありチャンクなしで分ける方向でいこうと思います.



skyblue

リンク

2015/6/30(Tue) 16:34:45|NO.69903

>fohoさんありがとうございます.そこはあとで直そうと思い直すのを忘れていたところです.
>でもtmp.0+1と1を足さなくても受信したファイルに
>すでにテキストならヌル文字ががついているはずなので
>わざわざヌル文字を足さなくてもいいと思います
テキストファイルでもバイナリでも最後にはヌル文字は含まれていません。
送られてきたデータに自分でヌル文字をつけるのが普通です。
Cなどではあらかじめ1バイト分だけ多めに確保してからデータを取得します。
もしかしてごみと思っているのは
ヌル終端されていない事による不定値なのではないでしょうか?
自分が調べたところチャンクの後に実際のデータがくると書かれていたので。



Noa

リンク

2015/6/30(Tue) 16:46:31|NO.69905

テキストファイルのEOFとヌル文字のことを混同していたようです.一応C言語もしたことがありますがテキストファイルしか処理したことがなかったので混同に気がつきませんでした.すみません.



Noa

リンク

2015/6/30(Tue) 17:45:50|NO.69906

ヌル終端が何のことか調べてみましたがよくわかりませんでした.
またとりあえず間違いを直してヘッダと本体を分けチャンクを使用しない場合だけを実装してみました.チャンクを使用する場合の処理はまだです.

#include "hspsock.as"
#define PORT 80 //HTTPポート #define TMPSIZE 512 //一時領域のサイズ #define SOCKETN 0 //ソケット番号 sdim servername,256//サーバーの名前 sdim filepath//アクセスするファイルパス sdim url sdim sdata sdim data sdim header dim error /* 0=正常 1=サーバー接続失敗 2=その他 4=URLパースエラー */ sdim stmp dim tmp,4 *main url="about:blank" input url,ginfo_winx-40,20,0 mesbox sdata, ginfo_winx/2, ginfo_winy-40, 4 pos ginfo_winx/2,20 mesbox header, ginfo_winx-ginfo_winx/2, ginfo_winy-40 ,4 pos ginfo_winx-40, 0:objsize 40,20 button "→", *download stop *download sendmsg objinfo_hwnd(0), $E, 0, 0 sdim url,stat+2 sendmsg objinfo_hwnd(0), $D, stat+1,varptr(url) if url="about:blank"{ objprm 1,"" color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "" stop } color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "お待ちください" error=0 dim tmp,3 tmp.2=strlen(url) //URLパース /* tmp.0=サーバー名とファイルパスの分け目 tmp.1=プロトコル名の文字数 tmp.2=URLの文字数 */ tmp.0=instr(url,,"://") if tmp.0==-1{ error=4 dialog "プロトコル部分がありません",1 stop }else{ if instr(url,,"http")==0{ tmp.1=7 }else{ error=4 dialog "プロトコルはhttp1.1にしか対応していません",1 stop } } tmp.0=instr(url,tmp.1,"/") if tmp.0==-1{ tmp.0=tmp.2 url+="/"//ドメイン名の後のスラッシュを省略されていた場合にスラッシュをつける http://xxx.com のように tmp.2++ }else{ tmp.0+=tmp.1 } if tmp.0-tmp.1>253{ error=4 dialog "ドメイン名が長すぎます.URLを確認してください",1 stop } memset servername,,256:sdim filepath,,tmp.2-tmp.0+1//初期化 memcpy servername,url,tmp.0-tmp.1,,tmp.1 memcpy filepath,url,tmp.2-tmp.0,,tmp.0 sockopen SOCKETN,servername,PORT//サーバーに接続 if stat==0{ sockput "GET "+filepath+" HTTP/1.1\nHost:"+servername+"\nConnection: close\n\n", SOCKETN//問い合わせ sdim data,TMPSIZE sdim header,TMPSIZE tmp.0=0//ヘッダーの受信済サイズ tmp.1=0//タイムアウトの回数 tmp.2=0//本文の受信済みサイズ -1ならヘッダーの受信が途切れた //ヘッダーの受信 repeat -1 memexpand header,TMPSIZE+tmp.0 sockgetb header, tmp.0, TMPSIZE , SOCKETN if stat==0{//break tmp.1++ if tmp.1==20 : tmp.2=-1 : break//0.2秒間受信しなければタイムアウト continue cnt } if instr(header,tmp.0,"\n\n")>=0{ //ヘッダーの受信のさい余った部分を本文側に移す tmp.2=stat-instr(header,tmp.0,"\n\n")-4 memcpy data,header,tmp.2,,instr(header,tmp.0,"\n\n")+4+tmp.0 tmp.0+=instr(header,tmp.0,"\n\n") poke header,tmp.0,0 break } tmp.0+=stat wait 1 loop if tmp.2!=-1{//ヘッダーをすべて受信できたなら //tmp3はチャンクを使用している場合はチャンクの数字,そうでない場合はContent-Lengthの値 if instr(header,0,"Transfer-Encoding: chunked")==-1{//チャンクでない場合 tmp.3=instr(header,0,"Content-Length:") if tmp.3>=0{ memset stmp,,64 if instr(header,tmp.3,"\n")==-1{//ないとは思うけどContent-Length:の行の後に改行がない場合 error=2 dialog "サーバーからの受信に失敗しました",1 stop } memcpy stmp,header,instr(header,tmp.3,"\n")-16,,tmp.3+16 tmp.3=int(stmp) //本文の受信 repeat -1 memexpand data,TMPSIZE+tmp.2 sockgetb data, tmp.2, TMPSIZE , SOCKETN if stat==0{//break tmp.1++ if tmp.1==20 : break//0.2秒間受信しなければタイムアウト continue cnt } tmp.2+=stat if tmp.2>=tmp.3:break wait 1 loop tmp.2=tmp.3 }else{//Transfer-Encoding: chunked も Content-Length: 何とか も指定されていない場合 error=2 dialog "サーバーからの受信に失敗しました",1 stop } }else{ //チャンクを使用している場合の処理(予定) tmp.3=0 repeat -1 memexpand data,TMPSIZE+tmp.2 sockgetb data, tmp.2, TMPSIZE , SOCKETN if stat==0{//break tmp.1++ if tmp.1==20 : break//0.2秒間受信しなければタイムアウト continue cnt } tmp.2+=stat wait 1 loop } } sdim sdata,tmp.2+1 memcpy sdata,data,tmp.2//sdata=data sdim data color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "ヘッダ:"+tmp.0+"バイト ファイルサイズ:"+tmp.2+"バイト" }else{ error=1 color 255,255,255 boxf 0,ginfo_winy-20,ginfo_winx,ginfo_winy color 0,0,0 pos 0,ginfo_winy-20 mes "サーバーに接続できません" stop } sockclose SOCKETN objprm 1,sdata objprm 2,header sdim sdata sdim header stop



foho

リンク

2015/6/30(Tue) 20:26:57|NO.69907

>ヌル文字でゴミを分けるというのは最初そうしようと思いましたがそれではバイナリであった場合には処理できないと思いやめにしました.具体的にはContent-Lengthがヘッダにない状態でバイナリを受信した場合バイナリと後ろのゴミを分けられないということです
何か勘違いしてると思います。
ゴミがつくのはスクリプトに問題があるからでサーバーから送られてくるデータにはゴミはついてないですよ。

>ヌル終端が何のことか調べてみましたがよくわかりませんでした.
文字の最後を表す文字コードが0の文字です。
http://www.onionsoft.net/hsp/v34/doclib/hsp3str.htm



foho

リンク

2015/6/30(Tue) 20:34:17|NO.69908

それとついでに言うと、どうしてもHSPSOCKを使わなければいけない理由があるわけではないのなら
hspinetを使えばその辺の面倒な処理は全部やってくれますよ。



Noa

リンク

2015/7/1(Wed) 02:23:32|NO.69912

サーバーから送られてくるデータにゴミはついていなくて受信する際にゴミがつくのはわかりますがスクリプトのどこに問題があるのかが分かりません.ヌル終端が何のことかわかりません.
確かにhspinetのほうが簡単そうですがいまいちhspinetが理解できずそれならhspsockで実装したほうがいいと思ったからです.



Noa

リンク

2015/7/1(Wed) 02:26:07|NO.69913

バイナリで途中に0が含まれていた場合そこで読み込みがとまってしまいます.



Noa

リンク

2015/7/1(Wed) 02:31:11|NO.69914

hspinetが理解できないというのは変に遅かったりエラーが出たりするからです.



skyblue

リンク

2015/7/1(Wed) 07:25:01|NO.69915

>ヌル終端が何のことか調べてみましたがよくわかりませんでした
他の方も書かれている通り、
文字列の最後にヌル文字(0x0)で終端されている事を言います。

>バイナリで途中に0が含まれていた場合そこで読み込みがとまってしまいます
読み込みサイズで判断するべき



Noa

リンク

2015/7/1(Wed) 08:42:58|NO.69916

skyblueさん,そのことはもうすでにわかっていてさきほど書いたように今読みこみサイズで判断できるように直しているところです.なのでだいじょうぶです.



Noap

リンク

2015/7/24(Fri) 21:21:15|NO.70221

今一応は完成しましたが各チャンクのサイズを正しく取得できないバグがあるので直しています。



Noa

リンク

2015/7/24(Fri) 21:22:05|NO.70222

すみません。NoapではなくNoaです。



Noa

リンク

2015/7/29(Wed) 11:29:52|NO.70301

チャンクを処理する部分のバグが直せずまた別の処理のしかたを思いついたのでいっかいその部分を書き直します。



Noa

リンク

2015/7/29(Wed) 19:17:51|NO.70304

16進法と10進法をまちがえていたことが原因でした。ようやく完成しました。この質問にこたえてくれて感謝します。



KA

リンク

2015/7/29(Wed) 22:25:26|NO.70307

自己完結するのではなくて、完成したスクリプトを貼るのが
一応の礼儀だと思いますよ?



Noa

リンク

2015/7/30(Thu) 14:53:11|NO.70325

すみません。完成したスクリプトを貼るのを忘れていました。今は貼れないので少し待ってください。



Noa

リンク

2015/7/30(Thu) 15:14:32|NO.70326

すみません。長すぎてうまく貼れませんでした。今試してもうまく貼れませんでした。ホームページにアップロードしてそのURLを貼ろうとおもいます。指摘してくれてありがとうございます。



Noa

リンク

2015/7/30(Thu) 15:52:28|NO.70328




Noa

リンク

2015/8/3(Mon) 16:19:22|NO.70431

ヘッダとデータ本体の切り分け処理などでバグがあったので修正しました。URLは同じです。



Noap

リンク

2015/8/3(Mon) 19:26:50|NO.70435

チャンク処理でバグがあったので修正しました。URLは同じです。



Noa

リンク

2015/8/3(Mon) 19:27:54|NO.70436

NoapではなくNoaでした



ONION software Copyright 1997-2023(c) All rights reserved.