sctp test

来源:互联网 发布:为什么java比php工资高 编辑:程序博客网 时间:2024/05/24 06:44

                                                               sctp简绍

1.SCTP全称

     sctp(StreamControl Transmission Protocol)即流控制传送协议。

2. sctp是增强型的tcp协议

    SCTP可以看做是TCP的增强协议,因为其可靠传输和拥塞控制机制基本都来自于TCP,但是它又对TCP进行了增强和完善,使得信令传输具有更高的可靠性。与TCP相比,SCTP最大的改变是增加了对多宿主(Multi-homing)、多流(Multi-streaming)以及部分有序(partialordering)的支持

3. sctp的多宿主特性(Mti-homing)

    多宿主是指一个SCTP端点可以通过多个IP地址到达,这样两个SCTP端点在建立了关联后,数据可以通过不同的物理通路进行传送。也就是说,当一条通路坏掉后,可以通过另一条通路到达对端

4. sctp的多流特性(Muti-homing)

    多流是指SCTP数据包会携带流标识和流序号,因此每个连接里有多个流的存在。由于采用多个流进行传输而且各个流相互独立,这样当一个流中的数据包需要重传,其他流中的数据可以继续传输, 解决了在TCP单流中容易出现的队头阻塞现象(head-of-line-blocking)

5. sctp的面向消息特性

sctp提供按序投递服务。和 UDP 一样,由发送端写入每条记录的长度,并随数据一同传递给接收端。SCTP是基于消息流,而TCP则是基于字节流

