SCTP多数据流:无限循环

时间:2013-03-18 16:01:05

标签: sctp

我在SCTP上有一个简单的客户端 - 服务器应用程序!客户端连接到服务器开放3个流,服务器每个流发送一个文件。问题是我不知道如何控制3个流,知道什么时候来自流i的sctp_rcvmsg()它意味着该流的文件传输已经结束......但似乎sctp_recvmsg()从不停止。这是我的代码。 CLIENT

#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <time.h>

#define BUFFERSIZE 1024

int main(int argc, char** argv) {

int i, sockCliSCTP, flags, res;

/* Server netwrok informations */
struct sockaddr_in servAddr;

/* To get which stream it has received data from */
struct sctp_sndrcvinfo sndrcvinfo;

/* Init message to setup number of streams */
struct sctp_initmsg initmsg;

/* Catching events */
struct sctp_event_subscribe events;

/* Buffer to receive files */
char buffer[BUFFERSIZE];

/* Remove previous recently used files */
remove("first.txt");
remove("second.txt");
remove("third.txt");

char ipServ[32] = "127.0.0.1";
short int servPort = 29008;

/* BEGIN SCTP PART */
/* Creating client socket for SCTP protocol */
sockCliSCTP = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );

/* Specify that a maximum of 3 streams will be available per socket */
memset( &initmsg, 0, sizeof(initmsg) );
initmsg.sinit_num_ostreams = 3; /* output streams */
initmsg.sinit_max_instreams = 3; /* input streams */
initmsg.sinit_max_attempts = 2;
setsockopt(sockCliSCTP, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg) );

/* Initializing server network data structs */
bzero( (void *)&servAddr, sizeof(servAddr) );
servAddr.sin_family = AF_INET;
inet_pton(AF_INET, ipServ, &servAddr.sin_addr);
servAddr.sin_port = htons(29008);
int sizeServ = sizeof(servAddr);

/* Connect to server */
res = connect(sockCliSCTP, (struct sockaddr *)&servAddr, sizeof(servAddr));
if (res < 0) {
    printf("Connection to server refused!\n");
    exit(1);
}

memset( (void *)&events, 0, sizeof(events) );
events.sctp_data_io_event = 1;
res = setsockopt(sockCliSCTP, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events));
if (res < 0) {
    printf("setsockopt failed!\n");
    exit(1);
}

/* The clients simply waits and receives for three files from the server.
 * The size of the files is increased each time this client is launched. */

FILE *oneF, *twoF, *threeF;
oneF = fopen("first.txt", "a"); /* Stream 0 */
twoF = fopen("second.txt", "a"); /* Stream 1 */
threeF = fopen("third.txt", "a"); /* Stream 2 */

/* To measure time */
time_t timeStart;
time_t timeEnd;
time_t timeRes = 0;

time(&timeStart);

int count0 = 0, count1 = 0, count2 = 0;

int checkRead[3];
for(i = 0; i<3; i++) {
    checkRead[i] = 1;
}


/* Receiving in parallel the files from 3 streams */
while(checkRead[0] || checkRead[1] || checkRead[2]) {

    printf("%d %d %d\n", checkRead[0], checkRead[1], checkRead[2]);

    res = sctp_recvmsg(sockCliSCTP, (void*)buffer, sizeof(buffer), (struct sockaddr*)&servAddr, (socklen_t *)&sizeServ, &sndrcvinfo, &flags);

    if (res == 0) {
        printf("%d stream is zero\n", sndrcvinfo.sinfo_stream);
        checkRead[sndrcvinfo.sinfo_stream] = 0;
        continue;
    }


    /* Check from which stream the data came in */
    switch(sndrcvinfo.sinfo_stream) {

    /* Write on file oneF --> first.txt */
    case 0:
        count0++;
        printf("Message received from stream 0\n");
        //printf("%s\n\n", buffer);
        fprintf(oneF, "%s", buffer);
        break;



    /* Write on file twoF --> second.txt */
    case 1:
        count1++;
        printf("Message received from stream 1\n");
        //printf("%s\n\n", buffer);
        fprintf(twoF, "%s", buffer);
        break;




    /* Write on file threeF --> third.txt */
    case 2:
        count2++;
        printf("Message received from stream 2\n");
        //printf("%s\n\n", buffer);
        fprintf(threeF, "%s", buffer);
        break;


    }

    memset(buffer, 0, sizeof(buffer));
    sleep(1);
}

close(sockCliSCTP);

