SCTP編程

1. 簡介
SCTP是爲了在IP網上傳輸信令而由IETF的信令傳輸工做組(SIGTRAN)提出的傳輸層協議(RFC2960,RFC4960)。 和TCP,UDP相比, UDP是無鏈接的傳輸協議,它能知足低延遲的要求,可是它卻沒法保證可靠傳輸。TCP能保證數據可靠傳輸,可是它也不能徹底符合信令傳輸的要求;TCP套接字不支持多宿性;TCP是面向比特流的,將數據傳輸看成是沒有結構的字節序列。

2. SCTP的基本概念

編程

  • 多宿性(multi-homing)

    多宿是指一個SCTP 端點能夠經過多個IP地址到達,這樣兩個SCTP端點在創建了關聯後,數據能夠經過不    同的物理通路進行傳送。也就是說,當一條通路壞掉後,能夠經過另外一條通路到達對端。安全

  • 多流性(multi-streaming)

    因爲採用多個流進行傳輸並且各個流相互獨立,這樣當一個流中的數據包須要重傳,其餘流中的數據能夠    繼續傳輸, 解決了在TCP單流中容易出現的隊頭阻塞現象(head-of-line).服務器

  • 安全機制

    SCTP採用「四次握手」的鏈接創建方式和COOKIE機制消除了SYN攻擊的威脅, Cookie機制設立的主要用意    是將狀態信息存儲在客戶端或者網絡上,而非服務器內存中,它的使用將服務器資源預留的時間推遲到了
    Cookie帶回完整的鑑別信息後。這是一種簡單有效的防護DoS攻擊的方法。

3. SCTP編程

Linux內核從2.6已經支持SCTP協議棧了,並且也提供了套接口(socket),
SCTP的套接口兩類:一對一(相似TCP)和一對多(相似UDP)。

網絡

  • 一對一


    而後客戶端能夠用connect()鏈接服務器, write(), read()讀寫,close()關閉套接口
    服務器端用bind()綁定端口,listen()監聽,accept()接受鏈接,write()/read()讀寫,
    close()  關閉,這和普通TCP程序是相同的。

socket

  • 一對多

    一對多方式的SCTP編程和UDP相似,打開的是SCTP的有序分組接口:
    socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)
    用的socket(), bin(), listen(), close()等函數和原來同樣,但發送接收數據是用
    sctp_sendto(),sctp_sendmsg()和sctp_recvmsg()這些SCTP專用函數。

4. 例子

   爲了使用方便使用SCTP的套接口,以下的文件須要安裝:

    rpm -ivh lksctp-tools-1.0.7-1.i386.rpm

    能夠用wget在
http://downloads.sourceforge.net/lksctp下面download.
  
    客戶端源代碼(
sctpclnt.c):


tcp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "common.h"

int main()
{
  int connSock, in, i, ret, flags;
  struct sockaddr_in servaddr;
  struct sctp_status status;
  struct sctp_sndrcvinfo sndrcvinfo;
  struct sctp_event_subscribe events;
  struct sctp_initmsg initmsg;
  char buffer[MAX_BUFFER+1];

  /* Create an SCTP TCP-Style Socket */
  connSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );

  /* Specify that a maximum of 5 streams will be available per socket */
  memset( &initmsg, 0, sizeof(initmsg) );
  initmsg.sinit_num_ostreams = 5;
  initmsg.sinit_max_instreams = 5;
  initmsg.sinit_max_attempts = 4;
  ret = setsockopt( connSock, IPPROTO_SCTP, SCTP_INITMSG,
                     &initmsg, sizeof(initmsg) );

  /* Specify the peer endpoint to which we'll connect */
  bzero( (void *)&servaddr, sizeof(servaddr) );
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(MY_PORT_NUM);
  servaddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );

  /* Connect to the server */
  ret = connect( connSock, (struct sockaddr *)&servaddr, sizeof(servaddr) );

  /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */
  memset( (void *)&events, 0, sizeof(events) );
  events.sctp_data_io_event = 1;
  ret = setsockopt( connSock, SOL_SCTP, SCTP_EVENTS,
                     (const void *)&events, sizeof(events) );

  /* Read and emit the status of the Socket (optional step) */
  in = sizeof(status);
  ret = getsockopt( connSock, SOL_SCTP, SCTP_STATUS,
                     (void *)&status, (socklen_t *)&in );

  printf("assoc id = %d\n", status.sstat_assoc_id );
  printf("state = %d\n", status.sstat_state );
  printf("instrms = %d\n", status.sstat_instrms );
  printf("outstrms = %d\n", status.sstat_outstrms );

  /* Expect two messages from the peer */

  for (i = 0 ; i < 2 ; i++) {

    in = sctp_recvmsg( connSock, (void *)buffer, sizeof(buffer),
                        (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags );

    if (in > 0) {
      buffer[in] = 0;
      if (sndrcvinfo.sinfo_stream == LOCALTIME_STREAM) {
        printf("(Local) %s\n", buffer);
      } else if (sndrcvinfo.sinfo_stream == GMT_STREAM) {
        printf("(GMT ) %s\n", buffer);
      }
    }

  }

  /* Close our socket and exit */
  close(connSock);

  return 0;
}