6. source code

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/sctp.h>#include <arpa/inet.h>#include <time.h>#include <errno.h>#include <fcntl.h>#include <assert.h>#include <signal.h>#include <sys/time.h> #include <sys/utsname.h>#include <signal.h>#include <unistd.h>                                                                                                         #include <getopt.h>  static int streamno[] = {0, 1, 2, 3, 4};static int gSleepTime = 20; /* us */static long gTimer = 0; /* ms */static long gSendByte = 0;static long gRecByte = 0;static int gExit = 0;#define MAXRANGE 1600#define recBufSize (40*1024)#define MAX_BUFFER 256#define GMT_STREAM 256#define SYS_IT_INTERVAL_SEC 0#define URBAN_IT_INTERVAL_USEC (2*1000) /* 2ms */typedef enum _OS_VERSION{    OS_ES4,    OS_CENTOS,}OS_VERSION;static int Linux_OS_Release=OS_ES4; /* 0=ES4, 1=CentOS */static void SetFSMTimer(){    struct itimerval        *ptv, tv;    struct utsname          u_name;    uname(&u_name);    if(strstr(u_name.release,"2.6.9") == NULL)            Linux_OS_Release = OS_CENTOS;    ptv = (struct itimerval *) &tv;    ptv->it_interval.tv_sec = SYS_IT_INTERVAL_SEC;    ptv->it_value. tv_sec = SYS_IT_INTERVAL_SEC;    /*    if(Linux_OS_Release == OS_ES4)    {            ptv->it_interval.tv_usec = ES4_IT_INTERVAL_USEC;            ptv->it_value.tv_usec = ES4_IT_INTERVAL_USEC;    }    else    {            ptv->it_interval.tv_usec = CENTOS_IT_INTERVAL_USEC;            ptv->it_value.tv_usec = CENTOS_IT_INTERVAL_USEC;    }*/    ptv->it_interval.tv_usec = URBAN_IT_INTERVAL_USEC;    ptv->it_value.tv_usec    = URBAN_IT_INTERVAL_USEC;    setitimer(ITIMER_REAL, ptv, NULL);}static void sysTimer_IRQ(){    gTimer += 2;}static void SigactionSystem(){struct sigaction action;action.sa_handler = sysTimer_IRQ;sigemptyset(&action.sa_mask);action.sa_flags = SA_RESTART;if(sigaction(SIGALRM, &action, NULL)<0){printf("sigactin sigalarm failed\n");}}inline char *get_human_byte(long int byte){    static char human[256];    memset(human, 0, 256);    if((byte >> 30) > 0)        sprintf(human, "%ldG%ldM%ldK%ldB", byte >> 30, (byte >> 20) % 1024, (byte >> 10) % 1024, byte % 1024);    else if((byte >> 20) > 0)        sprintf(human, "%ldM%ldK%ldB", (byte >> 20) % 1024, (byte>>10) % 1024, byte % 1024);    else if((byte >> 10) > 0)        sprintf(human, "%ldK%ldB", (byte >> 10) % 1024, byte % 1024);    else        sprintf(human, "%ldB", byte % 1024);    return human;}inline char *get_human_byte_v(long int byte){    static char human[256];    memset(human, 0, 256);    if((byte >> 30) > 0)        sprintf(human, "%ldG%ldM%ldK%ldB", byte >> 30, (byte >> 20) % 1024, (byte >> 10) % 1024, byte % 1024);    else if((byte >> 20) > 0)        sprintf(human, "%ldM%ldK%ldB", (byte >> 20) % 1024, (byte>>10) % 1024, byte % 1024);    else if((byte >> 10) > 0)        sprintf(human, "%ldK%ldB", (byte >> 10) % 1024, byte % 1024);    else        sprintf(human, "%ldB", byte % 1024);    return human;}int client_init_socket(){    int     connSock, on = 1;    long    rec_sock_buf_size = 40*1024;    int     send_sock_buf_size = 512*1024;    /* Create SCTP TCP-Style Socket */    connSock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);    /* set send buffer size */    if(setsockopt(connSock, SOL_SOCKET, SO_SNDBUF, &send_sock_buf_size, sizeof(send_sock_buf_size)) !=0)    {        fprintf(stderr, "%s set socket send buffer failed\n", __FUNCTION__);        return -1;    }    /* set receive buffer size */    if(setsockopt(connSock, SOL_SOCKET, SO_RCVBUF, &rec_sock_buf_size, sizeof(rec_sock_buf_size)) != 0)    {        fprintf(stderr, "%s set socket rec buffer failed\n", __FUNCTION__);        return -1;    }    /* set reuse addr */    if(setsockopt(connSock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0)    {        fprintf(stderr, "%s set addr reusable failed\n", __FUNCTION__);        return -1;    }    /* set no delay */    if(setsockopt(connSock, IPPROTO_SCTP, SCTP_NODELAY, &on, sizeof(on)) != 0)    {        fprintf(stderr, "%s set tcp no dealy failed\n", __FUNCTION__);        return -1;    }    return connSock;}int client_connect(int connSock, unsigned short int serverPort, const char *pServerIP){    int in = 0;    struct sockaddr_in servaddr;    struct sctp_status status;    struct sctp_event_subscribe events;    struct sctp_initmsg initmsg;    /* Specify that a maximum of 5 streams will be available per socket */    memset( &initmsg, 0, sizeof(initmsg) );    initmsg.sinit_num_ostreams  = 5;    initmsg.sinit_max_instreams = 5;    initmsg.sinit_max_attempts  = 4;        /* Specify the peer endpoint to which we'll connect to*/    bzero( (void *)&servaddr, sizeof(servaddr) );    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(serverPort);    servaddr.sin_addr.s_addr = inet_addr( pServerIP );    /* Connect to the server */    if(connect( connSock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)    {        fprintf(stderr, "%s connect err. errno:%d errmsg:%s\n", __FUNCTION__, errno, strerror(errno));        return -1;    }    /* set nonblock */    if(fcntl(connSock, F_SETFL, O_NONBLOCK) < 0)    {        fprintf(stderr, "%s set nonblock failed\n", __FUNCTION__);        return -1;    }    /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */    memset( (void *)&events, 0, sizeof(events) );    events.sctp_data_io_event = 1;    if( setsockopt( connSock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events) ) < 0)    {        printf("setsockopt err. errno:%d errmsg:%s\n", errno, strerror(errno));        return -1;    }    /* Read and emit the status of the Socket (optional step) */    in = sizeof(status);    if(getsockopt( connSock, SOL_SCTP, SCTP_STATUS, (void *)&status, (socklen_t *)&in ) < 0)    {        fprintf(stderr, "%s getsockopt err. errno:%d errmsg:%s\n", __FUNCTION__, errno, strerror(errno));        return -1;    }    printf("assoc id = %d\n", status.sstat_assoc_id );    printf("state = %d\n", status.sstat_state );    printf("instrms = %d\n", status.sstat_instrms );    printf("outstrms = %d\n", status.sstat_outstrms );    return 0;}inline int client_get_msg_len(const unsigned char *pMsg){    return ( (unsigned short int)(pMsg[0] - 0) << 8) + pMsg[1] - 0;}static int client(unsigned short int serverPort, const char *pServerIP){    static long int sTimer = 0;    int connSock, in, flags, totalRecPackNum = 0;    struct sctp_sndrcvinfo sndrcvinfo;    unsigned char buffer[recBufSize+1];    connSock = client_init_socket();    if(client_connect(connSock, serverPort, pServerIP) < 0)    {        fprintf(stderr, "%s client_connet err.\n", __FUNCTION__);        close(connSock);        return -1;    }    for (; ;)    {        in = sctp_recvmsg(connSock, (void *)buffer, recBufSize, (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags);        if (in > 0)        {            buffer[in] = 0;            gRecByte += in;            totalRecPackNum++;                        if(0 == (gTimer % 1000) && 0 != gTimer && sTimer != gTimer)            {                printf("receiveByteV:%s/s recPackV:%ld recBytes:%s recTime:%ld.%ld(m)\n",                                        get_human_byte_v(gRecByte/(gTimer/1000)),                                        totalRecPackNum/(gTimer/1000),                                        get_human_byte(gRecByte),                                        gTimer/1000, gTimer%1000);                sTimer = gTimer;            }            if(0 != sndrcvinfo.sinfo_ppid)                printf("ppid:%x\n", sndrcvinfo.sinfo_ppid);            // printf("TotalRecPackNum:%d streamno:%d recLen:%d lenInMsg:%d\n", ++totalRecPackNum, sndrcvinfo.sinfo_stream, in, client_get_msg_len(buffer)/*, buffer + 2*/);            /* check msg len rec len */            if(in != (2 + client_get_msg_len(buffer)) )            {                fprintf(stderr, "err\n");                close(connSock);                assert(in == (2 + client_get_msg_len(buffer)));            }        }        // usleep(gSleepTime);        if(1 == gExit)        {            close(connSock);            return 0;        }    }    /* Close our socket and exit */    fprintf(stderr, "%s err\n", __FUNCTION__);    close(connSock);        return 0;}inline static const unsigned char *get_rand_str(int maxRange, int *realRange){    /* a-z A-Z */    // const int maxCharNum = 51;    static unsigned char str[MAXRANGE];    // int i = 0, readRandRange;    // char ch;    if(maxRange >= MAXRANGE)        return NULL;/*    srand( (unsigned)time(NULL) );    readRandRange = rand()%maxRange;    // printf("RAND_MAX:%ld readRandRange:%d\n", RAND_MAX, readRandRange);    for(i = 0; i < readRandRange; ++i)    {        ch = rand() % maxCharNum;        // printf("ch:%d\n", ch);        if(ch > (maxCharNum>>1))            ch = 'A' + ch - 25;        else            ch = 'a' + ch;        str[i+2] = ch;    }    str[0] = ((readRandRange & 0xff00) >> 8);    str[1] = (readRandRange & 0xff);    *realRange = readRandRange + 2;*/    str[0] = ((maxRange & 0xff00) >> 8);    str[1] = (maxRange & 0xff);    *realRange = maxRange + 2;    // str[*realRange] = '0';    // printf("len:%d strLen:%d str:%s\n", *realRange, client_get_msg_len(str), str);    return str;}int server_init_socket(){    int     listenSock, on = 1;    long    rec_sock_buf_size = 40*1024;    int     send_sock_buf_size = 512*1024;    /* Create SCTP TCP-Style Socket */    listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);    /* set send buffer size */    if(setsockopt(listenSock, SOL_SOCKET, SO_SNDBUF, &send_sock_buf_size, sizeof(send_sock_buf_size)) !=0)    {        fprintf(stderr, "%s set socket send buffer failed\n", __FUNCTION__);        return -1;    }    /* set receive buffer size */    if(setsockopt(listenSock, SOL_SOCKET, SO_RCVBUF, &rec_sock_buf_size, sizeof(rec_sock_buf_size)) != 0)    {        fprintf(stderr, "%s set socket rec buffer failed\n", __FUNCTION__);        return -1;    }    if(setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0)    {        fprintf(stderr, "%s set addr reusable failed\n", __FUNCTION__);        return -1;    }    /* set no delay */    if(setsockopt(listenSock, IPPROTO_SCTP, SCTP_NODELAY, &on, sizeof(on)) != 0)    {        fprintf(stderr, "%s set tcp no dealy failed\n", __FUNCTION__);        return -1;    }    return listenSock;}int server_bindandlisten(int listenSock, unsigned short int localServerPort, const char *pServerIP){    struct sockaddr_in servaddr;    struct sctp_initmsg initmsg;    /* Accept connections from any interface */    bzero( (void *)&servaddr, sizeof(servaddr) );    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = inet_addr( pServerIP );    // htonl( INADDR_ANY);    servaddr.sin_port = htons(localServerPort);    if(bind(listenSock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)    {        fprintf(stderr, "%s bind err. errno:%d errmsg:%s\n", __FUNCTION__, errno, strerror(errno));        return -1;    }    /* set nonblock */    if(fcntl(listenSock, F_SETFL, O_NONBLOCK) < 0)    {        fprintf(stderr, "%s set nonblock failed\n", __FUNCTION__);        return -1;    }    /* Specify that a maximum of 5 streams will be available per socket */    memset( &initmsg, 0, sizeof(initmsg) );    initmsg.sinit_num_ostreams  = 5;    initmsg.sinit_max_instreams = 5;    initmsg.sinit_max_attempts  = 4;    if(setsockopt( listenSock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg) ) < 0)    {        fprintf(stderr, "%s setsockopt err. errno:%d errmsg:%s\n", __FUNCTION__, errno, strerror(errno));        return -1;    }    /* Place the server socket into the listening state */    listen(listenSock, 5);    return 0;}static int server(unsigned short int localServerPort, const char *pServerIP){    long int sTimer = 0;    int listenSock, connSock;    const unsigned char *pSendMsg = NULL;    int sendLen = 0, totalSendPackNum = 0;    long int protID = 55;            listenSock = server_init_socket();    server_bindandlisten(listenSock, localServerPort, pServerIP);    /* Server loop... */    while(1)    {        /* Await a new client connection */        printf("Awaiting a new connection\n");        while(1)        {            connSock = accept( listenSock, (struct sockaddr *)NULL, (socklen_t *)NULL );            if(connSock < 0)            {                fprintf(stderr, "%s accept err. connSock:%d errno:%d errmsg:%s\n", __FUNCTION__, connSock, errno, strerror(errno));                continue;            }            break;        }        printf("accept suc and ready to sleep 10 seconds\n");        sleep(30);        printf("after sleep 30 seconds\n");        /* New client socket has connected then send msg to the client socket*/        while(1)        {            if((pSendMsg = get_rand_str(200, &sendLen)) == NULL)            {                fprintf(stderr, "%s get_rand_str err\n", __FUNCTION__);                return -1;            }            if(sendLen <= 0)            {                fprintf(stderr, "%s sendLen:%d\n", __FUNCTION__, sendLen);                continue;            }                        if(sctp_sendmsg( connSock, (void *)pSendMsg, sendLen, NULL, 0, protID, 0, streamno[2], 0, 0 ) < 0)            {                fprintf(stderr, "%s sctp_sendmsg errno:%d errmsg:%s\n", __FUNCTION__, errno, strerror(errno));                return -1;            }            protID = ((protID + 1) % 0x100000000);             // printf("totalPackNum:%d v:%d streamno:%d sendLen:%d lenInmsg:%d\n", ++totalSendPackNum, streamno[0], sendLen, client_get_msg_len(pSendMsg)/*, pSendMsg + 2*/);            gSendByte += sendLen;            totalSendPackNum++;            if(0 == (gTimer % 1000) && 0 != gTimer && sTimer != gTimer)            {                printf("sendByteV:%s/s sendPackV:%ld sendByte:%s timeNow:%ld.%ld(s)\n",                                get_human_byte_v(gSendByte/(gTimer/1000)),                                totalSendPackNum/(gTimer/1000),                                get_human_byte(gSendByte),                                gTimer/1000, gTimer%1000);                sTimer = gTimer;            }            // usleep(gSleepTime);            if(1 == gExit)            {                close(connSock);                return 0;            }        }        /* Close the client connection */        close( connSock );    }    return 0;} void sig_handler(int sig){    if(sig == SIGINT)    {        printf("ctrl+c has been keydowned\n");        gExit = 1;    }}int main(int argc, char **argv){    int retval, isServer = -1;    char clientIP[256] = {0};    char serverIP[256] = {0};    unsigned short int clientPort;    unsigned short int serverPort;SigactionSystem();SetFSMTimer();    signal(SIGINT, sig_handler);    while((retval = getopt(argc, argv, "cst")) != -1)    {        switch(retval)        {            case 'c': // optind: next command index    optarg: command string                strcpy(clientIP, argv[optind]);                clientPort = atoi(argv[optind + 1]);                isServer = 0;                break;            case 's':                strcpy(serverIP, argv[optind]);                serverPort = atoi(argv[optind + 1]);                isServer = 1;                break;            case 't':                gSleepTime = atoi(argv[optind]);                break;            default:                break;        }    }    if(1 == isServer)        return server(serverPort, serverIP);    else if(0 == isServer)        return client(clientPort, clientIP);    printf("usage: xx -c serverIP serverPort/-s serverPort/-t\n");    return 0;}

7. compile

    gcc -Wall -g -o xx sctp.c -lsctp

8. host a client run: ./sctp -s b 2222 -t 1

    host b server run: ./sctp -c b 2222 -t 1

0 0
原创粉丝点击