SCTP并发服务器

注:一定要通过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,buf,n,(struct sockaddr*)&clientaddr,len,0,0,2,0,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,BUFSIZE,(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,childbuf,n,(struct sockaddr*)&peer,peerlen,0,0,3,0,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;
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/rgbmarco/article/details/79559566