注:一定要通过setsockopt函数开启sctp_io_data_event事件,否则得到的关联号可能为0,从而调用getpeeloff失败
服务器端代码:
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/sctp.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#define BUFSIZE 4096
#define LISTENQ 100
const char* Inet_ntop(void* ptr) {
static char str[INET_ADDRSTRLEN];
return inet_ntop(AF_INET,ptr,str,INET_ADDRSTRLEN);
}
static void sig_child(int signo) {
int pid;
while ((pid = waitpid(-1,NULL,WNOHANG)) > 0) {
printf("child process %d terminated\n",pid);
}
}
void server_echo(int sockfd) {
struct sctp_sndrcvinfo sri;
struct sockaddr_in clientaddr;
socklen_t len = sizeof(struct sockaddr_in);
int pid;
char buf[BUFSIZE];
ssize_t n;
int connfd;
sctp_assoc_t id;
bzero(&sri,sizeof(struct sctp_sndrcvinfo));
struct sctp_event_subscribe events;
bzero(&events,sizeof(struct sctp_event_subscribe));
events.sctp_data_io_event = 1;
if (setsockopt(sockfd,IPPROTO_SCTP,SCTP_EVENTS,&events,sizeof(struct sctp_event_subscribe)) < 0) {
printf("setsockopt error: %s\n",strerror(errno));
exit(1);
}
while ((n = sctp_recvmsg(sockfd,buf,BUFSIZE,(struct sockaddr*)&clientaddr,&len,&sri,&len)) > 0) {
if (sctp_sendmsg(sockfd,n,len,0,2,0) != n) {
printf("sctp_sendmsg error: %s\n",strerror(errno));
break;
}
if ((connfd = sctp_peeloff(sockfd,sri.sinfo_assoc_id)) < 0) {
printf("sctp_peeloff error: %s\n",strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
printf("fork error: %s\n",strerror(errno));
exit(1);
}else if (pid == 0) {
char childbuf[BUFSIZE];
ssize_t n;
struct sockaddr_in peer;
socklen_t peerlen = sizeof(struct sockaddr_in);
struct sctp_sndrcvinfo csri;
int cflags;
while ((n = sctp_recvmsg(connfd,childbuf,(struct sockaddr*)&peer,&peerlen,&csri,&cflags)) > 0) {
printf("child process pid = %d from IP: %s\n",getpid(),Inet_ntop(&peer.sin_addr));
if (sctp_sendmsg(connfd,peerlen,3,0) != n) {
printf("sctp_sendmsg error: %s\n",strerror(errno));
exit(1);
}
}
exit(0);
}
}
}
int main(int argc,char** argv) {
if (argc != 2) {
printf("please add or check <service-name or port>\n");
exit(1);
}
struct addrinfo hints;
bzero(&hints,sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_SEQPACKET;
hints.ai_protocol = IPPROTO_SCTP;
struct addrinfo* results;
int err;
if ((err = getaddrinfo(NULL,argv[1],&hints,&results)) != 0) {
printf("getaddrinfo error: %s\n",strerror(err));
exit(1);
}
struct addrinfo* dummy = results;
int sockfd;
for (; dummy != NULL; dummy = dummy->ai_next) {
if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) {
continue;
}
if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) {
break;
}
close(sockfd);
}
if (dummy == NULL) {
printf("all socket Failed\n");
freeaddrinfo(results);
exit(1);
}
if (listen(sockfd,LISTENQ) < 0) {
printf("listen error: %s\n",strerror(errno));
exit(1);
}
freeaddrinfo(results);
if (signal(SIGCHLD,sig_child) == SIG_ERR) {
printf("signal error: %s\n",strerror(errno));
exit(1);
}
server_echo(sockfd);
return 0;
}