ポート番号の取得方法
今回も簡単な WinSock プログラムを作って、WinSock に慣れましょう。 今回紹介するのは、プロトコル名を渡してそのプロトコルの待ち受け TCP ポート番号を返すプログラムです。 例えば、HTTP を渡すとポート番号 80 番が返ってきます。
ポート番号の取得は、getservbyname 関数で行います。サービス名を文字列で渡すと、 そのサービス名に対するポート番号を返します。戻り値は servent 型のポインタとして返され、 WinSock により割り当てられたメモリ領域をポイントします。このメモリ領域はスレッド毎にただひとつ 割り当てられた (WinSock が使いまわす) 領域をポイントしているので、これを解放したり、 プログラムから直接書き換えたりしてはいけません。
ちなみに、servent 型は次の形をしています。
typedef struct servent { char FAR *s_name; char FAR FAR **s_aliases; short s_port; char FAR *s_proto; } SERVENT, *PSERVENT, FAR *LPSERVENT;
ポート番号は short 型の s_port に返されます。これはネットワークバイトオーダーで返ってくるので、 ホストバイトオーダーに変換しないといけません。そのために、ntohs 関数を使っています。
尚、どのサービス名のポート番号を取得できるか、ということですが、これは %SYSTEMROOT%\System32\drivers\etc\services に書いてあります。 getservbyname 関数はこのファイル services を参照しています。
今回作成するプログラムの実行例は次の通りです。
> getport http
Port: 80
サンプルコード
getport.cpp として以下の内容を保存します。
#include <stdio.h> #include <winsock2.h> int main(int argc, char* argv[]) { INT rc; WSADATA wsaData; if ( 2 != argc ) { printf ("getport\nex. getport http\n" ); return 1; } // WinSock の初期化 rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if(0 != rc) { printf("WSAStartup Failed.\n"); return 1; } servent* pServEnt = getservbyname ( argv[1], NULL); if ( pServEnt ) { printf ("Port: %d\n", ntohs(pServEnt->s_port)); } // WinSock のクリーンアップ WSACleanup(); return 0; }
makefile は次の通りです。
TARGETNAME=getport CPP=cl.exe LINK32=link.exe OUTDIR=.\chk ALL : "$(OUTDIR)\$(TARGETNAME).exe" "$(OUTDIR)" : @if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=\ /MT\ /W4\ /Fo"$(OUTDIR)\\"\ /Fd"$(OUTDIR)\\"\ /c\ /Zi\ /DWIN32\ /DUNICODE\ /D_UNICODE\ LINK32_FLAGS=\ ws2_32.lib\ /subsystem:console\ /pdb:"$(OUTDIR)\$(TARGETNAME).pdb"\ /machine:I386\ /out:"$(OUTDIR)\$(TARGETNAME).exe"\ /DEBUG\ /RELEASE LINK32_OBJS= \ "$(OUTDIR)\$(TARGETNAME).obj" "$(OUTDIR)\$(TARGETNAME).exe" : "$(OUTDIR)" $(LINK32_OBJS) $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS) .cpp{$(OUTDIR)}.obj:: $(CPP) $(CPP_PROJ) $<
上記ファイルを同じディレクトリにおき、nmake すると、 サブディレクトリ chk に実行可能ファイル getport.exe が作成されます。