アプリ版:「スタンプのみでお礼する」機能のリリースについて

rshに関連してどなたか教えて下さい。
rsh-clientをC言語で書くには、具体的にどうしたらよいのでしょう?
例えば、
(1)socketをオープン。
(2)port=514でconnectを確立。
(3)sendで、"0\0"、ローカルユーザ、リモートユーザ、コマンドを送信。
(4)recvで受信。
とやっているのですが、毎回(3)まではエラーがなく、(4)で-1が返ってきます。私の理解が根本的に間違っているのかも知れません。
同じコマンドを、コマンドプロンプトからのrsh.exeでは実行可能です。
諸般の理由で、WindowsからLinux上のアプリを動かすのに、どうしてもCのコードの中にrshの機能を埋め込んで使いたのです。HTTP-clientのCのソースコードはよく見かけるし、自分でも書いていますが、rsh-clientは見たことがありません。
閉じた系で使うため、セキュリティ管理等は不要なので、使い慣れたrshが有り難いのですが...
是非よろしくお願いします。

A 回答 (4件)

>そもそもrsh-clientの機能を実現するにはどのように書くのが一般的なんでしょうか?



一般的かどうか分かりませんが個人的な意見として
rsh-clientを自力実装することをあきらめ、
windows付属のrshをCreateProcessで起動し、プロセスの標準入出力をリダイレクトする。
という方法が良いのでは思われます。

参考情報
他のプロセスの出力を取得する
http://www.h4.dion.ne.jp/~fht/wptips/readprc.html
    • good
    • 0

1,エラーコードが10054なのでWSAECONNRESET (10054) ですね。


 >? 意味 : ピアによって接続がリセットされました。
ピア(サーバー)からの強制切断なので、送信しているデータは形式/内容ともに正しいものですか?

※)rshをethealでパケットキャプチャしながら実行して
  rshの通信プロトコルを調べてみてください。

2,提示コードではコンパイルが通りません。
3,sendの戻り値のチェックが提示コードでは抜けています。
 sendの戻値として-1の時があります。

4,以下の内容は手元の環境でwindows付属のrshを試してみた結果です。

手元の環境でwindows付属のrshコマンドを実行してみたところ、
rsh接続時に2つソケット(標準入出力用と標準エラー用)を作っています。
そして最初に標準エラー用のソケットの送信元ポート番号にNULL終端を付加しsendしています。

提示されたコードは最初に送信データとして"0\0"を送っていますが、
エラー用の送信元ポート番号を送る必要があるのではないのでしょうか?

以下のコードでソケットの送信元ポート番号を取得できます。

1,ローカル変数を2つ追加。
SOCKADDR_IN local;
int len;
2,iRC=send(sock,"0\0",2,0);の部分を以下のように変更。
len = sizeof(local);
/*ソケットの送信元ポート番号を取得*/
getsockname(sock,(const struct sockaddr*)&local,&len);
sprintf(t,"%u\0",ntohs(local.sin_port));
iRC=send(sock,t,strlen(t)+1,0);

以上、ご参考まで。

この回答への補足

たびたびすいません。
ご指摘に従って書き換えましたが、やはりrecvのところで-1が返ってきます。
コマンドとしては、取り敢えず"ls -l"を与えており、Windows付属のrsh.exeではちゃんと実行できます。
当方のコーディングは、根本的に間違っている可能性があります。
そもそもrsh-clientの機能を実現するにはどのように書くのが一般的なんでしょうか?

補足日時:2008/05/21 20:29
    • good
    • 0

recv関数の戻り値が-1(SOCKET_ERROR)なので、サーバー側からの異常切断(RST)またはエラーだと思われます。


どのエラーなのかはWSAGetLastError関数で取得できますので確認してみてください。

例)
int n = recv(sock,buf,1024,0);
int code = WSAGetLastError();

Windows ソケットのエラー コード、値、および意味
http://support.microsoft.com/kb/819124/ja
recv Function
http://msdn.microsoft.com/en-us/library/ms740121 …
WSAGetLastError
http://msdn.microsoft.com/en-us/library/ms741580 …

この回答への補足

もう少し具体的に書きますと、書きのようにコーディングしています。
実際にやってみると、エラーコード10054が返ってきました。
----で囲んだ辺りの書き方が悪いのかも知れません。
引き続きアドバイスをお願いします。

int Exec_RSH(char *sCommand,char *sRet_str)
{ struct hostent *pHost;
WSADATA wsaData;
WORD wVersionRequired=0x0101;
SOCKADDR_IN addr;
SOCKET sock;
DWORD dwIP;
u_short PORT_NO=514;
int i=0,iRC=0;
char t[128],buf[4096];
int bFlag=1;
*sRet_str='\0';
if((WSAStartup(wVersionRequired,&wsaData))!=CLIENT_NO_ERROR) return(WSAGetLastError());
sock=socket(PF_INET,SOCK_STREAM,0);
if(sock==INVALID_SOCKET) return(-1);
if((dwIP=inet_addr(MY_HOST1))==INADDR_NONE){
if((pHost=gethostbyname(MY_HOST1))==NULL) return(-2);
dwIP=*((DWORD*)(pHost->h_addr));
}
addr.sin_family=AF_INET;
addr.sin_port=htons(PORT_NO);
addr.sin_addr.s_addr=dwIP;
if(connect(sock,(const struct sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR) return(-3);
/*------------------------------------------------------*/
iRC=send(sock,"0\0",2,0);
strcpy(t,LOCAL_USER);
iRC=send(sock,t,strlen(t)+1,0);
strcpy(t,REMOTE_USER);
iRC=send(sock,t,strlen(t)+1,0);
strcpy(t,sCommand);
iRC=send(sock,t,strlen(t)+1,0);
/*------------------------------------------------------*/
while(bFlag){
i=recv(sock,buf,NNN-1,0);
if(i==0) break;
if(i==SOCKET_ERROR) return(WSAGetLastError());
buf[i]='\0';
strcat(sRet_str,buf);
}
closesocket(sock);
WSACleanup();
return(0);
}

補足日時:2008/05/19 18:47
    • good
    • 0

はじめまして。


1,ビルド環境はwindows/linuxどちらですか?
winsockの場合はソケット操作を行う前にWSAStartupで初期化する必要がありますが。
2,文中のエラーがないとはどのようなことを仰っていますか?
3,Nagle アルゴリズムの影響を受けていませんか?
4,Etherealなどで実際にsend時にどのようなパケットが送信されたのか確認はしたのでしょうか?

この回答への補足

ありがとうございます。補足します。
1,ビルド環境はWindowsのVisual C++(をただのCコンパイラとして使っている)です。紙面の都合で書いていませんが、WSAStartupはsocketオープンの前にやってあります。リンク時にwsock32.libも指定しています。実際にHTTP-clientなどは、前述のようにして上手く動いています。
2,4,Ethereal?で確認した訳ではありませんが、
iRC=send(sock,"0\0",2,0);
等として、iRCの返り値が送信量と同じなことを確認しています。
3,すいません。仰っている意味が判りません。

今更何も素人がrshをCでコーディングしなくても...というご意見は大いにあるでしょうが、いろいろ事情(&好み)がありまして...エラーチャック、セキュリティ対策など細かいことは不要です。Linuxサーバ上の(かなり処理時間の掛かる)命令を実行させ、返ってくる結果をバッファで受信・結果判別できれば、目的達成です。
うまくいけば、同じよう記してLinux上でも動かしたいので、できるだけ汎用的な書き方が望ましい野ですが...よろしくお願いします。

補足日時:2008/05/18 17:58
    • good
    • 0

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