|
|
|
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
| |
|
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に戻る
といった感じです。
アルゴリズムはいいと思うんですけど。
丸投げですいません。
誰かがエラーを修正して役立てることを期待しています。
最後に、長文ですいません。
そしてエラーが発生するようなプログラムですいません。
|
|
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のホームページは対応していないのでしょうか.
| |
|
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はクライアント側でどうすれば指定できますか.
|
|
2015/6/30(Tue) 00:59:05|NO.69893
ますます自分でもわからなくなってきたので質問をまとめますと
http1.0で通信する場合絶対にContent-Lengthをつけてもらうにはどうするか
http1.1で通信する場合ヘッダのTransfer-Encoding:(TE:)にどのような値をつけるとチャンクではなくContent-Lengthで返してもらえるか
の2つです
|
|
2015/6/30(Tue) 01:01:55|NO.69894
あと
チャンクとたまたまチャンクと似たようになっているファイルをどう区別して処理を分けるか
です
一人で大量に書きこんですみません
|
|
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ではチャンクはなくなりますが後ろにやはりごみがつきます
これはあなたのスクリプトに原因があると思います。
一番最初の質問にあるスクリプトを実行するとやはりゴミがついていますし。
ヌル文字を考慮してなんじゃないかと思います。
|
|
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
|
|
2015/6/30(Tue) 15:47:02|NO.69901
fohoさんありがとうございます.そこはあとで直そうと思い直すのを忘れていたところです.でもtmp.0+1と1を足さなくても受信したファイルにすでにテキストならヌル文字ががついているはずなのでわざわざヌル文字を足さなくてもいいと思います.
チャンクとそれによく似たファイルを見分けるというのは確かにヘッダで見分けられます.なぜか昨日はそこまで思えなく,そのことに今日気がついて書きこみました.意味のない質問をしてすみません.
ヌル文字でゴミを分けるというのは最初そうしようと思いましたがそれではバイナリであった場合には処理できないと思いやめにしました.具体的にはContent-Lengthがヘッダにない状態でバイナリを受信した場合バイナリと後ろのゴミを分けられないということです.
|
|
2015/6/30(Tue) 15:49:16|NO.69902
とりあえずヘッダでチャンクがついているかみわけてそれで処理をチャンクありチャンクなしで分ける方向でいこうと思います.
|
|
2015/6/30(Tue) 16:34:45|NO.69903
>fohoさんありがとうございます.そこはあとで直そうと思い直すのを忘れていたところです.
>でもtmp.0+1と1を足さなくても受信したファイルに
>すでにテキストならヌル文字ががついているはずなので
>わざわざヌル文字を足さなくてもいいと思います
テキストファイルでもバイナリでも最後にはヌル文字は含まれていません。
送られてきたデータに自分でヌル文字をつけるのが普通です。
Cなどではあらかじめ1バイト分だけ多めに確保してからデータを取得します。
もしかしてごみと思っているのは
ヌル終端されていない事による不定値なのではないでしょうか?
自分が調べたところチャンクの後に実際のデータがくると書かれていたので。
|
|
2015/6/30(Tue) 16:46:31|NO.69905
テキストファイルのEOFとヌル文字のことを混同していたようです.一応C言語もしたことがありますがテキストファイルしか処理したことがなかったので混同に気がつきませんでした.すみません.
|
|
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
| |
|
2015/6/30(Tue) 20:26:57|NO.69907
>ヌル文字でゴミを分けるというのは最初そうしようと思いましたがそれではバイナリであった場合には処理できないと思いやめにしました.具体的にはContent-Lengthがヘッダにない状態でバイナリを受信した場合バイナリと後ろのゴミを分けられないということです
何か勘違いしてると思います。
ゴミがつくのはスクリプトに問題があるからでサーバーから送られてくるデータにはゴミはついてないですよ。
>ヌル終端が何のことか調べてみましたがよくわかりませんでした.
文字の最後を表す文字コードが0の文字です。
http://www.onionsoft.net/hsp/v34/doclib/hsp3str.htm
|
|
2015/6/30(Tue) 20:34:17|NO.69908
それとついでに言うと、どうしてもHSPSOCKを使わなければいけない理由があるわけではないのなら
hspinetを使えばその辺の面倒な処理は全部やってくれますよ。
|
|
2015/7/1(Wed) 02:23:32|NO.69912
サーバーから送られてくるデータにゴミはついていなくて受信する際にゴミがつくのはわかりますがスクリプトのどこに問題があるのかが分かりません.ヌル終端が何のことかわかりません.
確かにhspinetのほうが簡単そうですがいまいちhspinetが理解できずそれならhspsockで実装したほうがいいと思ったからです.
|
|
2015/7/1(Wed) 02:26:07|NO.69913
バイナリで途中に0が含まれていた場合そこで読み込みがとまってしまいます.
|
|
2015/7/1(Wed) 02:31:11|NO.69914
hspinetが理解できないというのは変に遅かったりエラーが出たりするからです.
|
|
2015/7/1(Wed) 07:25:01|NO.69915
>ヌル終端が何のことか調べてみましたがよくわかりませんでした
他の方も書かれている通り、
文字列の最後にヌル文字(0x0)で終端されている事を言います。
>バイナリで途中に0が含まれていた場合そこで読み込みがとまってしまいます
読み込みサイズで判断するべき
|
|
2015/7/1(Wed) 08:42:58|NO.69916
skyblueさん,そのことはもうすでにわかっていてさきほど書いたように今読みこみサイズで判断できるように直しているところです.なのでだいじょうぶです.
|
|
2015/7/24(Fri) 21:21:15|NO.70221
今一応は完成しましたが各チャンクのサイズを正しく取得できないバグがあるので直しています。
|
|
2015/7/24(Fri) 21:22:05|NO.70222
すみません。NoapではなくNoaです。
|
|
2015/7/29(Wed) 11:29:52|NO.70301
チャンクを処理する部分のバグが直せずまた別の処理のしかたを思いついたのでいっかいその部分を書き直します。
|
|
2015/7/29(Wed) 19:17:51|NO.70304
16進法と10進法をまちがえていたことが原因でした。ようやく完成しました。この質問にこたえてくれて感謝します。
|
|
2015/7/29(Wed) 22:25:26|NO.70307
自己完結するのではなくて、完成したスクリプトを貼るのが
一応の礼儀だと思いますよ?
|
|
2015/7/30(Thu) 14:53:11|NO.70325
すみません。完成したスクリプトを貼るのを忘れていました。今は貼れないので少し待ってください。
|
|
2015/7/30(Thu) 15:14:32|NO.70326
すみません。長すぎてうまく貼れませんでした。今試してもうまく貼れませんでした。ホームページにアップロードしてそのURLを貼ろうとおもいます。指摘してくれてありがとうございます。
|
|
2015/7/30(Thu) 15:52:28|NO.70328
|
|
2015/8/3(Mon) 16:19:22|NO.70431
ヘッダとデータ本体の切り分け処理などでバグがあったので修正しました。URLは同じです。
|
|
2015/8/3(Mon) 19:26:50|NO.70435
チャンク処理でバグがあったので修正しました。URLは同じです。
|
|
2015/8/3(Mon) 19:27:54|NO.70436
NoapではなくNoaでした
|
|