/* SCTP一到多式流分回射服务器程序 */ /* server.c */ #include "wrapper.c" #define SERV_PORT 8888 #define LISTENQ 128 int main(int argc, char **argv) { int sockfd, msg_flags; // msg_flags参数中存放可能有的消息标志 char buf[BUFSIZ]; struct sockaddr_in servaddr, clieaddr; struct sctp_sndrcvinfo sri; // 存放与消息相关的细节信息 struct sctp_event_subscribe evnts; int stream_increment = 1; socklen_t len; size_t n; if (argc == 2) { stream_increment = atoi(argv[1]); } // 创建一个SCTP一到多式套接字 sockfd = Socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); Bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); // 设置套接字选项 bzero(&evnts, sizeof(evnts)); evnts.sctp_data_io_event = 1; Setsockopt(sockfd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)); Listen(sockfd, LISTENQ); while (1) { len = sizeof(clieaddr); n = Sctp_recvmsg(sockfd, buf, BUFSIZ, (struct sockaddr*)&clieaddr, &len, &sri, &msg_flags); if (stream_increment) { sri.sinfo_stream++; // sctp_get_no_strms函数用来获取最大流号 if (sri.sinfo_stream >= sctp_get_no_strms(sockfd, (struct sockaddr*)&clieaddr, len, sri)) { sri.sinfo_stream = 0; } } Sctp_sendmsg(sockfd, buf, n, (struct sockaddr*)&clieaddr, len, sri.sinfo_ppid, sri.sinfo_flags, sri.sinfo_stream, 0, 0); } return 0; }
/* SCTP一到多式流分回射客户程序*/ /* client.c */ #include "wrapper.c" #define SERV_PORT 8888 #define SERV_MAX_SCTP_STRM 10 /* normal maximum streams */ void sctpstr_cli(FILE * fp, int sockfd, struct sockaddr *to, socklen_t tolen) { struct sockaddr_in peeraddr; struct sctp_sndrcvinfo sri; char sendline[BUFSIZ], recvline[BUFSIZ]; socklen_t len; int out_sz, rd_sz; int msg_flags; bzero(&sri, sizeof(sri)); while (fgets(sendline, BUFSIZ, fp) != NULL) { if (sendline[0] != '[') { printf("error, line must be of the form '[streamnum]text'\n"); continue; } sri.sinfo_stream = strtol(&sendline[1], NULL, 0); out_sz = strlen(sendline); Sctp_sendmsg(sockfd, sendline, out_sz, to, tolen, 0, 0, sri.sinfo_stream, 0, 0); len = sizeof(peeraddr); rd_sz = Sctp_recvmsg(sockfd, recvline, sizeof(recvline), (struct sockaddr*)&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); } } void sctpstr_cli_echoall(FILE * fp, int sockfd, struct sockaddr *to, socklen_t tolen) { struct sockaddr_in peeraddr; struct sctp_sndrcvinfo sri; char sendline[BUFSIZ], recvline[BUFSIZ]; socklen_t len; int rd_sz, i, strsz; int msg_flags; bzero(sendline, sizeof(sendline)); bzero(&sri, sizeof(sri)); while (fgets(sendline, BUFSIZ - 9, fp) != NULL) { strsz = strlen(sendline); if (sendline[strsz-1] == '\n') { sendline[strsz-1] = '\0'; strsz--; } for (i = 0; i < SERV_MAX_SCTP_STRM; i++) { snprintf(sendline + strsz, sizeof(sendline) - strsz, ".msg.%d", i); Sctp_sendmsg(sockfd, sendline, sizeof(sendline), to, tolen, 0, 0, i, 0, 0); } for (i = 0; i < SERV_MAX_SCTP_STRM; i++) { len = sizeof(peeraddr); rd_sz = Sctp_recvmsg(sockfd, recvline, sizeof(recvline), (struct sockaddr*)&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\n", rd_sz, recvline); } } } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; struct sctp_event_subscribe evnts; int echo_to_all = 0; // 验证参数并创建一个套接字 if (argc < 2) perr_exit("Missing host argument\n"); if (argc > 2) { printf("Echoing messages to all streams\n"); echo_to_all = 1; } sockfd = 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; Setsockopt(sockfd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)); // 调用回射处理函数 if(echo_to_all == 0) sctpstr_cli(stdin, sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); else sctpstr_cli_echoall(stdin, sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); // 结束处理 Close(sockfd); return 0; }
/* wrapper.c */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/sctp.h> #include <netinet/in.h> #include <arpa/inet.h> void perr_exit(const char * s) { perror(s); exit(1); } int Socket(int domain, int type, int protocol) { int sockfd; sockfd = socket(domain, type, protocol); if (sockfd == -1) { perr_exit("socket error"); } return sockfd; } void Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int n; n = connect(sockfd, addr, addrlen); if (n == -1) { perr_exit("connect error"); } } void Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int n; n = bind(sockfd, addr, addrlen); if (n == -1) { perr_exit("bind error"); } } void Listen(int sockfd, int backlog) { int n; n = listen(sockfd, backlog); if (n == -1) { perr_exit("listen error"); } } int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { int connfd; connfd = accept(sockfd, addr, addrlen); if (connfd == -1) { perr_exit("accept error"); } return connfd; } void Getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) { if (getsockopt(fd, level, optname, optval, optlen) < 0) perr_exit("getsockopt error"); } void Setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) { if (setsockopt(fd, level, optname, optval, optlen) < 0) perr_exit("setsockopt error"); } ssize_t Sctp_recvmsg(int sockfd, void *msg, size_t len, struct sockaddr *from, socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags) { int ret; ret = sctp_recvmsg(sockfd, msg, len, from, fromlen, sinfo, msg_flags); if (ret < 0) { perr_exit("sctp_recvmsg error"); } return ret; } ssize_t Sctp_sendmsg (int sockfd, const void *msg, size_t len, struct sockaddr *to, socklen_t tolen, uint32_t ppid, uint32_t flags, uint16_t stream, uint32_t timetolive, uint32_t context) { int ret; ret = sctp_sendmsg(sockfd, msg, len, to, tolen, ppid, flags, stream, timetolive, context); if(ret < 0) { perr_exit("sctp_sendmsg error"); } return(ret); } void Close(int fd) { int n; n = close(fd); if (n == -1) { perr_exit("close error"); } } void Inet_pton(int af, const char *src, void *dst) { int res; res = inet_pton(af, src, dst); if (res == 0) perr_exit("src soes not contain a character"); else if (res == -1) perr_exit("inet_pton error"); } /**********************************************************************************/ /* 程序取自UNP-V1-3Edtion源码中sctp/sctp_addr_to_associd.c, sctp/sctp_getnostrm.c */ sctp_assoc_t sctp_address_to_associd(int sock_fd, struct sockaddr *sa, socklen_t salen) { struct sctp_paddrparams sp; int siz; int n; siz = sizeof(struct sctp_paddrparams); bzero(&sp,siz); memcpy(&sp.spp_address,sa,salen); n = sctp_opt_info(sock_fd,0, SCTP_PEER_ADDR_PARAMS, &sp, &siz); if (n == -1) { perr_exit("sctp_opt_info error"); } return(sp.spp_assoc_id); } int sctp_get_no_strms(int sock_fd,struct sockaddr *to, socklen_t tolen, struct sctp_sndrcvinfo sri) { int retsz; struct sctp_status status; retsz = sizeof(status); bzero(&status,sizeof(status)); //status.sstat_assoc_id = sctp_address_to_associd(sock_fd,to,tolen); status.sstat_assoc_id = sri.sinfo_assoc_id; Getsockopt(sock_fd,IPPROTO_SCTP, SCTP_STATUS, &status, &retsz); return(status.sstat_outstrms); } /**********************************************************************************/