SCTP并发服务器

本文介绍了一种使用SCTP协议的服务器端编程方法,包括如何设置SCTP事件订阅、接收消息并剥离连接创建子进程进行独立处理。代码示例展示了关键步骤,如错误处理、信号处理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注:一定要通过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;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值