我和我的一个朋友正在尝试实现这个简单的客户端-服务器应用程序。我们观察了性能,我们注意到,为了传输 3 个文件,单个 SCTP 关联 3-streamed 的性能远低于 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 或其他一些错误。这似乎是我们唯一正确的方法,因为我们读到多流服务器应该是一个迭代服务器,这就是我们所做的。有一种特殊的额外类型的套接字,称为 SOCK_SEQPACKET 用于一对多样式,但我们不清楚如何使用它,因为没有示例。这可能是关键吗?那么,您能否就如何实现一个好的多流 SCTP 应用程序给我们一些建议?