第228章 SMTPサーバーに接続する


さて、今回から少しだけメール関係のプログラムをします。

ご存知のようにメールを出すサーバーがSMTPサーバーで、受けるほうは POP3サーバーが一般的です。まずはSMTPサーバーに接続して 簡単なメールを送るプログラムを作ってみます。



SMTPに接続するにはWinsockを少しだけ使います。

1.Wsock32.libをプロジェクトに加える 2.ソース・ファイルにWIN32_LEAN_AND_MEANをdefineする   winsock2.hをインクルードする 3.WSAStartup関数でWinsockを初期化 4.gethostbyname関数でホスト情報を取得する 5.socket関数でソケットを作ります 6.getservbyname関数でサービス情報を取得する 7.getservbynameが失敗したときはhtons関数を使ってポートを指定する 8.connect関数でソケットに接続 9.recv関数で接続したソケットからのデータを取得します 10.send関数で「HELO サーバー名」で挨拶する(?) 11.recv関数でサーバーの応答を受け取る 12.対話を続ける 13.send関数で「QUIT\r\n」を送信して対話を終了 14.recv関数でサーバーの応答を受け取る 15.closesocket関数でソケットをクローズします 16.WSACleanup関数でクリーンアップ

というように結構面倒くさいです。

さてWIN32_LEAN_AND_MEANとは何かというと、VC++特有の定義で、ヘッダファイルの 容量を小さくします。

また、これをdefineしないと、エラー(二重定義)が山のように出てきます。 これをソースファイルでdefineするかわりに、「プロジェクト」「設定」 「C/C++」「プリプロセッサ」で「プリプロセッサの定義」に 加えても同じことです。

また、「12.の対話を続ける」というのはSMTPのコマンドを 知らなくてはいけません。 どうもこれは(VC++の)ヘルプには書いてないようです。 で、どうするかというと直接SMTPに聞きます。 「HELP\r\n」を送信するとコマンドの一覧が返ってきます。

うすうす気づいていると思いますがSMTPに送信するときは、 最後に「\r\n」を付けます。これを忘れるといつまでたっても サーバーの応答が来ません。

int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );

この関数はW32_32.DLLを初期化します。

wVersionRequestedにはWinsockの最低限必要なバージョンを指定します。 2.0が必要ならMAKEWORDマクロでMAKEWORD(2,0)とします。

lpWSADataはWSADATA構造体へのポインタで、これに情報が格納されて戻ってきます。 今回は、この構造体を参照しません。

struct hostent FAR * gethostbyname ( const char FAR * name );

ホスト情報を取得します。

nameにはホスト名を指定します。

戻り値はHOSTENT構造体へのポインタとなります。

struct hostent { char FAR * h_name; char FAR * FAR * h_aliases; short h_addrtype; short h_length; char FAR * FAR * h_addr_list; };

h_nameはホストのオフィシャル名です。

h_aliasesはホストのあだ名です。

h_addrtypeは返されるアドレスのタイプです。

h_lengthはアドレスの長さです。

h_addr_listはホストのアドレスのリストです。

SOCKET socket ( int af, int type, int protocol );

ソケットを作ります。

afにはアドレスファミリィを指定します。ここではPF_INETを指定します。

typeにはソケットタイプを指定します。ここではSOCK_STREAMを指定します。

protocolにはソケットで使われるプロトコルを指定します。ここでは0を指定します。

戻り値はソケット型データとなります。(WindowsのHWNDみたいなもの)

struct servent FAR * getservbyname ( const char FAR * name, const char FAR * proto );

サービス情報を取得します。

nameにはサービス名を指定します。今回はメールなので"mail"を指定します。

protoにはプロトコル名を指定します。NULLを指定すると最初のサービスエントリを 返します。

struct servent { char FAR * s_name; char FAR * FAR * s_aliases; short s_port; char FAR * s_proto; };

s_nameはサービスのオフィシャル名です。

s_aliasesはサービスのあだ名です。

s_portはサービスが接触できるポート番号です。

s_protoは、サービスに接触するとき使われるプロトコル名です。

u_short htons ( u_short hostshort );

TCP/IPネットワークにおけるバイトオーダーを返します。

int connect ( SOCKET s, const struct sockaddr FAR* name, int namelen );

ソケットへの接続を確立します。

sはsocket関数の戻り値を指定します。

nameには接続しようとしているソケットの名前のSOCKADDR構造体へのポインタを指定します。

namelenには名前の長さを指定します。

struct sockaddr { u_short sa_family; char sa_data[14]; };

この構造体はWinsock通信に参加しているマシンのIPアドレスを格納するのに 使いますが、実際にアドレスの各部分を設定するにはSOCKADDR_IN構造体を 使います。2つの構造体は単に型キャストすれば相互に使えます。

struct sockaddr_in{ short sin_family; unsigned short sin_port; struct in_addr sin_addr; char sin_zero[8]; };

sin_familyは、アドレスファミリィ(AF_INET)を指定します。

sin_portにはIPポートを指定します。

sin_addrにはIPアドレスを指定します。

sin_zero[8]はSOCKADDRと同じサイズにするためのパディングです。

in_addr構造体は次のように定義されています。

struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un;

さて、ここまでできればあとは、サーバーとのやり取りとなります。

int recv ( SOCKET s, char FAR* buf, int len, int flags );

sはsocket関数の戻り値です。

bufにはサーバーから返されるデータのバッファです。

lenはバッファサイズを指定します。

flagsにはこの関数の呼び出しが行われる方法を指定します。 ここでは特に指定しません。

int send ( SOCKET s, const char FAR * buf, int len, int flags );

接続しているソケットにデータを送ります。

sはSOCKETです(socket関数の戻り値)。

bufは転送するバッファです。

lenはバッファサイズです。

flagsはこの関数の呼び出しが起こったときの行動を指定します。 ここでは、特に指定しません。

int closesocket ( SOCKET s );

ソケットをクローズします。

sはソケットを指定します。

int WSACleanup (void);

W32_32.DLLの使用を終了します。

成功すれば0を返します。

さて、今回はわかったようなわからん説明でした。実際の プログラミングをみればなんとなくわかってきます。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 20/Sep/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。