SCTP hébergement multiple

J'ai mis au point cette simple application client - serveur avec C où le client est juste pour envoyer des données au serveur et le serveur écoute juste à ce que le client envoie. Le protocole que j'utilise est SCTP et je suis intéressé sur la façon de mettre en œuvre l'hébergement multiple fonction.

J'ai été à la recherche à travers l'internet à propos de la SCTP et d'hébergement multiple et n'ont pas été en mesure de trouver des exemples sur la façon d'instruire SCTP d'utiliser plusieurs adresses pour la communication. Je n'ai réussi à trouver ce que les commandes que l'on devrait utiliser lorsque vous essayez de configurer SCTP avec hébergement multiple et il devrait être assez simple.

J'ai créé un client et un serveur qui utilisent mes ordinateurs deux interfaces WLAN que leurs points de connexion. Les deux adaptateurs sont connectés au même point d'accès. Le serveur est à l'écoute pour les données du client à partir de ces interfaces et le client envoie des données à travers eux. Le problème est que lorsque je déconnecte la primaire adaptateur de réseau sans fil le client envoie des données, la transmission s'arrête juste quand il le faut de secours à la connexion secondaire. J'ai tracé les paquets avec Wireshark et la première INIT et INIT_ACK paquets de rapport qu'à la fois le client et le serveur sont en utilisant les adaptateurs lan sans fil que leurs liens de communication.

Lorsque je reconnecte la primaire connexion wi-fi, la transmission se poursuit après un peu de temps et d'éclats une énorme charge de paquets au serveur qui n'est pas droit. Les paquets ont été transmis au cours de la connexion secondaire. Sur de nombreux sites, il est dit que SCTP commutateurs entre les connexions automatiquement, mais dans mon cas ça ne se produit. Alors, avez-vous les gars avez des indices pourquoi la transmission n'a pas de secours à la connexion secondaire lors de la primaire du lien, même si le client et le serveur connaît les uns les autres adresses, y compris l'adresse secondaire?

Sur le serveur:

Le serveur crée un SOCK_SEQPACKET de type socket et lie toutes les interfaces trouvé avec INADDR_ANY. getladdrs signale que le serveur est limité à 3 adresses (y compris les 127.0.0.1). Après que le serveur est à l'écoute à la prise et attend le client pour envoyer des données. Le serveur lit les données avec sctp_recvmsg appel.

Sur le client:

Le client crée également un SEQPACKET prise et se connecte à une adresse IP spécifiée par un argument de ligne de commande. getladdrs dans ce cas renvoie également 3 adresses comme dans les serveurs cas. Après que le client commence à envoyer des données au serveur avec une seconde de retard sur le serveur jusqu'à ce que l'utilisateur interrompt l'envoyer avec Ctrl-C.

Voici le code source:

Serveur:

