かなり長い間、お休みします。もうずーっと、お休み
したいです。
open server.fujiuchi.or.jp user password cd data lcd C:\データ\temp prompt off mget z01*.dhr bye
日本語のディレクトリ名は私のポリシーには反するのだが、やむ にやまれぬ事情によるもので仕方がない。スクリプト自体は完成して、テスト でも正常動作することを確認したのだが、テスト運用中たまに ftp.exe がア プリケーション エラーになることがあった。最初は WSH スクリプトから WScript.Shell を利用して ftp.exe を実行しているのが原因ではないかと思 い、bat ファイルで ftp.exe を実行してから WSH プログラム ( DB データ登 録 ) を実行するように変更した。んが、やっぱりたまに ftp.exe がアプリケ ーション エラーで異常終了してしまう。なぜだ...ただたんに ftp を実行し ているだけじゃないか。うわーん(泣) そんなわけでなんかヒントはないかと Microsoft を検索してい たら、ありました、ヒントじゃなくて答えが。
なんだよ、Win2k のバグじゃねーか。こらーーー(怒) おまけに英語 版はちゃんと「put or lcd」と書いてあるのに、日本語版では「put など」と lcd が省略されてるし。そんなことするから検索の時に最初に日本語版がみつ からんかったんだーーー(怒)それに英語版を見るとどうやら同じバグが WinXP にもあるようだが、日本語版では WinXP に関する情報がいっさいない...駄目 だこりゃ。日本語版、情報量少なすぎ。つーか、少なくとも英語版の情報と同 等量を提示してくれよ。ほんと機械翻訳の方がまだましだぜ、put を「おく」 ってしていても(笑)そんなわけで Win2k の場合には SP4 を適用すればこのバ グは解決するようですが、これまたやむにやまれぬ事情により SP なんて適用 できるわけがありません。はぁ...しょうがない、ftp.exe で lcd せずに、bat ファイル内で cd する方針にしよう。そんなわけで今回、 bat ファイルの書 き方まで勉強 ( 復習 ) したし、せっかくなんで作成した bat ファイルもの せときます。bat ファイルなんて、なつかしーでしょ。
@echo off set FtpDir=C:\データ\temp set FtpCmdFile=C:\データ\ftpcmd.txt if not exist %FtpDir% mkdir %FtpDir% %SystemRoot%\system32\cscript.exe C:\makeftp.vbs //Nologo %FtpCmdFile% if %errorlevel% NEQ 0 goto :EOF cd /d %FtpDir% %SystemRoot%\system32\ftp.exe -s:%FtpCmdFile% %SystemRoot%\system32\cscript.exe C:\updatedb.vbs //Nologo %FtpDir%
とりあえずこれでしばらくテスト運用して、様子を見てみたいと 思います。さてと、あとは早くネットワークプログラムの続きをまとめないと なぁ。さらに今回の件で以前 MS-Access のファイルにアクセスする方法とか なんとか言っていたのを思い出した。そ れもまとめてしまわないと。これは...年内は無理かなぁ。
12 int main( int argc, char *argv[] ) 13 { 14 int sockfd, i; 15 char buf[BUFMAX+1]; 16 struct sockaddr_in addr; 17 18 if( argc != 2 ) return 1; 19 sockfd = socket( AF_INET, SOCK_STREAM, 0 ); 20 if( sockfd == 0 ) return 2; 30 memset( &addr, 0, sizeof( addr ) ); 31 addr.sin_family = AF_INET; 32 if( inet_pton( AF_INET, argv[1], &addr.sin_addr ) <= 0 ) 33 return 3; 34 addr.sin_port = htons(13); 35 i = connect( sockfd, ( struct sockaddr * )&addr, sizeof( addr ) ); 36 if( i < 0 ) return 4; 37 while( ( i = read( sockfd, buf, BUFMAX ) ) > 0 ){ 38 buf[i] = '\0'; 39 fputs( buf, stdout ); 40 } 41 close( sockfd ); 42 return 0; 43 }return で返す数字で debug するというのは、もうはや破綻しており ます(笑) まあサンプルプログラムなんで気にしないことにしましょう。今回 のポイントは inet_pton 関数です。この関数は 8 ビットごとドット区切表記 (この表記方法、なんて言うんでしょうね。man には dotted-quad format と 書いてありましたが)の文字列を構造体 in_addr に変換(格納?)してくれま す。では早速動作確認。
% ./a.out 127.0.0.1 11 SEP 2003 00:27:56 JST % ./a.out localhost % echo $status 3 % ./a.out www.fujiuchi.or.jp % echo $status 3 %そんなわけで IP アドレスが無事変換されていそうなことが確認でき ました。んがしかし、普通は 8 ビットごとドット区切表記ではなく、ホスト名 (例えば www.fujiuchi.or.jp とか → 実際にはこんなホスト名...ないですよ ね?)でサーバ(通信相手)を指定しますよね。そーゆー場合にはどうするの か。これまた、それようの関数が最初から用意されているのでそれを利用しま す。余計な心配御無用といったところか、至れり尽せりといったところか。そ んなわけでサンプルプログラムは以下のとおり。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/types.h> 5 #include <sys/socket.h> 6 #include <netinet/in.h> 7 #include <arpa/inet.h> 8 #include <unistd.h> 9 #include <netdb.h> 10 11 #define BUFMAX 20 12 13 int main( int argc, char *argv[] ) 14 { 15 int sockfd, i; 16 char buf[BUFMAX+1]; 17 struct sockaddr_in addr; 18 struct hostent *hp; 19 struct servent *sp; 20 21 if( argc != 2 ) return 1; 22 hp = gethostbyname( argv[1] ); 23 if( hp == NULL ) return 2; 24 sp = getservbyname( "daytime", "tcp" ); 25 if( sp == NULL ) return 3; 26 sockfd = socket( hp->h_addrtype, SOCK_STREAM, 0 ); 27 if( sockfd == 0 ) return 4; 28 memset( &addr, 0, sizeof( addr ) ); 29 memcpy( &addr.sin_addr, hp->h_addr, hp->h_length ); 30 addr.sin_family = hp->h_addrtype; 31 addr.sin_port = sp->s_port; 32 i = connect( sockfd, ( struct sockaddr * )&addr, sizeof( addr ) ); 33 if( i < 0 ) return 4; 34 while( ( i = read( sockfd, buf, BUFMAX ) ) > 0 ){ 35 buf[i] = '\0'; 36 fputs( buf, stdout ); 37 } 38 close( sockfd ); 39 return 0; 40 }あー、return の数字を直すのが面倒だ。この方法、やっぱ駄目です ね(笑) ホスト名を変換(格納?)する関数 gethostbyname 関数と、おまけで サービス名を変換(格納?)する関数 getservbyname 関数も利用しています。 おのおのの詳しい説明は、man を見てください(あいかわらずなげやり)。そん なわけで実行結果は以下のとおり。
% ./a.out 127.0.0.1 11 SEP 2003 00:29:26 JST % ./a.out localhost 11 SEP 2003 00:29:32 JST % ./a.out www.fujiuchi.or.jp 11 SEP 2003 00:29:41 JST % ./a.out www.hoge.co.jp % echo $status 2 %これでクライアントプログラムの一通りの説明はしたように思えま すが、実はもう一歩先があります。それについてはまた次回に。
28 } 29 close( sockfd ); 30 return 0; 31 }あと、memset 関数を使っているのに、string.h を include するの を忘れてました。最初のほうに追加しておいてください。
% telnet 127.0.0.1 13 Trying 127.0.0.1... telnet: connect to address 127.0.0.1: Connection refused %...あれ、どーやらサービスが動いてないらしい。ま、これは不要な サービスは動かさないという、セキュリティの基本ですね。そんなわけでちょ っと調べてみましたが、そーか、inetd じゃななくて xinetd なのか... xinetd なんかさわったことないからよくわからないんだけどなぁ。
% cd /etc/xinetd.d/ % ls -aF ./ chargen-udp dbskkd-cdb finger rlogin servers talk time-udp ../ daytime echo ntalk rsh services telnet chargen daytime-udp echo-udp rexec rsync sgi_fam time % more daytime # default: off # description: A daytime server. This is the tcp \ # version. service daytime { disable = yes type = INTERNAL id = daytime-stream socket_type = stream protocol = tcp user = root wait = no } % su - # vi /etc/xinetd.d/daytime disable = no に変更 # ps aux | grep xinetd root 631 0.0 0.4 2092 900 ? S 12:51 0:00 xinetd -stayalive root 1248 0.0 0.3 3476 648 pts/4 S 13:37 0:00 grep xinetd # kill -HUP 631 # exit % telnet 127.0.0.1 13 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. 29 AUG 2003 21:15:44 JST Connection closed by foreign host. %というわけで無事に daytime サービスの動作確認終了。次に参考書 などを参考にできる限りシンプルなプログラムを作成してみました。ただし本 当にシンプルなプログラムかどうかは疑問が残るところではありますが...そ んなわけで、以下のプログラムは参考書に掲載されている例題プログラムとま ったく一緒というわけではありませんので、ご注意ください。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <unistd.h> 8 9 #define BUFMAX 20 10 11 int main( int argc, char *argv[] ) 12 { 13 int sockfd, i; 14 char buf[BUFMAX+1]; 15 struct sockaddr_in addr; 16 17 sockfd = socket( AF_INET, SOCK_STREAM, 0 ); 18 if( sockfd == 0 ) return 1; 19 memset( &addr, 0, sizeof( addr ) ); 20 addr.sin_family = AF_INET; 21 addr.sin_addr.s_addr = htonl( 0x7F000001 ); /* 127.0.0.1 */ 22 addr.sin_port = htons( 13 ); 23 i = connect( sockfd, ( struct sockaddr * )&addr, sizeof( addr ) ); 24 if( i < 0 ) return 2; 25 while( ( i = read( sockfd, buf, BUFMAX ) ) > 0 ){ 26 buf[i] = '\0'; 27 fputs( buf, stdout ); 28 } 29 return 0; 30 }えーっと、一応簡単な説明を。17 行目でソケットを作成し、20 行目 から 22 行目までで通信先の IP アドレスなどを変数に格納、23 行目で接続を 試みて、25 行目の while 文の部分でサーバからの応答を読み込み標準出力に 出力するという流れになっています。17 行目の AF_INET とか SOCK_STREAM の 説明は...また今度ということで(笑) とりあえず TCP/IPv4 の場合は AF_INET と SOCK_STREAM ということで間違いないと思う。ちなみに UDP/IPv4 は AF_INET / SOCK_DGRAM だと思う。19 行目の memset 関数は bzero 関数で も良いのですが、 man bzero に bzero 関数より memset 関数を使えというよ うなことが書いてあったので、今回は memset 関数を利用しています。21 行目 の 16 進数で 0x7F000001 という謎の数字は、8 ビットごとに区切り 10 進数 に直すと 127.0.0.1 になります。htonl 関数と htons 関数は... byte order をネットワークに適したものに自動的に変換してくれるということでご了承 ください。それから構造体 sockaddr_in とか sockaddr とかは以下のプリプ ロセッサ結果からの抜粋を見てください。
% gcc -E sample.c 関係個所を抜粋 typedef unsigned short int sa_family_t; struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; typedef uint16_t in_port_t; typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; }; struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[sizeof (struct sockaddr) - (sizeof (unsigned short int)) - sizeof (in_port_t) - sizeof (struct in_addr)]; };説明が投げやりなのはいつものこと(笑) というかこの説明で十分だ よね。後はなんか変なこと書いてなければ良いけど...最後にデバグの際のヒ ント。というか printf 関数とか使えば良いという話もあるけど、だって面倒 じゃん。
サービスされている場合 tcsh% ./a.out 29 AUG 2003 22:00:58 JST tcsh% echo $status 0 tcsh% サービスされていない場合 tcsh% ./a.out tcsh% echo $status 2 tcsh%え? tcsh 以外の場合はどうするんだですって? そんなこと知りません 。私は tcsh 使いですから(笑)
さて、久々(?)に公式紹介シリーズ第 ? 回。何回目かは調べるのが面倒だ し、ま、どーでもいいでしょ。で、真空中の光速を c [m3/m]、真 空の誘電率を ε0 [F/m]、真空の透磁率 μ0 [H/m] とすると、
c = 1 / √ε0 μ0
となります。ちなみに誘電率 ε ( 比誘電率 εr ) 、透磁率 μ ( 比透磁率 μr ) の媒体中の光速 v [m3/m] は、v = 1 / √ε μ = c / √εr μr
となります。さて次は表皮効果 ( skin effect ) の話。電流密度が 1 / e2 以上となる表面からの導体の厚さを「表皮厚さ」と言い、以 下の式で表されます。δ = 1 / √π f μ σ
ただし、δ [m] : 表皮厚さ、f [Hz] : 周波数、μ [H/m] : 導体の 透磁率、σ : 導体の伝導率 です。void func( void ) { int i; /* これは OK */ { int j; /* これは構文エラー */ } }そんなこと ANSI じゃできない...あれ?できるんだ?調べてみたらちゃんと K&R 第2版 に書いてあった...(私の手元にある本では p.102 「4.8 ブロ ック構造」にはっきりと) がーん、これは gcc の方言だと思っていた。うー ん、ま、いっか。一つ勉強になったし(苦笑)。だけど関数内の static 変数の ポインタを return し、他の関数で利用するのは決して良いプログラムとはい えないと思うのだが。なんて偉そうなこと言っても、C++ で恥ずかしいこと言 っている前歴があったりするので、これ 以上はやめておこう。それはさておき、Windows ( Visual C++ ) でも socket 関連 ( Winsock というらしい ) が用意されているらしいので、ちょっと Linux で socket 関連を勉強しなおしてみよう。しっかし、昔作ったプログラ ムのソース、どこへいったかなぁ...ふと思い出したが、Java でもちょっとネ ットワークプログラミングを勉強したことがあったような気がするけど、その プログラムもどこへいったんだろう。
ティナ | ロック | カイエン | シャドウ | エドガー | マッシュ | セリス |
48% (Lv.53) | 46% (Lv.54) | 45% (Lv.52) | 43% (Lv.52) | 43% (Lv.52) | 52% (Lv.53) | 51% (Lv.54) |
ストラゴス | リルム | セッツァー | モグ | ガウ | ゴゴ | ウーマロ |
40% (Lv.53) | 46% (Lv.52) | 45% (Lv.53) | 44% (Lv.49) | 18% (Lv.32) | 50% (Lv.49) | 43% (Lv.42) |