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];  
 
  connSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP ); 
  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) );  
  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" );  
  ret = connect( connSock, (struct sockaddr *)&servaddr, sizeof(servaddr) );  
  memset( (void *)&events, 0, sizeof(events) );  
  events.sctp_data_io_event = 1;  
  ret = setsockopt( connSock, SOL_SCTP, SCTP_EVENTS,  
                     (const void *)&events, sizeof(events) );  
  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(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;  
  listenSock = 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(MY_PORT_NUM);  
  ret = bind( listenSock, (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( listenSock, IPPROTO_SCTP, SCTP_INITMSG,   
                     &initmsg, sizeof(initmsg) );  
  listen( listenSock, 5 );  
  while( 1 ) {  
    printf("Awaiting a new connection\n");  
    connSock = accept( listenSock, (struct sockaddr *)NULL, (int *)NULL );  
    currentTime = time(NULL);  
    snprintf( buffer, MAX_BUFFER, "%s\n", ctime(¤tTime) );  
    ret = sctp_sendmsg( connSock, (void *)buffer, (size_t)strlen(buffer),  
                         NULL, 0, 0, 0, LOCALTIME_STREAM, 0, 0 );  
    snprintf( buffer, MAX_BUFFER, "%s\n", asctime( gmtime( ¤tTime ) ) );  
    ret = sctp_sendmsg( connSock, (void *)buffer, (size_t)strlen(buffer),  
                         NULL, 0, 0, 0, GMT_STREAM, 0, 0 );  
    close( connSock );  
  }  
  return 0;  
}  
gcc -Wall -o sctpclnt  sctpclnt.c -lsctp  

gcc -Wall -o sctpsrvr  sctpsrvr.c -lsctp  


欢迎留言


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值