SCTPを使ってみた//WIP
WIPです
本当に申し訳ないですが日本時間には間に合いそうにないです…… すみません(2016/12/6 AM 8:15)
はじめに
この記事はAizuAdventCalenderの記事である。 一つ前は misoton665 さん 一つ後は 0xShone さんです。 よろしくおねがいします。
モチベーション
SCTPと言うプロトコルを知り良さげだと感じたのとLinuxでAPIがあると知って やってみたくなった
SCTPとは
Stream Control Transmission Protocol
と言うプロトコル。
RFC4960で書かれている . RFC 4960 - Stream Control Transmission Protocol
簡単に説明するとTCPの様な信頼性は担保したいが制約が多すぎるので作られたのがSCTP。
公衆電話通信用に作られたが他の用途でも使うことができる。
TCP,UDPに比べあまりポピュラーではないがLTEのトランスポート層でも採用されている。
TCPと比べて良い点
Features TCP SCTP multi-streams support No Yes multi-homing support No Yes preservation of message boundaries No Yes unordered reliable message delivery No Yes
マルチホーミングとは複数の経路を使ってアクセスすることができる機能
使い方
LinuxのAPIでサポートされているので普通に利用できる https://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-10
環境
Ubuntu 16.0.4 gcc 5.4.1
下準備
sudo apt install libsctp-dev
簡単な実装(server)
#include<sys/socket.h> #include<netinet/in.h> #include<netinet/sctp.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include <errno.h> #define MAX_LISTEN 10 #define BUFSIZE 2048 int main(){ int sockfd; struct sctp_sndrcvinfo sndrcvinfo; sockfd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if(-1 == sockfd) { perror("error open socket"); exit(EXIT_FAILURE); } struct sockaddr_in server, from; memset( &server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = htonl( INADDR_ANY ); server.sin_port = htons(1204); if(-1 == bind(sockfd, (struct sockaddr *)&server, sizeof(server))) { perror("error bind"); close(sockfd); exit(EXIT_FAILURE); } if(-1 == listen(sockfd, MAX_LISTEN)) { exit(EXIT_FAILURE); } struct sctp_initmsg sctp_init; /* num_ostreams: number of outbound streams; max_instreams: max number of in-bound streams; max_attempts: max re-transmissions while establishing an association; max_init_timeo: time-out in milliseconds for establishing an association. */ memset( &sctp_init, 0, sizeof(sctp_init)); sctp_init.sinit_num_ostreams = 10; sctp_init.sinit_max_instreams = 10; sctp_init.sinit_max_attempts = 0; sctp_init.sinit_max_init_timeo = 0; int opt = 1; setsockopt(sockfd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_init, sizeof(sctp_init)); if(listen(sockfd, 1) < 0) { perror("error listen for connection"); exit(EXIT_FAILURE); } const char* message = "Hello world"; char buffer[BUFSIZE]; printf("start listen loop\n"); int msg_flags; while(1) { int resv_size = sctp_recvmsg( sockfd, buffer, strlen(buffer), (struct sockaddr *)&from, // sockaddr * from &len, // socklen_t * fromlen &sndrcvinfo, // struct sctp_sndrcvinfo &msg_flags // int * msg_flags ); if(-1 == resv_size) { perror("error receiving message"); exit(EXIT_FAILURE); } buffer[resv_size] = 0; int ret = sctp_sendmsg( sockfd, (void *)buffer, (size_t)strlen(buffer), NULL, // struct sockaddr *to 0, // socklen_t tolen 0, // uint32_t ppid 0, // uint32_t flags 0, // uint16_t stream_no 0, // uint32_t timetolive 0 // uint32_t context ); if(-1 == ret) { perror("error sending message: "); exit(EXIT_FAILURE); } } return 0; }
コンパイル
gcc sctp.c -lsctp
進捗
error open socket: Socket type not supported
Ref
http://www.asahi-net.or.jp/~aa4t-nngk/ipttut/output/other/rfc3286.txt マルチホーミング
http://tech.queryhome.com/44164/what-is-the-main-advantage-of-using-sctp-over-tcp-ip