在学习使用SCTP之前,你要确定操作系统是否安装了SCTP协议的相关库文件。我使用的是Ubuntu,安装方法如下:
sudo apt-get install libsctp-dev lksctp-tools
当你安装成功后,可以用如下代码来测试SCTP服务器,这是一个简单的回射服务:
sctp_darn -H 0 -P 2500 -l
然后打开另一个终端,输入下面的代码来启动一个客户端:
sctp_darn -H 0 -P 2600 -h 127.0.0.1 -p 2500 -s
安装完成后,在编译链接时,需要加上-lsctp选项。
在编写书中第十章(10.3)的SCTP服务器程序,和10.4的客户程序时,会报错。下面我们来一个一个看
问题1: “redefinition of ‘struct in_pktinof’”
意思是该结构体重定义了,原因是该结构已经包含在标准头文件“bits/in.h”中了,你只需要注释掉unp.h中的如下内容即可:
struct unp_in_pktinfo {
struct in_addr ipi_addr; /* dst IPv4 address */
int ipi_ifindex;/* received interface index */
};
问题2:”undefined reference to ‘Sctp_recvmsg’ and ‘Sctp_sendmsg’”
这两个函数都是作者编写的包裹函数,他们并不在“unpv13e/lib”中,在unp.h中也没有声明,也就说他们没有被编译到库libunp.a中。有关sctp的相关函数在文件夹unpv13e/sctp中,将文件“sctp_addr_to_associd.c 、sctp_getnostrm.c、sctp_wrapper.c”复制到你自己编写的程序所在目录,并将你需要用的包裹函数的声明在你的源代码中,或者unp.h中,不然会报隐式函数声明的警告。之后在编译自己的程序时加上这三个文件就好了,我以自己写的Makefile为例。我在当前目录下,写了sctpserv01.c和sctpclient01.c。Makefile文件内容如下:
#编译对象的名称
PROGS = sctpserv01 sctpclient01
#链接库
LIBS+= -lsctp -lunp
#编译参数
CFLAGS= -g
#链接需要的.o文件
OBJECT= sctp_wrapper.o sctp_getnostrm.o sctp_addr_to_associd.o
#编译器gcc
CC= gcc
all: ${PROGS}
sctpserv01: sctpserv01.o ${OBJECT}
${CC} ${CFLAGS} -o $@ $^ ${LIBS}
sctpclient01: sctpclient01.o ${OBJECT}
${CC} ${CFLAGS} -o $@ $^ ${LIBS}
sctp_wrapper: sctp_wrapper.o
${CC} ${CFLAGS} -o ${LIBS}
sctp_getnostrm: sctp_getnostrm.o
${CC} ${CFLAGS} -o ${LIBS}
sctp_addr_to_associd: sctp_addr_to_associd.o
${CC} ${CFLAGS} -o ${LIBS}
像这样就可以解决上面的问题了。但是在编译后,运行服务器和客户程序时,在客户端程序中输入需要回射的文本,服务器进程异常退出,并打印如下消息:
getsockopt error: Invalid argument
这就是第三个问题
问题3:getsockopt error: Invalid argument
在stackoverflow上找到了解决办法,需要对源代码进行修改,需要修改使用了函数“sctp_get_no_strms”的文件以及sctp_getnostrm.c文件,修改前后内容如下:
1、sctpserv01.c
// origin
if(sri.sinof_stream >= sctp_get_no_strms(sock_fd, (SA *)&cliaddr, len))
// after
if(sri.sinof_stream >= sctp_get_no_strms(sock_fd, (SA *)&cliaddr, len, sri))
2、sctp_getnostrm.c
// origin
status.sstat_assoc_id = sctp_address_to_associd(sock_fd,to,tolen);
Getsockopt(sock_fd,IPPROTO_SCTP, SCTP_STATUS,
&status, &retsz);
// after
status.sstat_assoc_id = sri.sinfo_assoc_id;
Getsockopt(sock_fd, IPPROTO_SCTP, SCTP_STATUS, &status, &retsz);
修改后重新编译就好了。