Chinaunix首页 | 论坛 | 博客
  • 博客访问: 217801
  • 博文数量: 19
  • 博客积分: 45
  • 博客等级: 民兵
  • 技术积分: 241
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-23 20:00
个人简介

如明日将死那样生活,如永远不死那样求知。

文章分类

全部博文(19)

文章存档

2018年(2)

2017年(3)

2015年(2)

2013年(11)

2012年(1)

我的朋友

分类: 网络与安全

2013-10-14 16:37:08

首先,并不是所有的操作系统都支持SCTP协议了。
一般,我是喜欢有root权限的。先安装sctp
apt-get install libsctp-dev
apt-get install lksctp-tools

有兴趣的可以把代码下载看一下
apt-get source lksctp-tools

(1)先说服务端吧
以IPV4为例,以下语句可以建立一个socket的描述符
  1. sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
  2. if (sockfd < 0) {
  3.     perror("socket() ");
  4.     return -1;
  5. }
顺带说一下,在打印errno之前,可以将errno记录在一个变量里,然后打印这个变量,目的是为了防止打印函数本身出错而改变了errno。
如果有兴趣的话,可以看一下 errno (http://blog.chinaunix.net/uid-20753106-id-3944921.html)
对于一对多套接字:
  1. socket(AF_INET, SOCK_SEQPACKET, IPPROTO_STCP);
对于基于IPV6地址的情况:
  1. socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_STCP);
为了让socket在接收数据时可以看到发送时相关的一些选项信息,可以设置以下选项
  1. struct sctp_event_subscribe events = {0};

  2. /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */
  3. memset( (void *)&events, 0, sizeof(events) );
  4. events.sctp_data_io_event = 1;
  5. res = setsockopt(sockfd, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events));
绑定IP地址:sctp是支持多宿的,如果要绑定的IP地址只有一个,当然还是可以用bind()函数的。但是,我们是要想研究怎么用sctp,所以本文尽量都用sctp_XXX()的函数了。
  1. serv_addr[0].sin_family = AF_INET;
  2. serv_addr[0].sin_port = htons(LOCAL_PORT);
  3. serv_addr[0].sin_addr.s_addr = inet_addr(LOCAL_IP);
  4. res = sctp_bindx(sockfd, (struct sockaddr *)serv_addr, SERVER_NUM, SCTP_BINDX_ADD_ADDR);

服务端 listen
  1. res = listen(sockfd, 20);

等待accept
  1. fd = accept(sockfd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
本文的例子中,使用的是一对一的套接字。而对于一对多的套接字,accept()函数返回的结果一直都是-1,一对多的套接字的情况,后续有机会再研究吧。

接入客户端以后就可以收发数据了。

下面先说client的建立,再说收、发接口吧。突然感觉内容很单薄,自己记自己看吧。
(2)客户端的建立
到绑定地址的阶段跟server端是一样的,但是后续的,对于服务端是 listen & accept,对于客户端是 connect。

connect到服务端
  1. serv_addr[0].sin_family = AF_INET;
  2. serv_addr[0].sin_port = htons(SERVER_PORT);
  3. serv_addr[0].sin_addr.s_addr = inet_addr(SERVER_IP);
  4. res = sctp_connectx(sockfd, (struct sockaddr *)serv_addr, SERVER_NUM, &sid);
在connect时,可以设置超时间,其实还有一种是非阻塞的connect方式。将来肯定会根据ubuntu或者SUSE的linux系统来研究一下这个问题。

(3)数据收发
接收:
  1. int sctp_recvmsg(int sd, void * msg, size_t len,
  2.                 struct sockaddr * from, socklen_t * fromlen,
  3.                 struct sctp_sndrcvinfo * sinfo, int * msg_flags);

参数名

I/O

说明

备注

sd

I

socket描述符

 

msg

I

消息指针

 

len

I

消息长度

 

from

I

源地址

 

fromlen

I

源地址长度

 

sinfo

I

消息的选项信息

需要启用套接字选项 sctp_data_io_event

msg_flags

I

消息标识符

 















sctp_sndrcvinfo 结构体定义如下:
  1. struct sctp_sndrcvinfo {
  2.     __u16 sinfo_stream;
  3.     __u16 sinfo_ssn;
  4.     __u16 sinfo_flags;
  5.     __u32 sinfo_ppid;
  6.     __u32 sinfo_context;
  7.     __u32 sinfo_timetolive;
  8.     __u32 sinfo_tsn;
  9.     __u32 sinfo_cumtsn;
  10.     sctp_assoc_t sinfo_assoc_id;
  11. };

类型

成员名

说明

备注

__u16

sinfo_stream;

目标流

 

__u16

sinfo_ssn;

流序号

 

__u16

sinfo_flags;

标识符

 

__u32

sinfo_ppid;

有效负荷协议标识符

 

__u32

sinfo_context;

出错返回值

 

__u32

sinfo_timetolive;

等待时间

 

__u32

sinfo_tsn;

传输序号

 

__u32

sinfo_cumtsn;

累积TSN

 

sctp_assoc_t

sinfo_assoc_id

关联ID

 


发送:
  1. int sctp_sendmsg(int sd, const void * msg, size_t len,
  2.                 struct sockaddr *to, socklen_t tolen,
  3.                 uint32_t ppid, uint32_t flags,
  4.                 uint16_t stream_no, uint32_t timetolive,
  5.                 uint32_t context);

参数名

I/O

说明

备注

Sd

I

socket描述符

 

msg

I

消息指针

 

len

I

消息长度

 

to

I

目的地址

 

tolen

I

目的地址长度

 

ppid

I

应用指定的有效负荷协议标识符

 

flags

I

发送标识符

 

stream_no

I

目标流

 

timetoive

 

等待时间

此值为消息未能成功发送到对等方的情况下消息过期之前可以等待的时间段,以毫秒为单位。

context

I

出错返回值

如果在发送消息时出现错误,则返回此值。






















后续想到了再加,发现有时候做过的也想不起来,也说不出来,呵呵。
阅读(3244) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~