#define BUFFER_SIZE (1 << 16)
#define PORT 10000   
int sock, ret, flags;
int i;
int addr_count = 0;
char buffer[BUFFER_SIZE];
socklen_t from_len;
struct sockaddr_in addr;
struct sockaddr_in *laddr[10];
struct sockaddr_in *paddrs[10];
struct sctp_sndrcvinfo sinfo;
struct sctp_event_subscribe event;  
struct sctp_prim prim_addr; 
struct sctp_paddrparams heartbeat;
struct sigaction sig_handler;
void handle_signal(int signum);
int main(void)
{
if((sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
perror("socket");
memset(&addr, 0, sizeof(struct sockaddr_in));
memset((void*)&event, 1, sizeof(struct sctp_event_subscribe));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
from_len = (socklen_t)sizeof(struct sockaddr_in);
sig_handler.sa_handler = handle_signal;
sig_handler.sa_flags = 0;
if(sigaction(SIGINT, &sig_handler, NULL) == -1)
perror("sigaction");
if(setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)) < 0)
perror("setsockopt");
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int))< 0)
perror("setsockopt");
if(bind(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0)
perror("bind");
if(listen(sock, 2) < 0)
perror("listen");
addr_count = sctp_getladdrs(sock, 0, (struct sockaddr**)laddr);
printf("Addresses binded: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*laddr)[i].sin_addr), (*laddr)[i].sin_port);
sctp_freeladdrs((struct sockaddr*)*laddr);
while(1)
{
flags = 0;
ret = sctp_recvmsg(sock, buffer, BUFFER_SIZE, (struct sockaddr*)&addr, &from_len, NULL, &flags);
if(flags & MSG_NOTIFICATION)
printf("Notification received from %s:%u\n",  inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
printf("%d bytes received from %s:%u\n", ret, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));      
}
if(close(sock) < 0)
perror("close");
}   
void handle_signal(int signum)
{
switch(signum)
{
case SIGINT:
if(close(sock) != 0)
perror("close");
exit(0);
break;  
default: exit(0);
break;
}
}

Et le Client:

#define PORT 10000
#define MSG_SIZE 1000
#define NUMBER_OF_MESSAGES 1000
#define PPID 1234
int sock;
struct sockaddr_in *paddrs[10];
struct sockaddr_in *laddrs[10];
void handle_signal(int signum);
int main(int argc, char **argv)
{
int i;
int counter = 1;
int ret;
int addr_count;
char address[16];
char buffer[MSG_SIZE];
sctp_assoc_t id;
struct sockaddr_in addr;
struct sctp_status status;
struct sctp_initmsg initmsg;
struct sctp_event_subscribe events;
struct sigaction sig_handler;
memset((void*)&buffer,  'j', MSG_SIZE);
memset((void*)&initmsg, 0, sizeof(initmsg));
memset((void*)&addr,    0, sizeof(struct sockaddr_in));
memset((void*)&events, 1, sizeof(struct sctp_event_subscribe));
if(argc != 2 || (inet_addr(argv[1]) == -1))
{
puts("Usage: client [IP ADDRESS in form xxx.xxx.xxx.xxx] ");        
return 0;
}
strncpy(address, argv[1], 15);
address[15] = 0;
addr.sin_family = AF_INET;
inet_aton(address, &(addr.sin_addr));
addr.sin_port = htons(PORT);
initmsg.sinit_num_ostreams = 2;
initmsg.sinit_max_instreams = 2;
initmsg.sinit_max_attempts = 5;
sig_handler.sa_handler = handle_signal;
sig_handler.sa_flags = 0;
if(sigaction(SIGINT, &sig_handler, NULL) == -1)
perror("sigaction");
if((sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
perror("socket");
if((setsockopt(sock, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg))) != 0)
perror("setsockopt");
if((setsockopt(sock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events))) != 0)
perror("setsockopt");
if(sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == -1)
perror("sendto");
addr_count = sctp_getpaddrs(sock, 0, (struct sockaddr**)paddrs);
printf("\nPeer addresses: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*paddrs)[i].sin_addr), (*paddrs)[i].sin_port);
sctp_freepaddrs((struct sockaddr*)*paddrs);
addr_count = sctp_getladdrs(sock, 0, (struct sockaddr**)laddrs);
printf("\nLocal addresses: %d\n", addr_count);
for(i = 0; i < addr_count; i++)
printf("Address %d: %s:%d\n", i +1, inet_ntoa((*laddrs)[i].sin_addr), (*laddrs)[i].sin_port);
sctp_freeladdrs((struct sockaddr*)*laddrs);
i = sizeof(status);
if((ret = getsockopt(sock, SOL_SCTP, SCTP_STATUS, &status, (socklen_t *)&i)) != 0)
perror("getsockopt");
printf("\nSCTP Status:\n--------\n");
printf("assoc id  = %d\n", status.sstat_assoc_id);
printf("state     = %d\n", status.sstat_state);
printf("instrms   = %d\n", status.sstat_instrms);
printf("outstrms  = %d\n--------\n\n", status.sstat_outstrms);
for(i = 0; i < NUMBER_OF_MESSAGES; i++)
{
counter++;
printf("Sending data chunk #%d...", counter);
if((ret = sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr))) == -1)
perror("sendto");
printf("Sent %d bytes to peer\n",ret);
sleep(1);
}
if(close(sock) != 0)
perror("close");
}
void handle_signal(int signum)
{
switch(signum)
{
case SIGINT:
if(close(sock) != 0)
perror("close");
exit(0);
break;  
default: exit(0);
break;
}
}

Alors, avez-vous les gars ont des indices de ce que je fais mal?

si votre sctp_getladdrs() en boucle en fait l'impression de plusieurs adresses à la fois le client et le serveur, vous pourriez ne pas vouloir utiliser sendto(), comme le sendto() qui spécifie une adresse réelle à envoyer, au lieu de cela, utilisez connect() et write() ou send() du client. Vérifiez avec wireshark si les signaux sont envoyés à l'école primaire et secondaire de chemin de trop.
Il semble que les signaux sont envoyés uniquement à l'adresse secondaire. Modifier les intervalles d'interrogation et le maximum de retransmissions ne semble pas avoir d'effet. Toutes les idées de force SCTP pour envoyer des battements de cœur par exemple. toutes les deux secondes pour toutes les connexions. Essayé d'utiliser sctp_paddrparams pour spécifier les intervalles d'interrogation, mais en vain.
C'est probablement ok si ce n'est pas l'envoi de battements de coeur sur la principale route si vous êtes l'envoi de données.

OriginalL'auteur Kari Vatjus-Anttila | 2011-06-14