netstat -ne
とかで見れるsocket-typeのDGRAMとかSTREAMってなんだろうって話
Proto RefCnt Flags Type State I-Node Path unix 2 [ ] DGRAM 12689 /run/systemd/shutdownd unix 3 [ ] STREAM CONNECTED 33511
STREAM (SOCK_STREAM)
TCP を使用したプロセスの通信を可能にする。ストリームソケットは、信頼性の高い、順序付けされた、重複のない双方向データフローをレコード境界なしで提供が可能。
DGRAM (SOCK_DGRAM)
UDP を使用したプロセスの通信を可能にする。データグラムソケットは、メッセージの双方向フローをサポート。データグラムソケット側のプロセスは、送信シーケンスとは異なる順序でメッセージを受信することがあります。
それぞれの生成方法としてはソケットプログラミングの例であげるなら(1)の生成時にオプションは指定してしまう。
socket() (1)ソケット生成 ↓ bind() (2)ソケット登録 ↓ listen() (3)ソケット接続準備 ↓ accept() (4)ソケット接続待機 ←接続要求 ↓ read()/write() (5)受信/送信 ←データ→クライアント側プログラム ↓ close() (6)ソケット切断
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/socket.2.html
int socket(int domain, int type, int protocol);
socket(2)は第二引数でソケットのタイプを指定することが可能なのでそこにSOCK_STREAM
やSOCK_DGRAM
を指定するが可能。
あんま書いたことないのでsock_dgramのサンプルを作成
基本的にはtcpプログラミングと同じように作成することが可能でsocket(2)のオプションが違うだけになる。telnetなりで繋ぐだけで簡単にudpサーバとしての動作を確認が可能。
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main() { int sock; struct sockaddr_in addr; char buf[2048]; sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.s_addr = INADDR_ANY; bind(sock, (struct sockaddr *)&addr, sizeof(addr)); memset(buf, 0, sizeof(buf)); recv(sock, buf, sizeof(buf), 0); printf("%s\n", buf); close(sock); return 0; }
余談
TCP のデータ部だけでなく、よりデバイスに近い情報である、IP や TCP のヘッダー情報を参照したいケースがあるとする。
上記のオプションだけではアクセスが可能なのはデータのみでそれらのヘッダーの情報にはアクセスできない。
PF_PACKET ドメインの SOCK_RAW を指定することでそれらのヘッダーにアクセスすることが可能となる。(raw_socketを使用するには特権ユーザとしてじっこうする必要がある)
EACCES ユーザーが broadcast フラグを設定していないソケットを用いて ブロードキャストアドレ スに送信を行おうとした。 EFAULT 不正なメモリアドレスが与えられた。 EINVAL 引き数が不正。 EMSGSIZE パケットが大きすぎる。 Path MTU Discoverry が有効になっている (IP_MTU_DISCOVER ソ ケットフラグ) か、パケットのサイズが IPv4 で許されている パケットサイズの最大値 64KB を越えている。 EOPNOTSUPP ソケット呼び出しに不正なフラグ (MSG_OOB など) が渡された。 EPERM ユーザーは raw ソケットをオープンする権限を持っていない。 実行ユーザー ID が 0 のプ ロセスか、 CAP_NET_RAW 属性を持つプロセスだけがこれを行うことができる。 EPROTO パラメータの問題を報告する ICMP エラーを受け取った。