charの00をプログラムが終了合図だと勘違いしてしまいます。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
helloworld1853
記事: 181
登録日時: 13年前

charの00をプログラムが終了合図だと勘違いしてしまいます。

#1

投稿記事 by helloworld1853 » 13年前

webサーバに画像をpostするソフトを作っているのですが、

流れとしては

まず、プログラムがtest.bmpをバイナリモードで開きデータをchar bodyに保存

char bodyをtest.cgiにpost

test.cgiがそれをもとにtest.bmpを作成

画像アップロード 成功!!

です。

画像のバイナリコードは

42 4D E4 0A 00 00 00 ・・・

です。

しかし、00の箇所をソケットの通信終了合図だと勘違いしてしまい、

結局画像は42 4D E4 0Aで止まってしまいます。

通信系のプログラミングはまだなれていないので

お手柔らかにお願いします。

コード:

#include <stdio.h>
#include <winsock2.h>

int main( void )
{
	int sock, ret;
	struct sockaddr_in addr;
	FILE *fp;
	char *fname = "test.bmp";
	char buf[100000];
	char body[100000];
	int  i;
	int size;

	WSADATA wsadata;
	WSAStartup( 0x0101, &wsadata );
	fp = fopen( fname, "rb" );
	size = fread( buf, sizeof( unsigned char ), 10000, fp );

	for( i=0; i<size; i++ )
	{
		
		printf( "%02X ", buf[i] );
	}
	puts("");

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("125.172.197.18");
	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;
	}
	sprintf(body,"namae=%s\r\n",buf);
	body[size+6]='\0';
	char head[] = "POST /~yamada_mama_papa/test.cgi HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n";
	char length[100];
	sprintf( length, "Content-Length: %d\r\n", strlen(body) );
	
	int n = 0;
	n += send( sock, head, strlen(head), 0 );
	n += send( sock, length, strlen(length), 0 );
	n += send( sock, "\r\n", 2, 0 );
	n += send( sock, body, strlen(body), 0 );
	printf( "send: %d\n", n );
	
	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 );
	fclose( fp );

}
以下がtest.cgi

コード:

#!/usr/local/bin/perl
use CGI;
$q = new CGI;
$Name = $q->param('namae');
print "Content-type: text/html\n\n";
print "<META http-equiv=\"Content-Type\" content=\"text/html; charset=Shift_JIS\">\n";
print $Name;
open (OUT,"> test.bmp");
print OUT $Name;
close (OUT);
print 'sucess';
exit;
[]/code]

よろしくお願いします。

tamaneko

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#2

投稿記事 by tamaneko » 13年前

初心者で提示ソースコードは高度で何をしているのかさっぱり分らないのですが、
表題の事が起こるのはバイナリデータを文字列操作関数で操作しているからではないですか?
文字列操作関数はバイナリの00を番兵とするって聞いたことがあります。
ソースコードは文字列操作関数だらけで、バイナリ操作の関数ぽいのかないので
そのように感じました。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#3

投稿記事 by h2so5 » 13年前

recvの戻り値で終了を判断せずとも、
ヘッダでBodyのサイズが分かるのだからそれを利用すればいいのではないでしょうか?


関係なさそうなので撤回します。
最後に編集したユーザー h2so5 on 2012年4月22日(日) 15:46 [ 編集 1 回目 ]

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#4

投稿記事 by helloworld1853 » 13年前

>初心者で提示ソースコードは高度で何をしているのかさっぱり分らないのですが、

僕のソースコードに無駄な部分が多いだけです。

あるソースコードを改造したものなので変な所もあるかもしれませんが

気にしないでください。

ソースコード・改です。

見やすくなったはずです。

コード:

#include <stdio.h>
#include <winsock2.h>