函數



服務器端源代碼(sctpsrvr.c):


oop

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include "common.h"

int main()
{
  int listenSock, connSock, ret;
  struct sockaddr_in servaddr;
  struct sctp_initmsg initmsg;
  char buffer[MAX_BUFFER+1];
  time_t currentTime;

  /* Create SCTP TCP-Style Socket */
  listenSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );

  /* Accept connections from any interface */
  bzero( (void *)&servaddr, sizeof(servaddr) );
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
  servaddr.sin_port = htons(MY_PORT_NUM);

  ret = bind( listenSock, (struct sockaddr *)&servaddr, sizeof(servaddr) );

  /* Specify that a maximum of 5 streams will be available per socket */
  memset( &initmsg, 0, sizeof(initmsg) );
  initmsg.sinit_num_ostreams = 5;
  initmsg.sinit_max_instreams = 5;
  initmsg.sinit_max_attempts = 4;
  ret = setsockopt( listenSock, IPPROTO_SCTP, SCTP_INITMSG,
                     &initmsg, sizeof(initmsg) );

  /* Place the server socket into the listening state */
  listen( listenSock, 5 );

  /* Server loop... */
  while( 1 ) {

    /* Await a new client connection */
    printf("Awaiting a new connection\n");
    connSock = accept( listenSock, (struct sockaddr *)NULL, (int *)NULL );

    /* New client socket has connected */

    /* Grab the current time */
    currentTime = time(NULL);

    /* Send local time on stream 0 (local time stream) */
    snprintf( buffer, MAX_BUFFER, "%s\n", ctime(&currentTime) );
    ret = sctp_sendmsg( connSock, (void *)buffer, (size_t)strlen(buffer),
                         NULL, 0, 0, 0, LOCALTIME_STREAM, 0, 0 );

    /* Send GMT on stream 1 (GMT stream) */
    snprintf( buffer, MAX_BUFFER, "%s\n", asctime( gmtime( &currentTime ) ) );
    ret = sctp_sendmsg( connSock, (void *)buffer, (size_t)strlen(buffer),
                         NULL, 0, 0, 0, GMT_STREAM, 0, 0 );

    /* Close the client connection */
    close( connSock );

  }

  return 0;
}
spa



分別編譯sctpclnt.c, sctpsrvr.c:

gcc -Wall -o sctpclnt sctpclnt.c -lsctp
gcc -Wall -o sctpsrvr sctpsrvr.c -lsctp

分別運行sctpsrvr和sctpclnt, 使用ethereal(wireshark)或者tcpdump來抓包。附件就是我抓的IP數據包。.net

 

1. 簡介
SCTP是爲了在IP網上傳輸信令而由IETF的信令傳輸工做組(SIGTRAN)提出的傳輸層協議(RFC2960,RFC4960)。 和TCP,UDP相比, UDP是無鏈接的傳輸協議,它能知足低延遲的要求,可是它卻沒法保證可靠傳輸。TCP能保證數據可靠傳輸,可是它也不能徹底符合信令傳輸的要求;TCP套接字不支持多宿性;TCP是面向比特流的,將數據傳輸看成是沒有結構的字節序列。

2. SCTP的基本概念

  • 多宿性(multi-homing)

    多宿是指一個SCTP 端點能夠經過多個IP地址到達,這樣兩個SCTP端點在創建了關聯後,數據能夠經過不    同的物理通路進行傳送。也就是說,當一條通路壞掉後,能夠經過另外一條通路到達對端。

  • 多流性(multi-streaming)

    因爲採用多個流進行傳輸並且各個流相互獨立,這樣當一個流中的數據包須要重傳,其餘流中的數據能夠    繼續傳輸, 解決了在TCP單流中容易出現的隊頭阻塞現象(head-of-line).

  • 安去機制

    CTP採用「四次握手」的鏈接創建方式和COOKIE機制消除了SYN攻擊的威脅, Cookie機制設立的主要用意    是將狀態信息存儲在客戶端或者網絡上,而非服務器內存中,它的使用將服務器資源預留的時間推遲到了
    Cookie帶回完整的鑑別信息後。這是一種簡單有效的防護DoS攻擊的方法。

3. SCTP編程

