Closed37

webserv

bayamasabayamasa

socket
int socket(int domain, int type, int protocol);

domain = 通信領域
プロトコルファミリ & アドレスファミリが決まる

AF_INET IPv4を基にしたTCP/IP
AF_INET6 IPv6を基にしたTCP/IP

他の通信領域

type = 通信の種類
SOCK_STREAM = ストリームソケット: TCP通信であるバイトストリーム通信を可能とする
SOCK_DGRAM = データグラムソケット: UDP通信であるデータグラム通信を可能とする

protocol = 通信プロトコル
基本的に他の2つの引数によってプロトコルが定まるので、デフォルトの0でよい

bayamasabayamasa

htons : host short byte order to network short byte order
ネットワークバイトオーダーをホストバイトオーダーに変更
short integerやlong integerなどがある

ネットワークバイトオーダーは規格でビッグエンディアンであるというきまりに対して、ホストバイトオーダーはホストの規格によってリトル or ビッグである。その誤差を埋める

bayamasabayamasa

ソケット API(Socket Application Programming Interface)は,アプリケーションに対し
て,異なるホスト間での通信をサポートするためのトランスポート層以下の機能を提供す
るプログラミングインタフェースで,クライアント/サーバモデルを実現するために用いら
れる.図 2 にクライアント/サーバ,TCP/IP プロトコル階層とソケット API の関係を示す.

つまりソケットAPIはトランスポート以下(TCP, UDP)の実装を隠蔽することができる。
https://home.soka.ac.jp/~matsumi/ne/NE_TEXT.pdf

bayamasabayamasa

setsocketopt
signature

       int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);

sockfd = 作成したsocket file discripter
level = どの層のオプションをセットするか。ソケットAPI層(アプリケーション層)のオプションの場合SOL_SOCKETをセットする

optname = 以下のmanのオプション
https://linuxjm.osdn.jp/html/LDP_man-pages/man7/socket.7.html

optval = optnameで指定したオプションの値
optlen = sizeof(optval)

bayamasabayamasa

wait関数
wait(&status)
子プロセスの修了を待つ
戻り値は修了した子プロセスのID。失敗したら-1

bayamasabayamasa

statusの値は16bitを取る。
上位8ビットはexit status。
下位8ビットは各マクロに対応するbit値を取る。
各マクロは例えばシグナルにより強制修了したときなどに利用される
https://www.c-lang.net/wait/index.html

bayamasabayamasa

waitpid
pid_t waitpid(pid_t pid, int *wstatus, int options);
第一引数のpid

< -1
プロセスグループID が pid の絶対値に等しい子プロセスのいずれかが終了するまでを待つ。
-1
子プロセスのどれかが終了するまで待つ。
0
プロセスグループ ID が、waitpid() が呼ばれた時点での呼び出し元のプロセスのプロセスグループ ID と等しい子プロセスを待つ。
> 0
プロセスID が pid に等しい子プロセスを待つ。

wstatus
これはwaitと一緒

options

  • WUNTRACED
    子プロセスが修了した場合だけでなく、停止した場合にもその状態を返す
    WIFSTOPPED or WSTOPSIGで値を判断する
  • WNOHANG
    状態が返せる子プロセスがないときには待たずに戻る
  • WCONTINUED
    終了した子プロセスの他に、継続された子プロセスの状況を報告します。WIFCONTINUED マクロによって、プロセスは 継続プロセスと終了プロセスを区別できます。

引用
基本的に0でいいかも

bayamasabayamasa

bind ソケットに名前をつける
int bind(int socket, const struct sockaddr *address, socklen_t address_len);

先に作成させておいたsocket file descripterにポート/アドレスなどを入力することにより、そのサーバーで一意に特定できるソケットに昇格する。

これによりクライアントが指定できるソケットが生まれる

bayamasabayamasa

listen
int listen(int socket, int backlog);

bindで名前をつけたsocketをクライアント待ち状態にするbacklogには対応する待ち行列を指定。
socketを処理している間に、キューにどれだけクライアントの通信を保存できるかを指定。
キューがいっぱいになると要求がリジェクトされるようになる。

bayamasabayamasa

accept クライアントからの接続の受け入れ
int accept(int socket, struct sockaddr *address, int *address_len);

listen状態のsocketを第一引数にとり、address/address_lenにクライアントの情報を返す
戻り値は新規作成した、socket fd。
listenは待受状態をつくるが実際に通信を行うのはlistenされているsocket descripterと違うのがミソ

bayamasabayamasa

shutdown
ソケットのからの入出力を停止する
int shutdown(int socket, int how);

howについて
SHUT_RD 今後このソケットではデータを受信しない
SHUT_WR 今後このソケットではデータを送信しない。通信相手にはEOFが送られる。
SHUT_RDWR RDもWRもどちらも

bayamasabayamasa

select 複数のソケットを扱えるようにする
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
nfds 監視するfdのmaxの値の+1の値を入れる (なので監視用のfdはつねに把握しておかないといけない)
readfds, writefds, exceptfds: 読み込みで使うfds, 書き込みで使うfds, 多分弾くfds
timeout: selectはfdの準備が完了するまで待ち続ける。その時間に制限をかける。

bayamasabayamasa

selectではfdを束にして使用するので、fd_setという構造体に詰め込む。
fd_setがint32[32]なので32 * 32 = 1024のfdをフラグの形で保存している。
fd_setの操作はマクロで使用する
FD_ZERO(fdset *fds) fdsetに入っているfdの初期化
FD_SET(int fd, fdset *fds)fdsetにfdを追加する
FD_CLR(int fd, fdset *fds)fdsetの特定のfdを削除する
FD_ISSET(int fd, fdset *fds)fdsの中にfdが入っているかbool値を返す

bayamasabayamasa

send
ssize_t send(int s , const void * buf , size_t len , int flags );

socketにてmsgを送る
writeとの違いはflagsがあるかないかである。

flags: フラグオプション
いくつかあるオプションの例

MSG_OOB
帯域外データを送受信する
MSG_PEEK
読み取らずにデータの確認だけを行う
MSG_DONTROUTE
パケットの経路を指定せずにデータを送信する

https://www.ibm.com/docs/ja/zos/2.3.0?topic=functions-recv-receive-data-socket

bayamasabayamasa

gethostname
自分のコンピューターのホスト名を取り出す
ホスト名はNULL終端を持っているかどうかが保証されていないので、最後にNULL終端をつけるのをわすれないようにする

bayamasabayamasa

selectを理解する
selectはそのソケットディスクリプタが読み取り可能か、書き込み可能かどうかを判断する。
そのため、acceptで接続を確認した新規のソケットディスクリプタが読み込み可能かを確認しないといけないためループを戻し毎回読み取り可能かどうかを確認してからrecvを行う必要がある
https://www.ibm.com/docs/ja/i/7.2?topic=designs-example-nonblocking-io-select

このスクラップは2023/04/09にクローズされました