人生で一番お金がなかったとき

初めて投稿させていただきます。

現在、Cにてあるクライアントプログラムを作成している者です。
構成は以下の通り。

《構成》
サーバ:PLC(シーケンサと書けば大体の方はわかりますか?)
クライアント:Linux Ubuntu9.10
通信方式:TCP/IP

《開発環境》
言語:C
IDE:eclipse
コンパイラ:gcc 4.x

《質問》
クライアントプログラムからASCIIデータをサーバへ送信し、サーバはクライアントから受信したASCIIデータに応答し、ASCIIデータ伝文を返信してきます。

このサーバからのASCIIデータ応答伝文をrecvfrom関数で受信し、応答伝文のASCIIデータを'buf'変数に格納し、標準出力関数で表示させるといったプログラムです。

このプログラムでは、ユーザ関数内でrecvfrom関数をコールしているのですが、ユーザ関数内でrecvfrom関数をコールした場合、受信データの先頭4byteしか受信できておらず、困っています。

ちなみに、main関数内でrecvfrom関数をコールすると、応答伝文全体のデータをきちんと受信できています。

ちなみに、サーバの応答ASCIIデータ伝文は、仕様通り(期待通り)のデータが返信されています。(ネットワークモニタ:wiresharkで確認済み)

recvfrom関数をコールする場所によって、変数に格納するデータ量が変わるといったことがあるのでしょうか。

ソースの一部を添付します。
参照の上、アドバイス等いただけないでしょうか。

《ソース》
◆mainソース
#include ...
:<-#include定義
int main{
  :<-変数定義、変数初期値代入処理等
ユーザ関数1()コール<-ユーザ関数1内でソケット通信処理を動作させている。
ユーザ関数2()コール<-同上


◆ユーザ関数用ソース
#include...
  :<-#include定義
unsigned char ユーザ関数名1;<-ユーザ関数プロトタイプ宣言
unsigned char ユーザ関数名2:<-同上
char 変数1[5];
char s_buf[4096];
char buf[4096];/*データ受信用バッファ*/
char 変数2[256];
size_t len;
long l;
int sock_fd;/*ソケット用ファイル記述子*/
struct sockaddr_in cl_addr;/*CPU用ソケットアドレス*/
socklen_t cl_len = 0;/*cl_addrのサイズ格納用*/
ssize_t n = 0;

unsigned char ユーザ関数1(char *引数1,…char *引数5){
  :送信データ生成処理
//* ソケット作成 *//
if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
  }
//* 接続先定義*//
memset(&cl_addr, 0, sizeof cl_addr);
cl_addr.sin_family  = AF_INET;/*プロトコル定義*/
cl_addr.sin_addr.s_addr = inet_addr("***.***.***.***"); /*IPアドレス定義*/
cl_addr.sin_port = htons(****);/*Port定義*/
//* 接続 *//
if (connect(sock_fd, (struct sockaddr *)&cl_addr, sizeof cl_addr) < 0) {
perror("connect");
return 1;
  }
//* データ送信 *//
if(send(sock_fd, s_buf, strlen(s_buf), 0) < 0){
fprintf(stderr, "could not send message : %s\n", s_buf);
exit(EXIT_FAILURE);
}
printf("\nSendMessage\n%s\n",s_buf);

//* データ受信 *//
cl_len = sizeof cl_addr;
//*↓↓このrecvfrom関数でbuf内にサーバ応答伝文の先頭4byteのみが格納されている。↓↓*//
if (( n = recvfrom(sock_fd, buf, sizeof buf,0, (struct sockaddr *)&cl_addr, &cl_len)) < 0) {
perror("recvfrom");
return 1;
}
fprintf(stderr ,"TCP from addr = %s, port = %d\n",
inet_ntoa(cl_addr.sin_addr),
ntohs(cl_addr.sin_port)
);

A 回答 (6件)

早い話が、こういうことが起きているのではないでしょうか。



#include <stdio.h>

void func(char *buf)
{
printf("%d\n", sizeof buf);
}

int main()
{
char buf[4096];

func(buf);
return 0;
}
    • good
    • 0

No.4さん



失礼しました、intではなくcharですね。。。
    • good
    • 0

No.2さんの回答で概ね合っているかと。


本筋から外れますが…

>int buf[4096];
>ならば、sizeof bufは4096を返しますが、

int型ならば4096はおそらく返されないでしょう。
char型で説明するつもりだったかと思われますが。


>ユーザ関数定義ソース内では、ユーザ関数1と2とあり、各関数で同一の変数名を使用したいと思い、グローバル宣言にしています。
>グローバル宣言とローカル宣言で何か違いでもあるのでしょうか。

スコープに違いがあります。
同じ名前のローカル変数を定義した場合、グローバル変数にはアクセスできませんのでご注意を。
# 名前空間で回避できるかも知れませんが…。
    • good
    • 0

お~い, 元質問文中のソースと #1 へのお礼に書かれていることが矛盾してるぞ....


質問文中では
char buf[4096]; /*データ受信用バッファ*/
となってるから buf は配列のはずなのに, なんで「bufポインタ変数」になるの? どっちが正しいのか, はっきりしてください.
実際のソースと違うものを出すのは余計な混乱を招くだけなのでやめてください.
    • good
    • 0

sizeof buf を 4096に変えたらデータを正しく取得できたとのこと、


原因はsizeofの使い方にあります。

bufをローカル変数として宣言した場合、
int buf[4096];
ならば、sizeof bufは4096を返しますが、

bufを明示的にメモリ獲得した場合、
int* buf = new int[4096];
sizeof buf はポインタのアドレス分のサイズ、
つまり4バイトしか返しません。

明示的にメモリを獲得した場合の
sizeofの使い方には注意しましょう。
    • good
    • 0

4バイトのみ、というのが気になります。


考えにくいのですが、sizeof buf となっているところを
4096 に変えてみて試してはいかがでしょうか。
    • good
    • 0
この回答へのお礼

Vidocqさん、早速の回答ありがとうございます。

回答いただいたとおりに、’sizeof buf’部分を’4096’に変更し、
再度デバックしたところ、期待通りのデータをbuf変数に格納することができました。

ただ、なぜ具体的な数値を指定しただけで、きちんと格納できたのかが、
全く理解できません。
main関数内での実行とユーザ関数内での実行との違いとすれば、
bufポインタ変数の宣言を、main関数ではローカル宣言、ユーザ関数ではグローバル宣言しているぐらいなものです。

ユーザ関数定義ソース内では、ユーザ関数1と2とあり、各関数で同一の変数名を使用したいと思い、グローバル宣言にしています。

グローバル宣言とローカル宣言で何か違いでもあるのでしょうか。

ちなみに、デバッカでmain関数内でのコール時とユーザ関数内でのコール時で、recvfrom関数コール直前の’buf’変数内部の格納データを比べてみたところ、以下のような明らかな違いがありました。

◆main関数内コール
buf = '\000' <repeats 2500 times>"\236, \037\211", '\000' <repeats 25 times>"\370, \371\377\26 ...

◆ユーザ関数内コール
buf = 0x804d200 ""

sizeof bufを4096に変更した場合でも、ユーザ関数内コール時のbuf変数格納値はrecvfrom関数コールするまでは同じでした。

何か具体的な原因をつかみたいものですが、思い当たるところございませんでしょうか?

お礼日時:2010/03/03 16:37

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!