筑波大学 システム情報系 情報工学域 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
https://www.coins.tsukuba.ac.jp/~syspro/2024/2024-07-03/tcp_connect.html
あるいは、次のページから手繰っていくこともできます。
https://www.coins.tsukuba.ac.jp/~syspro/2024/
http://www.coins.tsukuba.ac.jp/~yas/
102: /* 新城、筑波大学/情報学類/システムプログラム講義用 */ 103: #define PORTNO_BUFSIZE 30 104: 105: int 106: tcp_connect( char *server, int portno ) 107: { 108: struct addrinfo hints, *ai, *p; 109: char portno_str[PORTNO_BUFSIZE]; 110: int s, err; 111: snprintf( portno_str,sizeof(portno_str),"%d",portno ); 112: memset( &hints, 0, sizeof(hints) ); 113: hints.ai_socktype = SOCK_STREAM; 114: if( (err = getaddrinfo( server, portno_str, &hints, &ai )) ) 115: { 116: fprintf(stderr,"unknown server %s (%s)\n",server, 117: gai_strerror(err) ); 118: goto error0; 119: } 120: for( p=ai ; p ; p=p->ai_next ) 121: { 122: if( (s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0 ) 123: { 124: perror("socket"); 125: goto error1; 126: } 127: if( connect(s, p->ai_addr, p->ai_addrlen) >= 0 ) 128: { 129: break; 130: } 131: else 132: { 133: close( s ); 134: } 135: } 136: freeaddrinfo( ai ); 137: return( s ); 138: error1: 139: freeaddrinfo( ai ); 140: error0: 141: return( -1 ); 142: } 143:
まず、 標準の ライブラリ関数 getaddrinfo() を呼び出して、文字列のホスト名を IPアドレスとポート番号の組みに変換している。 変換された結果は、第4引数で番地が指定された構造体に返される。この構造体 には、socket() システム・コールを呼び出す時に使えるパラメタ (ai->ai_family, ai->ai_socktype, ai->ai_protocol) も返され る。 ポート番号は、引数で与えられた整数をそのまま使う。ただし、 getaddrinfo() は文字列を必要とするので、snprintf() を使って得ている。 ポート番号として、整数ではなく、/etc/services ファイルに含まれた文字列 で指定したいこともある。その場合は、getaddrinfo() 関数の第2引数には、 /etc/services に含まれている文字列を渡す。
次に、クライアント側のソケットを、socket() システムコールで作成している。
第1引数のai->ai_family
は、PF_INET かまたは PF_INET6 のいずれかで
ある。第2引数は、hints で指定した SOCK_STREAM である。
PF_INET と SOCK_STREAMの組み合わせの場合、
IPv4 の TCP、
PF_INET6 と SOCK_STREAMの組み合わせの場合、
IPv6 の TCP を使うことを意味する。
socket() の引数には、PF_INET/PF_INET6 の変りに、AF_INET/AF_INET6 と書い てもよい。ここでは、Protocol を選んでいるので、PF_ が正しいが、実際には、 PF_INET と AF_INET、PF_INET6 と AF_INET6 は同じである。また、多くのテキ ストで混在されて使われいる。
/usr/include/sys/socket.h: ... #define PF_INET AF_INET ... #define PF_INET6 AF_INET6 ...(<sys/socket.h> の内容は、 注意: Linux では
/usr/include/x86_64-linux-gnu/sys/socket.h
や
/usr/include/x86_64-linux-gnu/bits/socket.h
のようなファイルにある。
ソケットが作成できたら、connect() システムコールで接続する。その第2引 数と第3引数で、接続先のアドレスを指定しなければならない。 接続先には、 getaddrinfo() で得られた sockaddr を使う。 この構造体には、IP アドレスとポート番号が含まれている。
getaddrinfo() の中で malloc() されたメモリは、free() を直接呼び出して 解放するのではなく、freeaddrinfo() を呼び出して解放する。 (直接 free() を呼ぶと、ai_next の先が解放されない。)