int main( void )
{
	int sock, ret;
	struct sockaddr_in addr;
	FILE *fp;
	char *fname = "test.bmp";
	char buf[100000];
	char body[100000];
	int  i;
	int size;

	WSADATA wsadata;
	WSAStartup( 0x0101, &wsadata );
	fp = fopen( fname, "rb" );
	size = fread( buf, sizeof( unsigned char ), 10000, fp );

	for( i=0; i<size; i++ )
	{
		
		printf( "%02X ", buf[i] );
	}
	puts("");

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("125.172.197.18");
	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;
	}
	sprintf(body,"namae=%s\r\n",buf);
	body[size+6]='\0';
	char head[] = "POST /~yamada_mama_papa/test.cgi HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n";
	char length[100];
	sprintf( length, "Content-Length: %d\r\n", strlen(body) );
	
	closesocket( sock );
	fclose( fp );

}
さて、バイナリ操作の関数が必要な用ですが、

具体的にどの関数をつかえばいいのでしょうか。

調べてみたのですが、なかなか見つかりません。

それとも関数を作らなければいけないのでしょうか。

正直あまり技術がないので、関数を設計したくないのですが・・・

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#5

投稿記事 by h2so5 » 13年前

helloworld1853 さんが書きました: 画像のバイナリコードは

42 4D E4 0A 00 00 00 ・・・

です。

しかし、00の箇所をソケットの通信終了合図だと勘違いしてしまい、

結局画像は42 4D E4 0Aで止まってしまいます。
どうしてそう判断されたのか教えてください。
このコードでは 42 4D E4 0A という形式ではデータが表示されません。実際の出力を書いてください。

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#6

投稿記事 by helloworld1853 » 13年前

>実際の出力を書いてください。

そんな高度な手法は使いませんでした。

http://s1.etowns.slyip.net/~yamada_mama_papa/test.bmp

に画像が生成されるのでそれを保存し、

バイナリエディタで開きました。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#7

投稿記事 by みけCAT » 13年前

試してはいません。

コード:

sprintf(body,"namae=%s\r\n",buf);

コード:

strcpy(body,"namae=");
memcpy(&body[6],buf,size);
memcpy(&body[6+size],"\r\n");
とし、

コード:

sprintf( length, "Content-Length: %d\r\n", strlen(body) );

コード:

sprintf( length, "Content-Length: %d\r\n", 6+size );
としたらどうですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#8

投稿記事 by helloworld1853 » 13年前

みけCATさんのお力を借りて修正しましたが

変わりませんでした。

僕がソースコードをいじくってしまったからかもしれません。

引数が少ないとコンパイラがほざきやがったので・・・

どういじくったのかというと・・・

コード:

strcpy(body,"namae=");
memcpy(&body[6],buf,size);
memcpy(&body[6+size],"\r\n");

コード:

strcpy(body,"namae=");
memcpy(&body[6],buf,size);
memcpy(&body[6+size],"\r\n",4);
にしました。

なにか間違って入れば教えてください。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#9

投稿記事 by みけCAT » 13年前

helloworld1853 さんが書きました:引数が少ないとコンパイラがほざきやがったので・・・
ごめんなさい、私のミスです。

コード:

memcpy(&body[6+size],"\r\n",4);
ではなく

コード:

memcpy(&body[6+size],"\r\n",2);
です。
No.4のソースコードを元にしています。
このソースコードには、送信部分が無いようですが、どうなっていますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#10

投稿記事 by helloworld1853 » 13年前

みけCAT さん

ありがとうございます。

重要なミスに気づきました。

送信部分がないですね・・・

正直はずかしいミスでした。

あと生成された画像のバイナリを

42 4D E4 0Aと書きましたが

実際は42 4D E4 0A 0D 0Aでした。

でいま送信部分を書き直して実行した結果、

バイナリデータが42 4D E4 0Aでした。

これも僕のミスです。

とにかく少し結果が改善されましたが

プログラムの勘違いはそのままです。

話がややこしくなっていますがお許しを

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#11

投稿記事 by みけCAT » 13年前

とりあえず現状のプログラムを貼ってみてもらえますか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#12

投稿記事 by helloworld1853 » 13年前

最終ソースコードです。

recvを使用した箇所は受信用なので省いてもいいと判断しました。

コード:

#include <stdio.h>
#include <winsock2.h>

