Me and one of my friends are trying to realize this simple client-server application. We observed the performance and we noticed that, in order to transfer 3 files, a singole SCTP association 3-streamed is much less performant that 3 tcp connections. Studying the theory, we expected at least the same performance, overall because SCTP multistreaming should reduce tcp overheads. Here is server:
#include <sys/types.h>
#include <sys/socket.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 <sys/time.h>
#include <net/if.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char** argv) {
int sockCli, sockServ, i, flags, res, scanned;
int one = open("files/first.txt", O_RDONLY);
int two = open("files/second.txt", O_RDONLY);
int three = open("files/third.txt", O_RDONLY);
if(one < 0 || two < 0 || three < 0) {
printf("Error on opening file\n");
exit(1);
}
struct sockaddr_in client, server;
struct sctp_initmsg initmsg;
char buffer[1025];
sockServ = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if(sockServ < 0) {
printf("failed on creating socket\n");
exit(1);
}
memset(&server, 0, sizeof(server));
memset(&client, 0, sizeof(client));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl( INADDR_ANY );
server.sin_port = htons(35000);
int servSize = sizeof(server);
memset( &initmsg, 0, sizeof(initmsg) );
initmsg.sinit_num_ostreams = 3;
initmsg.sinit_max_instreams = 3;
initmsg.sinit_max_attempts = 2;
setsockopt(sockServ, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg) );
res = bind(sockServ, (struct sockaddr *)&server, sizeof(server));
if(res < 0) {
printf("bind() failed\n");
exit(1);
}
res = listen(sockServ, 5);
sockCli = accept(sockServ, (struct sockaddr*)&client, (socklen_t*)&servSize);
for(i=0; i<3; i++) {
memset(buffer, 0, sizeof(buffer));
if(i==0) {
while((scanned = read(one, (void*)buffer, sizeof(buffer))) > 0) {
sctp_sendmsg(sockCli, (void *)buffer, (size_t)strlen(buffer),
(struct sockaddr*)&client, (socklen_t)sizeof(client), 0, 0, 0 /* stream */, 0, 0 );
memset(buffer, 0, sizeof(buffer));
}
}
if(i==1) {
while((scanned = read(two, (void*)buffer, sizeof(buffer))) > 0) {
sctp_sendmsg(sockCli, (void *)buffer, (size_t)strlen(buffer),
(struct sockaddr*)&client, (socklen_t)sizeof(client), 0, 0, 1 /* stream */, 0, 0 );
memset(buffer, 0, sizeof(buffer));
}
}
if(i==0) {
while((scanned = read(three, (void*)buffer, sizeof(buffer))) > 0) {
sctp_sendmsg(sockCli, (void *)buffer, (size_t)strlen(buffer),
(struct sockaddr*)&client, (socklen_t)sizeof(client), 0, 0, 2 /* stream */, 0, 0 );
memset(buffer, 0, sizeof(buffer));
}
}
}
close(sockCli);
close(sockServ);
close(one); close(two); close(three);
return 0;
}
and the client:
#include <sys/types.h>
#include <sys/socket.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 <sys/time.h>
#include <net/if.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char** argv) {
remove("first.txt");
remove("second.txt");
remove("third.txt");
FILE* files[3];
int i, flags, count0=0, count1=0, count2=0, res, received, sockCli;
struct sockaddr_in server;
struct sctp_sndrcvinfo sndrcvinfo;
struct sctp_event_subscribe events;
struct sctp_initmsg initmsg;
struct timeval begin, end;
int sec, usecs;
char buffer[1025];
char ipServer[32] = "127.0.0.1";
short int servPort = 35000;
sockCli = socket(AF_INET, SOCK_STREAM , IPPROTO_SCTP);
if(sockCli < 0) {
printf("Error on creating socket\n");
exit(1);
}
memset(&initmsg, 0, sizeof(initmsg));
initmsg.sinit_num_ostreams = 3;
initmsg.sinit_max_instreams = 3;
initmsg.sinit_max_attempts = 2;
res = setsockopt(sockCli, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg) );
if(res < 0) {
printf("setsockopt() initmsg failed\n");
exit(1);
}
memset(&events, 0, sizeof(events));
events.sctp_data_io_event = 1;
res = setsockopt(sockCli, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events) );
if(res < 0) {
printf("setsockopt() events failed\n");
exit(1);
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
inet_pton(AF_INET, ipServer, &server.sin_addr);
server.sin_port = htons(servPort);
int servSize = sizeof(server);
for(i=0; i<3; i++) {
if(i==0)
files[i] = fopen("first.txt", "a+");
if(i==1)
files[i] = fopen("second.txt", "a+");
if(i==2)
files[i] = fopen("third.txt", "a+");
}
res = connect(sockCli, (struct sockaddr*)&server, sizeof(server));
if(res < 0) {
printf("connect() failed\n");
exit(1);
}
gettimeofday(&begin, NULL);
while(1) {
memset(buffer, 0, sizeof(buffer));
received = sctp_recvmsg(sockCli, (void*)buffer, sizeof(buffer), (struct sockaddr*)&server, (socklen_t*)&servSize, &sndrcvinfo, &flags);
if(received == 0) {
printf("Received 0 bytes, all streams ended\n");
break;
}
if(sndrcvinfo.sinfo_stream == 0) {
fprintf(files[0], "%s", buffer);
count0++;
memset(buffer, 0, sizeof(buffer));
continue;
}
if(sndrcvinfo.sinfo_stream == 1) {
fprintf(files[1], "%s", buffer);
count1++;
memset(buffer, 0, sizeof(buffer));
continue;
}
if(sndrcvinfo.sinfo_stream == 2) {
fprintf(files[2], "%s", buffer);
count2++;
memset(buffer, 0, sizeof(buffer));
continue;
}
}
gettimeofday(&end, NULL);
close(sockCli);
for(i=0; i<3; i++)
fclose(files[i]);
sec = end.tv_sec - begin.tv_sec;
if (end.tv_usec > begin.tv_usec)
usecs = end.tv_usec - begin.tv_usec;
else
usecs = begin.tv_usec - end.tv_sec;
printf("Time elapsed is %d,%d\n", sec, usecs);
printf("Received\n%d messages on stream 0\n%d messages on stream 1\n%d messages on stream 2\n", count0, count1, count2);
return 0;
}
Maybe we are using stcp_() API in a bad way or some other mistakes. This seems the only correct way to us to go, because we read that a multi-streamed server should be an iterative one, and it's what we do. There is a special extra kind of socket called SOCK_SEQPACKET for one-to-many style but it's not clear to us how to use it because there no example. Could this be the key? So, might you please give us some advice about how to implement a good multistreamed SCTP application?