SCTP(Stream Control Transmission Protocol)というTCP, UDPに変わる通信プロトコルについてテストしてみました。
セキュリティ面でDDoS攻撃によるSYN Floodに強く、データ転送面では送信と受信が同じ単位で扱える便利さがあります。個人的にはまずこの二つに注目しましたが、まだまだ高い機能を持っています。
参考:
http://www.asahi-net.or.jp/~AA4T-NNGK/ipttut/output/sctpcharacteristics.html
Stream Control Transmission Protocol (SCTP) はネットワーク戦線ではまだ新顔の部類に入るプロトコルだが、利用される場面は日に日に広がりつつあり TCP および UDP プロトコルの弱点を改善するものでもあるため、こうしてセクションを設けて解説することにした。 SCTP は TCP にも勝る高信頼性を備え、なお且つ、プロトコルヘッダの造りから、オーバーヘッドが低く抑えられている。
ということで実装してみました。
環境 : Ubuntu 14.04
SCTPclie.c (クライアント)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/sctp.h> #define PORTNO 12121 int main() { struct sockaddr_in servaddr; struct sctp_status status; struct sctp_sndrcvinfo sndrcvinfo; struct sctp_event_subscribe events; char buf[1024]; int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); bzero((void *)&servaddr, sizeof(servaddr) ); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORTNO); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); int ret = connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)); if(ret < 0){ perror("connect"); exit(1); } strcpy(buf, "Hello! from client 1"); sctp_sendmsg(sock, (void *)buf, (size_t)strlen(buf), NULL, 0, 0, 0, 0, 0, 0); strcpy(buf, "Hi! from client 2"); sctp_sendmsg(sock, (void *)buf, (size_t)strlen(buf), NULL, 0, 0, 0, 1, 0, 0); bzero(buf, sizeof(buf)); int flags; memset( (void *)&events, 0, sizeof(events) ); events.sctp_data_io_event = 1; setsockopt(sock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events) ); int n, suc = 0; for(n=0;n<10;n++){ int in = sctp_recvmsg(sock, buf, sizeof(buf), (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags); if(in > 0){ suc ++; } printf("Received : %s / Stream : %d\n", (char*)buf, sndrcvinfo.sinfo_stream); if(suc >= 2){ break; } } close(sock); return 0; } |
SCTPserv.c (サーバ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/sctp.h> #define PORTNO 12121 int main() { struct sockaddr_in servaddr, clieaddr; struct sctp_initmsg initmsg; struct sctp_event_subscribe events; struct sctp_sndrcvinfo sndrcvinfo; int lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); bzero((void *)&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORTNO); int ret = bind(lsock, (struct sockaddr *)&servaddr, sizeof(servaddr)); memset(&initmsg, 0, sizeof(initmsg)); initmsg.sinit_num_ostreams = 5; initmsg.sinit_max_instreams = 5; initmsg.sinit_max_attempts = 4; ret = setsockopt(lsock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); listen(lsock, 5); while( 1 ) { char buf[1024]; int flags ; printf("Listening port : %d ....\n", PORTNO); bzero((void *)&clieaddr, sizeof(clieaddr)); int sock = accept(lsock, (struct sockaddr *)NULL, (int *)0); if(sock == -1){ perror("accept"); exit(1); } memset( (void *)&events, 0, sizeof(events) ); events.sctp_data_io_event = 1; setsockopt(sock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events) ); int n; int suc = 0; for(n = 0; n < 10 ; n++){ bzero(buf, sizeof(buf)); int in = sctp_recvmsg(sock, buf, sizeof(buf), (struct sockaddr *)NULL, (socklen_t*)0, &sndrcvinfo, &flags); if(in > 0){ suc ++; } printf("Received : %s / Stream : %d\n", (char*)buf, sndrcvinfo.sinfo_stream); if(suc >= 2){ break; } } strcpy(buf, "Hello! from Server 1"); sctp_sendmsg(sock, (void *)buf, (size_t)strlen(buf), NULL, 0, 0, 0, 0, 0, 0); strcpy(buf, "Hello! from Server 2"); sctp_sendmsg(sock, (void *)buf, (size_t)strlen(buf), NULL, 0, 0, 0, 1, 0, 0); close(sock); } return 0; } |
下記サイトを参考にしました。
「SCTPによるネットワーキングの向上」
http://www.ibm.com/developerworks/jp/linux/library/l-sctp/
ストリームID(sndrcvinfo.sinfo_stream)を取得するのに、うまくできない時がありました。送信と受信を相互にすると、挙動が不安定なときがありました。(タイミングによるものかどうか) 一応上のようなやり方で安定して通信できるようになりましたが・・・失敗したときようにループを多めにまわしています。
コマンド
apt-get install libsctp-dev
cc -o SCTPclie SCTPclie.c -lsctp
cc -o SCTPserv SCTPserv.c -lsctp
あと、マルチホーミングによる障害対応にも興味がありますので、また機会があればテストしたみたいです。