地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【TCP】TCPの話 SOCK_DGRAM/SOCK_STREAM

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_STREAMSOCK_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を使用するには特権ユーザとしてじっこうする必要がある)

github.com

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 エラーを受け取った。