2013-03-18 75 views
1

我在SCTP上有一個簡單的客戶機 - 服務器應用程序!客戶端連接到服務器打開3個流,服務器每個流發送一個文件。問題是,我不知道如何控制3個流,要知道什麼時候從流i的sctp_rcvmsg(),這意味着該流的文件傳輸結束......但似乎sctp_recvmsg()從來沒有停止。這是我的代碼。 CLIENTSCTP多數據流:無限循環

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




} 



} 

我在哪裏犯了一個錯誤? :(

回答

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將是一個空指針。

+0

嘿,非常感謝。我現在已經解決了。請,我可以請你幫忙嗎?我不知道爲什麼n個傳輸n個文件的TCP總是比1個關聯SCTP和n個流快得多。爲什麼這個?至少他們應該是平等的,不是嗎?我的論文將失去它的目標是SCTP效率很低......或者,我是否以錯誤的方式使用了sctp API?我應該如何將它們用於多流? Pleass如果可以的話,幫助我,因爲這對我來說非常重要! – user1576208 2013-03-22 20:36:55