1

我在 SCTP 上有一个简单的客户端-服务器应用程序!客户端连接到打开 3 个流的服务器,服务器为每个流发送一个文件。问题是我不知道如何控制 3 个流,要知道流 i 0 中的 sctp_rcvmsg() 何时结束,这意味着该流的文件传输已结束……但似乎 sctp_recvmsg() 永远不会停止。这是我的代码。客户

#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);




}



}

我在哪里犯错?:(

4

1 回答 1

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将是一个空指针。

于 2013-03-22T20:00:46.853 回答