time(&timeEnd);
timeRes = timeEnd - timeStart;
printf("Time elapsed is: %d seconds\n", (int)timeRes);

printf("%d messages on stream 0,\n %d messages on stream 1,\n %d messages on stream 2\n", count0, count1, count2);


}

和服务员:

#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFFERSIZE 1024

int main(int argc, char** argv) {

int sockCli, sockServ, one, two, three, i, res;

struct sockaddr_in client, server;

/* data struct to declarate streams */
struct sctp_initmsg initmsg;

/* buffer to read from file */
char buffer[BUFFERSIZE];

/* socket server listening */
sockServ = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);

bzero( (void *)&client, sizeof(client));
bzero( (void *)&server, sizeof(server));


/* Preparing sever data struct and bind() */
bzero( (void *)&server, sizeof(server) );
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl( INADDR_ANY );
server.sin_port = htons(29008);

bind(sockServ, (struct sockaddr *)&server, sizeof(server));

/* Maximum of 3 streams will be available per socket */
memset( &initmsg, 0, sizeof(initmsg) );
initmsg.sinit_num_ostreams = 3;
initmsg.sinit_max_instreams = 3;
initmsg.sinit_max_attempts = 2;

res = setsockopt(sockServ, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
if (res < 0) {
    printf("setsockopt() failed!\n");
    exit(1);
}


/* Preparing the three files to be sent */
one = open("files/first.txt", O_RDONLY);
if (one < 0) {
    printf("Error on opening first file!\n");
    exit(1);
}

two = open("files/second.txt", O_RDONLY);
if (two < 0) {
    printf("Error on opening second file!\n");
    exit(1);
}

three = open("files/third.txt", O_RDONLY);
if (three < 0) {
    printf("Error on opening third files!\n");
    exit(1);
}


int checkFiles[3];
for(i=0; i<3; i++) {
    checkFiles[i] = 1;
}


res = listen(sockServ, 5);
if (res < 0) {
    printf("listen() failed!\n");
    exit(1);
}



while(1) {

    ssize_t readRes;
    int len = sizeof(client);
    sockCli = accept(sockServ, (struct sockaddr*)&client, &len);

    if (sockCli < 0) {
        printf("Error on accept()!\n");
        exit(1);
    }

    printf("Associated to client!\n");

    while(1) {

        memset(buffer, 0, sizeof(buffer));
        if ((readRes = read(one, (void*)buffer, sizeof(buffer))) > 0) {
            sctp_sendmsg(sockCli, (void*)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, 0 /* stream number */, 0, 0);
        }


        memset(buffer, 0, sizeof(buffer));
        if ((readRes = read(two, (void*)buffer, sizeof(buffer))) > 0) {
            sctp_sendmsg(sockCli, (void*)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, 1 /* stream number */, 0, 0);
        }


        memset(buffer, 0, sizeof(buffer));
        if ((readRes = read(three, (void*)buffer, sizeof(buffer))) > 0) {
            sctp_sendmsg(sockCli, (void*)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, 2 /* stream number */, 0, 0);
        }

        else {break;}

    }

    close(sockCli);
    close(one);
    close(two);
    close(three);




}



}

我在哪里弄错了? :(

1 个答案:

答案 0 :(得分:2)

sctp_recvmsg 没有从单个流收到消息。它只返回收到的任何消息,然后应用程序可以确定消息来自哪个流。

执行此代码后,客户端收到所有数据后:

res = sctp_recvmsg(sockCliSCTP, (void*)buffer, sizeof(buffer), (struct sockaddr*)&servAddr, (socklen_t *)&sizeServ, &sndrcvinfo, &flags);

if (res == 0) {
    printf("%d stream is zero\n", sndrcvinfo.sinfo_stream);
    checkRead[sndrcvinfo.sinfo_stream] = 0;
    continue;
}

res 变为0,因为未收到任何消息且 sndrcvinfo 结构不会更改。因此, sndrcvinfo.sinfo_stream 将保持与上一条消息来自的任何流相同,因为您未能更改 checkRead [] 值,您将陷入循环

还有一些其他错误会导致服务器/客户端出现奇怪的行为。

例如,由于服务器关闭文件描述符并且第二次不发送任何数据,因此您无法连续两次运行客户端而没有分段错误。因此,当你这样做时,你会发生段错误:

 checkRead[sndrcvinfo.sinfo_stream] = 0;

因为 sndrcvinfo 将是一个空指针。