一到一形式套接字是一个类型为SOCK_STREAM,协议为IPPROTO_SCTP的网际套接字。
服务器程序无需管理大量的套接字描述符,单个套接字描述符将代表多个关联。在一到多形式的套接字上,用“关联标识”来标识单个连接。
一到多形式套接字是一个类型为SOCK_SEQPACKET,协议为IPPROTO_SCTP的网际套接字。
(1)SCTP一到多式流分回射服务器
stcp_sndrcvinfo结构体:(UNIX网络编程P175)
struct sctp_sndrcvinfo
{
u_int16_t sinfo_stream; //指定新的默认流,所有外出消息将被发送到该流中
u_int16_t sinfo_ssn;
u_int16_t sinfo_flags;
u_int32_t sinfo_ppid; //置于所有外出消息的SCTP净荷协议标识字段的默认值
u_int32_t sinfo_context; //指定新的默认上下文,用于检索无法发送到对端的消息
u_int32_t sinfo_timetolive; //指定新的默认生命周期
u_int32_t sinfo_tsn;
u_int32_t sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
}
#include "unp.h"
int
main(int argc, char **argv)
{
int sock_fd,msg_flags;
char readbuf[BUFFSIZE];
struct sockaddr_in servaddr, cliaddr;
struct sctp_sndrcvinfo sri;
struct sctp_event_subscribe evnts; //SCTP通知结构p176
int stream_increment=1; //决定增长外来消息的流号
socklen_t len;
size_t rd_sz;
if (argc == 2)
stream_increment = atoi(argv[1]);
sock_fd = Socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); //创建一到多式的SCTP套接字
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //捆绑通配地址,表示将在建立的任何关联中使用所有可用的本地地址
servaddr.sin_port = htons(SERV_PORT);
Bind(sock_fd, (SA *) &servaddr, sizeof(servaddr));
bzero(&evnts, sizeof(evnts));
evnts.sctp_data_io_event = 1; //仅仅预定sctp_data_io_event,开启每次recvmsg调用返回sctp_sndrcvinfo
Setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, //设置SCTP_EVENTS,修改SCTP套接字的通知预定
&evnts, sizeof(evnts));
Listen(sock_fd, LISTENQ);
for ( ; ; ) {
len = sizeof(struct sockaddr_in);
rd_sz = Sctp_recvmsg(sock_fd, readbuf, sizeof(readbuf),
(SA *)&cliaddr, &len,
&sri,&msg_flags); //阻塞在等待来自任何一个远程对端的消息之上
if(stream_increment) { //如果设置了stream_increment标识变量
sri.sinfo_stream++;
if(sri.sinfo_stream >= sctp_get_no_strms(sock_fd,(SA *)&cliaddr, len))
sri.sinfo_stream = 0;
}
Sctp_sendmsg(sock_fd, readbuf, rd_sz,
(SA *)&cliaddr, len,
sri.sinfo_ppid,
sri.sinfo_flags,
sri.sinfo_stream,
0, 0); //使用来自sri结构的净荷协议ID、标识以及可能改动过的流号发送回消息本身
}
}
(2)SCTP一到多式流分回射客户程序:
#include "unp.h"
void
sctpstr_cli(FILE *fp, int sock_fd, struct sockaddr *to, socklen_t tolen)
{
struct sockaddr_in peeraddr;
struct sctp_sndrcvinfo sri;
char sendline[MAXLINE], recvline[MAXLINE];
socklen_t len;
int out_sz,rd_sz;
int msg_flags;
bzero(&sri,sizeof(sri));
while (fgets(sendline, MAXLINE, fp) != NULL) {
if(sendline[0] != '[') { // 检测用户输入是否符合[#]text
printf("Error, line must be of the form '[streamnum]text'\n");
continue;
}
sri.sinfo_stream = strtol(&sendline[1],NULL,0); //客户把用户在输入请求中的请求的流号转换成sri结构的sinfo_stream
out_sz = strlen(sendline);
Sctp_sendmsg(sock_fd, sendline, out_sz,
to, tolen,
0, 0,
sri.sinfo_stream,
0, 0); // 发送消息
len = sizeof(peeraddr);
rd_sz = Sctp_recvmsg(sock_fd, recvline, sizeof(recvline),
(SA *)&peeraddr, &len,
&sri,&msg_flags); // 客户阻塞,等待服务器回射的消息
printf("From str:%d seq:%d (assoc:0x%x):",
sri.sinfo_stream,sri.sinfo_ssn,
(u_int)sri.sinfo_assoc_id); //显示回射消息:流号、流序列号、文本消息本身
printf("%.*s",rd_sz,recvline);
}
}
#define SCTP_MAXLINE 800
void sctpstr_cli_echoall(FILE *fp, int sock_fd, struct sockaddr *to, socklen_t tolen)
{
struct sockaddr_in peeraddr;
struct sctp_sndrcvinfo sri;
char sendline[SCTP_MAXLINE], recvline[SCTP_MAXLINE];
socklen_t len;
int rd_sz,i,strsz;
int msg_flags;
bzero(sendline,sizeof(sendline));
bzero(&sri,sizeof(sri)); // 初始化用于建立各个流的sri结构,客户的数据发送和数据接收将通过这些流进行
while (fgets(sendline, SCTP_MAXLINE - 9, fp) != NULL)
{
strsz = strlen(sendline);
if(sendline[strsz-1] == '\n') {
sendline[strsz-1] = '\0';
strsz--;
}
for(i=0;i 2) {
printf("Echoing messages to all streams\n");
echo_to_all = 1;
}
sock_fd = Socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr); //把通过命令行传递的服务器地址从表达式转换成数值格式
bzero(&evnts, sizeof(evnts));
evnts.sctp_data_io_event = 1; //仅仅预定sctp_data_io_event,开启每次recvmsg调用返回sctp_sndrcvinfo
Setsockopt(sock_fd,IPPROTO_SCTP, SCTP_EVENTS,
&evnts, sizeof(evnts)); //设置SCTP_EVENTS,修改SCTP套接字的通知预定
if(echo_to_all == 0)
sctpstr_cli(stdin,sock_fd,(SA *)&servaddr,sizeof(servaddr));
else
sctpstr_cli_echoall(stdin,sock_fd,(SA *)&servaddr,sizeof(servaddr));
Close(sock_fd);
return(0);
}