『TCP/IP ソケットプログラミング C言語編』を読む
TCP/IP ソケットプログラミング C言語編
ソケットプログラミングのためのDevContainerを立てる
第1章 ネットワークとプロトコルの概要
1.1 ネットワーク、パケット、プロトコル
第2章 ソケットの基礎
Dockerコンテナ内でサーバーソケットに接続できない
TCPEchoClient.cの43行目で、sockaddr_in構造体をallocateせずにいきなりmemsetしてるけど、いいの?t6o_o6t.icon
code: TCPEchoClient_1.c
memset(&echoServAddr, 0, sizeof(echoServAddr));
そもそも普段、mallocはするけどmemsetは使ったことない
第3章 メッセージの作成
3-1. データのエンコード
sprintfではなくsnprintfを使う
3-2 バイト順
hton(プロセッサ固有のバイト順で扱っているデータを、ネットワークバイト順に変換する)
htonl(long型バージョン)
htons(short型バージョン)
ntoh
ntohl
ntohs
PF_INETとAF_INETの違いは
UDPEchoServer.cで、echoServAddr.sin_addr.s_addrをhtonl(INADDR_ANY)にしている
これはなに?
クライアント側のプログラムだと、s_addrには接続先ホストのIPアドレスを格納するよね
第4章 UDPソケット
UDPのメッセージについて
任意のアドレスから「複数の」アドレスへ(あるいは複数のアドレスから任意のアドレス)へ
UDPが接続を確立せずにメッセージを送信できることに起因する。
TCPの場合は1つのクライアントソケットで1対1の通信を行う。
UDPの場合は1つのクライアントソケットで、1対多の送信を行える。
UDPのソケットはそもそも、「決まった通信相手」という概念が存在しない
通信ごとに相手が変わり得るので、あらゆる送受信には必ず通信相手の情報が伴う設計。
まとめると
TCPクライアント
接続の確立
自身のソケットディスクリプタと、接続先アドレスをconnect()に渡す。
送信時
自身のソケットディスクリプタをsend()に渡す。
送信先アドレスは接続確立時に決まっているので渡す必要がない。
受信時
自身のソケットディスクリプタをrecv()に渡す。
受信元アドレスは接続確立時に決まっているので受け取る必要がない。
UDPクライアント
接続の確立
しない。どの相手への通信でも同じソケットを使い回せる。
送信時
自身のソケットディスクリプタと、送信先アドレスをsendto()に渡す。
受信時
自身のソケットディスクリプタと、受信元アドレスを受け取るためのバッファポインタをrecvfrom()に渡す。
TCPはソケットごとに誰と誰が通信するか決まっている
このため、データの受信バッファをそのまま読み取れば良い
データはFIFOで格納される
UDPはソケットに対して通信相手が決まっていない
だからメッセージ境界が保持される設計になっている
5-1
ミスを見つけたかもしれない
どちらの場合も、$ optLenにはバッファへのポインタを指定します。
直前に示されているインターフェースでは、setsockoptの方はポインタではない
getsockopt
optLenはunsigned int *
setsockopt
optLenはunsigned int
後のコードで、setsockoptのoptLenはポインタではない
code: example_optLen.c
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize, sizeof(rcvBufferSize)) < 0)
DieWithError("setsockopt() failed");
引数
int socket
sock
int level
SOL_SOCKET
int optName
SO_RCVBUF
void *optVal
rcvBufferSize
unsigned int optLen
sizeof(rcvBufferSize)
ミスっぽいな、これ
バッファへのポインタを指定するのは、optValです。
なぜgetsockoptのoptLenはポインタなのか。
この関数は、次の2つの値を返す必要がある。
ソケットオプションの値
ソケットオプションの長さ
複数の値を返したいので、ポインタにするしかない。
setsockoptの場合は、ソケットオプションの長さを返す必要はないので、ポインタにしなくとも問題ない。
関数ポインタがちゃんと使われているのを初めて見た
イベントハンドラを登録するために関数ポインタを使う
5-3 ノンブロッキングI/O
ビジーカーソルってなんです?
ソケットでCLIで動くチャットを作るを実行するには、これが必要だ!
非同期なソケットでサーバーとやり取り?
5.3.1
5-3 ノンブロッキングIOでは、ソケット呼び出し(recvfrom)が常に処理をブロッキングしてしまう問題を解消する。
そのために、
ソケットをノンブロッキングソケットに指定する
2. SIGIOメッセージを介してrecvfromの準備完了を知る
3. SIGIOハンドラ内でrecvfromを実行する
メッセージを関数呼び出しではなくシグナルを使って待機する。
5-4 マルチタスクでは、TCPで複数のソケットを同時にエコーできない問題を解消する。
シングルスレッドで動作しているのが原因。
対処
クライアントごとにプロセスを作成
forkでプロセスを生成
スレッドを作成
pthread_createでクライアントのスレッドを作成
Pthreads
プロセスとは異なり、親とアドレス空間を共有する
メモリをコピーする必要がない
資源を削減できる
5