私と友人の 1 人は、この単純なクライアント/サーバー アプリケーションを実現しようとしています。パフォーマンスを観察したところ、3 つのファイルを転送するために、3 ストリーミングされた単一の SCTP アソシエーションは、3 つの tcp 接続よりもはるかにパフォーマンスが低いことに気付きました。理論を調べたところ、SCTP マルチストリーミングによって tcp オーバーヘッドが削減されるため、全体として少なくとも同じパフォーマンスが期待されました。サーバーは次のとおりです。
#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;
}
そしてクライアント:
#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;
}
stcp_() API の使い方が間違っているか、その他の間違いがあるのかもしれません。マルチストリームサーバーは反復サーバーであるべきだと読んだので、これが唯一の正しい方法のように思えます。1 対多のスタイル用に SOCK_SEQPACKET と呼ばれる特別な種類のソケットがありますが、例がないため、その使用方法は明確ではありません。これが鍵になるのでしょうか?では、優れたマルチストリーム SCTP アプリケーションを実装する方法についてアドバイスをいただけませんか?