Linux內核從2.6已經支持SCTP協議棧了,並且也提供了套接口(socket),
SCTP的套接口兩類:一對一(相似TCP)和一對多(相似UDP)。

  • 一對一


    而後客戶端能夠用connect()鏈接服務器, write(), read()讀寫,close()關閉套接口
    服務器端用bind()綁定端口,listen()監聽,accept()接受鏈接,write()/read()讀寫,
    close()  關閉,這和普通TCP程序是相同的。

  • 一對多

    一對多方式的SCTP編程和UDP相似,打開的是SCTP的有序分組接口:
    socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)
    用的socket(), bin(), listen(), close()等函數和原來同樣,但發送接收數據是用
    sctp_sendto(),sctp_sendmsg()和sctp_recvmsg()這些SCTP專用函數。

4. 例子

   爲了使用方便使用SCTP的套接口,以下的文件須要安裝:

    rpm -ivh lksctp-tools-1.0.7-1.i386.rpm

    能夠用wget在
http://downloads.sourceforge.net/lksctp下面download.
  
    客戶端源代碼(
sctpclnt.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "common.h"

int main()
{
  int connSock, in, i, ret, flags;
  struct sockaddr_in servaddr;
  struct sctp_status status;
  struct sctp_sndrcvinfo sndrcvinfo;
  struct sctp_event_subscribe events;
  struct sctp_initmsg initmsg;
  char buffer[MAX_BUFFER+1];

  /* Create an SCTP TCP-Style Socket */
  connSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );

  /* Specify that a maximum of 5 streams will be available per socket */
  memset( &initmsg, 0, sizeof(initmsg) );
  initmsg.sinit_num_ostreams = 5;
  initmsg.sinit_max_instreams = 5;
  initmsg.sinit_max_attempts = 4;
  ret = setsockopt( connSock, IPPROTO_SCTP, SCTP_INITMSG,
                     &initmsg, sizeof(initmsg) );

  /* Specify the peer endpoint to which we'll connect */
  bzero( (void *)&servaddr, sizeof(servaddr) );
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(MY_PORT_NUM);
  servaddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );

  /* Connect to the server */
  ret = connect( connSock, (struct sockaddr *)&servaddr, sizeof(servaddr) );

  /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */
  memset( (void *)&events, 0, sizeof(events) );
  events.sctp_data_io_event = 1;
  ret = setsockopt( connSock, SOL_SCTP, SCTP_EVENTS,
                     (const void *)&events, sizeof(events) );

  /* Read and emit the status of the Socket (optional step) */
  in = sizeof(status);
  ret = getsockopt( connSock, SOL_SCTP, SCTP_STATUS,
                     (void *)&status, (socklen_t *)&in );

  printf("assoc id = %d\n", status.sstat_assoc_id );
  printf("state = %d\n", status.sstat_state );
  printf("instrms = %d\n", status.sstat_instrms );
  printf("outstrms = %d\n", status.sstat_outstrms );

  /* Expect two messages from the peer */

  for (i = 0 ; i < 2 ; i++) {

    in = sctp_recvmsg( connSock, (void *)buffer, sizeof(buffer),
                        (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags );

    if (in > 0) {
      buffer[in] = 0;
      if (sndrcvinfo.sinfo_stream == LOCALTIME_STREAM) {
        printf("(Local) %s\n", buffer);
      } else if (sndrcvinfo.sinfo_stream == GMT_STREAM) {
        printf("(GMT ) %s\n", buffer);
      }
    }

  }

  /* Close our socket and exit */
  close(connSock);

  return 0;
}


服務器端源代碼(sctpsrvr.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include "common.h"

int main()
{
  int listenSock, connSock, ret;
  struct sockaddr_in servaddr;
  struct sctp_initmsg initmsg;
  char buffer[MAX_BUFFER+1];
  time_t currentTime;

  /* Create SCTP TCP-Style Socket */
  listenSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );

  /* Accept connections from any interface */
  bzero( (void *)&servaddr, sizeof(servaddr) );
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
  servaddr.sin_port = htons(MY_PORT_NUM);

  ret = bind( listenSock, (struct sockaddr *)&servaddr, sizeof(servaddr) );

  /* Specify that a maximum of 5 streams will be available per socket */
  memset( &initmsg, 0, sizeof(initmsg) );
  initmsg.sinit_num_ostreams = 5;
  initmsg.sinit_max_instreams = 5;
  initmsg.sinit_max_attempts = 4;
  ret = setsockopt( listenSock, IPPROTO_SCTP, SCTP_INITMSG,
                     &initmsg, sizeof(initmsg) );

  /* Place the server socket into the listening state */
  listen( listenSock, 5 );

  /* Server loop... */
  while( 1 ) {

    /* Await a new client connection */
    printf("Awaiting a new connection\n");
    connSock =

相關文章
相關標籤/搜索