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?
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
Vous devez vous connecter pour publier un commentaire.
Ok j'ai résolu le problème d'hébergement multiple enfin. Voici ce que j'ai fait.
J'ai ajusté le rythme cardiaque de la valeur à 5000 ms avec sctp_paddrparams struct. Les drapeaux variable situé dans la struct a dans SPP_HB_ENABLE mode parce que sinon SCTP ignore le rythme cardiaque de la valeur lorsque vous tentez de définir la valeur avec setsockopt().
Que c'était la raison pourquoi SCTP de ne pas envoyer les battements de cœur aussi souvent que je le voulais. La raison pourquoi je n'avais pas remarqué le drapeau variable, était obsolète le guide de référence de SCTP je lisais, qui a déclaré qu'il n'existe pas de drapeaux variable à l'intérieur de la structure! Référence plus récente a révélé qu'il y avait. Afin de pulsation problème résolu!
Une autre chose est de modifier la rto_max valeur, par exemple, de 2000 ms ou plus. L'abaissement de la valeur indique la SCTP pour modifier le chemin d'accès beaucoup plus tôt. La valeur par défaut est de 60 000 ms qui était trop élevé (1 minute avant qu'il commence à modifier le chemin d'accès). rto_max valeur peut être ajustée avec sctp_rtoinfo struct.
Avec ces deux modifications, l'hébergement multiple commencé à travailler. Oh, et une autre chose. Le Client doit être en mode de FLUX de données lorsque le Serveur est en SEQPACKET mode. Le Client envoie des données à un serveur normal send() de commande de Serveur et de lire les données avec sctp_recvmsg() où addr structure est définie sur NULL.
J'espère que cette information aide les autres gars en difficulté avec l'hébergement multiple de SCTP. Cheers les gars pour vos avis, ceux qui ont été d'une grande aide pour moi! Voici quelques exemple de code, donc ce peut-être le premier d'hébergement multiple exemple simple dans le net, si vous me demandez (pas de trouver des exemples de multistreaming exemples)
Serveur:
Client:
OriginalL'auteur Kari Vatjus-Anttila
Vous client ouvre une assosiation en utilisant sendto (). Il est OK.
Mais après que vous ne devriez pas utiliser sendto() plus. Parce que sendto() sera probablement force SCTP à utiliser l'interface de la propriété intellectuelle.
Ainsi, l'utilisation de write() ou send() au lieu de sendto():
C'est sûrement pas hype, j'ai une poignée d'applications où cela fonctionne parfaitement. 5 paquets, c'est à dire 5 secondes sonne un peu à court d'attente à la variation au cours mais avec ddefault minuteries. Et tbh je ne suis pas sûr de savoir comment les API travaille lorsque vous utilisez la plaine socket api.
OriginalL'auteur SKi
Je n'ai jamais essayé SCTP mais selon cette site il prend en charge deux modèles.
un-à-un style et un-à-plusieurs style.
Autant je comprends l'hébergement multiple les travaux de l'un-à-un style.
Afin d'ouvrir un un-à-un style de douille vous avez besoin d'un appel comme :
Noter que
SOCK_STREAM
est différent de celui de votreSOCK_SEQPACKET
Lorsque vous ne
il semble en ouvrir un, un-à-beaucoup de style prise, que je ne pouvais pas comprendre si elle prend en charge l'hébergement multiple ou non.
Alors essayez de votre code avec
SOCK_STREAM
paramètre.Aussi ici est un exemple qui utilise
SOCK_STREAM
.As far as I understand multihoming works for one-to-one style
est en fait une fausse déclaration. un-à-un et un-à-plusieurs, différent de paradigmes pour la programmation avec sctp sockets. lorsque vous utilisez l'un-à-un, vous du programme "tcp style"; lorsque vous utilisez l'un-à-plusieurs vous programme "udp style" (c'est à dire que vous n'utilisez pas explicitementlisten()
etaccept()
- elles sont effectuées automatiquement dans le noyau). pour plus de détails, pls. d'acheter ou d'emprunter la 3ème édition de la Steven de l'UNP, 1er volume. la sctp api rfc explique cet aspect.OriginalL'auteur O.C.