zoukankan      html  css  js  c++  java
  • 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).
    安去机制
        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
    ", status.sstat_assoc_id );
      printf("state     = %d
    ", status.sstat_state );
      printf("instrms   = %d
    ", status.sstat_instrms );
      printf("outstrms  = %d
    ", 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
    ", buffer);
          } else if (sndrcvinfo.sinfo_stream == GMT_STREAM) {
            printf("(GMT  ) %s
    ", 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
    ");
        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
    ", ctime(¤tTime) );
        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
    ", asctime( gmtime( ¤tTime ) ) );
        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;
    }
    分别编译sctpclnt.c, sctpsrvr.c:
    gcc -Wall -o sctpclnt  sctpclnt.c -lsctp
    gcc -Wall -o sctpsrvr  sctpsrvr.c -lsctp
    分别运行sctpsrvr和sctpclnt, 使用ethereal(wireshark)或者tcpdump来抓包。附件就是我抓的IP数据包。

  • 相关阅读:
    Vector Dictionary HashMap
    崩溃java (打印当前类的地址)
    colspan、rowspan的使用
    基础操作
    安装vuex-devtools插件
    在使用Vuex插件进行状态管理的步骤
    运行cnpm run dev出现错误解决办法
    在使用vue开发时,文件路径的引用(给文件起别名)
    下载脚手架vue.cli出现的问题
    什么是闭包?
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318225.html
Copyright © 2011-2022 走看看