int main( void )
{
	int sock, ret;
	struct sockaddr_in addr;
	FILE *fp;
	char *fname = "test.bmp";
	unsigned char buf[100000];
	char body[100000];
	int  i;
	int size;

	WSADATA wsadata;
	WSAStartup( 0x0101, &wsadata );
	fp = fopen( fname, "rb" );
	size = fread( buf, sizeof( unsigned char ), 100000, fp );

	for( i=0; i<size; i++ )
	{
		
		printf( "%02X ", buf[i] );
	}
	puts("");

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("125.172.197.18");
	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;
	}
	strcpy(body,"namae=");
	memcpy(&body[6],buf,size);
	memcpy(&body[6+size],"\r\n",2);

	body[size+6]='\0';

	char head[] = "POST /~yamada_mama_papa/test.cgi HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n";
	char length[100];
	sprintf( length, "Content-Length: %d\r\n", 6+size );
	int n=0;
	n+=send(sock,head,strlen(head),0);
	n+=send(sock,length,strlen(length),0);
	n+=send(sock,"\r\n",2,0);
	n+=send(sock,body,strlen(body),0);

	closesocket( sock );

	fclose( fp );

}

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#13

投稿記事 by helloworld1853 » 13年前

ほかの関数をつかうしか手がないのでしょうか。

それとも自作関数を用いる必要があるのでしょうか。

御回答をお待ちしております。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#14

投稿記事 by h2so5 » 13年前

strlenは文字列の長さを返す関数ですから、strlen(body)は適当ではないですね。
この場合、画像ファイルのサイズはsizeに入っているのではないでしょうか。

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#15

投稿記事 by YuO » 13年前

バイナリデータの取り扱い方を勉強する方が先のような気もしますが……。

バイナリデータの長さをデータから汎用的に知る方法はありません。
なので,「バイナリデータの長さを取得する関数」は存在しません。

基本的には,freadで読み込んだサイズだけsendすることになります。
sendは指定したサイズ丁度を送信するとは限らないため,部分的に送信していた場合は残りの部分を送信する,というコードも必要になります。
さらに,一回のfreadで全部を読み込んだとも限らないため,終了を検知するまでfreadする必要もあります。
# Content-Lengthに与える値は,FindFirstFile API等で知ることになります。

helloworld1853
記事: 181
登録日時: 13年前

Re: charの00をプログラムが終了合図だと勘違いしてしまいます。

#16

投稿記事 by helloworld1853 » 13年前

みなさまのおかげで無事完成しました。

本当に有難うございました。

ソースコードです。

コード:

#include <stdio.h>
#include <winsock2.h>

int main( void )
{
	int sock, ret;
	struct sockaddr_in addr;
	FILE *fp;
	char *fname = "test.bmp";
	unsigned char buf[100000];
	//char buf1[1000000];
	char body[100000];
	int  i;
	int size;
	//int counter;

	WSADATA wsadata;
	WSAStartup( 0x0101, &wsadata );
	fp = fopen( fname, "rb" );
	size = fread( buf, sizeof( unsigned char ), 100000, fp );

	for( i=0; i<size; i++ )
	{
		
		printf( "%02X ", buf[i] );
	}
	puts("");
	//PROC pfn0rig;
	//printf("%d\n",buf[5]);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("61.214.105.140");
	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;
	}
	strcpy(body,"namae=");
	memcpy(&body[6],buf,size);
	memcpy(&body[6+size],"\r\n",2);
	//sprintf(body,"namae=%s\r\n",buf);
	body[size+6]='\0';
	//puts("*****************************************************************************************");
	//printf( "%s ",body);
	//body[strlen(body)]='\0';
	//printf("%s",body);
	//char body[] = "namae=2222222222222222222222\r\n";
	char head[] = "POST /~yamada_mama_papa/test.cgi HTTP/1.0\r\nHost: s1.muryo.etowns.net\r\n";
	char length[100];
	sprintf( length, "Content-Length: %d\r\n", 6+size );
	int n=0;
	n+=send(sock,head,strlen(head),0);
	n+=send(sock,length,strlen(length),0);
	n+=send(sock,"\r\n",2,0);
	n+=send(sock,body,size,0);
	//char buf[256];
	//printf( "http recv data\n" );
	//printf( "=============================\n" );
	
	closesocket( sock );
	//close( sock );
	fclose( fp );

}


閉鎖

“C言語何でも質問掲示板” へ戻る