プロが教える店舗&オフィスのセキュリティ対策術

初めて投稿します。
ネットワークに接続したプリンタ4台を、SNMPを使って状態監視するソフトを作成しています。以下のソース(文字数制限のため、大半をコメントで記述しています)を実行すると、SnmpMgrRequest()関数内でメモリリークを起こします。
この関数の戻り値はエラーではありません。しかもプリンタ1台のみを監視するとメモリリークしません。この関数をコメント化しても起きません。
SNMPは始めてなので何が悪いのかよくわかりません。
どなたか何かご存知であればご教示お願いします。
開発環境はWindowsXP(SP1) VC++6 SP5を使用しています。
(ソースの拡張子は.cです。)

void main(){
while(1){
for (i = 0 ; i < 4 ; i++) {
mib=StsGet([プリンタのIPアドレス]);
}
Sleep(600);
}
}

int StsGet(LPSTR adr) {
//SnmpUtilMemAlloc ()でSNMPエージェントのアドレス取得
//SnmpUtilMemAlloc()でコミュニティ取得
//変数バインディングの初期化
//SnmpMgrStrToOid()でOIDを文字列から値に変換
//SnmpUtilMemReAlloc ()で変数バインディングにメモリを割当て
//変数バインディングにOIDを追加
//SnmpMgrOpen ()でSNMPマネージャAPIのオープン(タイムアウト:100ms、リトライ:1回)
// SnmpMgrRequest()でSNMPマネージャAPIに指定操作(Get)を要求
//SnmpUtilVarBindListFree(),SnmpUtilMemFree()で各変数を解放
//SnmpMgrClose()でSNMPマネージャAPIとの接続を終了
return [プリンタ状態;]
}

A 回答 (2件)

Musaffah様



Musaffah様は、WinSNMPを使用していないので、
SnmpCleanupは必要ありません。不適切なアドバイスをしてしまい、
申し訳ございませんでした。

サンプルコードありがとうございました。
さっそく、こちらでも確かめてみましたが、
メモリーリークも起きませんし、ちゃんと動作しているようです。
環境は、以下のとおりです。
Windows2000(SP4)
VC++6.0(SP6)
.NET2003

ダイアログベースのプロジェクトで、ボタンを押すと、
PrnStsGet関数を永久ループで呼び出すようにしました。
VC++6.0, .NET2003両方とも、問題なく動作しますし、
プリンターを2台モニターしても、問題ありません。

ということで、OSとVC++の最新アップデートをお勧めします。
VC++は、Service Pack6を、WindowsXPはSP2にアップデートした
上で、WindowsUpdateを実行して、最新にしたほうがいいでしょう。

会社の同僚で、ネットワーク通信プログラムがフリーズするという
問題が起きていたのですが、SP2にアップデートしたら、解決したようです。

もし、これでも、解決しないようであれば、
新規にテスト用プロジェクトを作成し、このプログラムだけを
実装して、動作テストをすることをお勧めします。
このことにより、問題の切り分けがはっきりするかもしれません。
    • good
    • 0
この回答へのお礼

お礼の返事が遅くなって申し訳ありません。

WindowsXPをSP2にアップデートしたところ、確かにメモリリークしなくなったことを確認しました!

大変助かりました。ありがとうございました!!

お礼日時:2005/03/03 08:26

Musaffah様



WinSNMP APIについては、サンプルコードもないし、
google検索でも、ほどんど引っかからないので、
似たような例は見つかりにくいかもしれませんね。

さて、質問内容についてですが、コメントアウトされた
ソースコードでは、こちらも、検証できないので、
自信はありませんが、以下を試してみてはいかがでしょうか?

●SnmpMgrStrToOid関数のあとに、SnmpUtilOidFreeでメモリを開放する。
●SnmpMgrClose()のあとに、SnmpCleanup()を実行する。


> SnmpMgrRequest()関数内でメモリリークを起こします。

Microsoftが提供したAPIの場合、使い方を誤ると、たまに、
このようなことがおきます。
たとえば、マルチスレッドアプリケーションにおいて、
あるスレッドで初期化したインスタンスやサービスを
別のスレッドが使った場合などに発生したりします。

この回答への補足

woody_poco様。
アドバイスありがとうございます!
SnmpCleanup()を実行したら2回目以降のチェックができなくなってしまいました(泣)。
質問でコメントアウトした関数を提示します(文字制限オーバーですが・・・すいません)。
SnmpMgrOpen()とSnmpMgeRequest()の初回実行時にのみそれぞれスレッドが1つずつ生成されているのまでは判明しましたが、メモリリークの原因は未だ不明です。
申し訳ありませんがご協力お願い致します。

#define ERR 0x0800
#define Bind RFC1157VarBind
#define BindList RFC1157VarBindList
#define AsnObj AsnObjectIdentifier

int PrnStsGet(LPSTR adr){
UINT iRet=ERR;
LPSTR oid=".1.3.6.1.2.1.25.3.5.1.2.1", comname="public";
LPSTR agt,cmnty;
BindList bind;
Bind *tmpVb;
AsnObj obj;
LPSNMP_MGR_SESSION se;
BYTE req=SNMP_PDU_GET;
AsnInteger errSts,errIdx;

agt=(LPSTR)SnmpUtilMemAlloc((UINT)(strlen(adr)+1));
strcpy(agt,adr);
cmnty=(LPSTR)SnmpUtilMemAlloc((UINT)(strlen(comname)+1));
strcpy(cmnty,comname);
bind.list=NULL;
bind.len=0;
SnmpMgrStrToOid(oid,&obj);
bind.len++;
tmpVb=(Bind *)SnmpUtilMemReAlloc(bind.list,(sizeof(Bind)* bind.len));
bind.list=tmpVb;
bind.list[bind.len-1].name=obj;
bind.list[bind.len-1].value.asnType=ASN_NULL;
se=SnmpMgrOpen(agt,cmnty,100,1);
if(SnmpMgrRequest(se,req,& bind,&errSts,&errIdx))
if(errSts==0){
AsnAny *pAny=& bind.list[0].value;
iRet = pAny->asnValue.address.stream[0];
}
SnmpUtilVarBindListFree(&bind);
SnmpUtilMemFree(agt);
SnmpUtilMemFree(cmnty);
SnmpMgrClose(se);
return iRet;
}

補足日時:2005/02/25 14:43
    • good
    • 0

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