Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 3 sur 3
  1. #1
    Invité(e)
    Invité(e)

    Par défaut [Sources] [UDP] [réseau] émetteur / récepteur multicast

    Bonjour,

    Voici un petit programme pouvant soit émettre soit recevoir un message multicast UDP.

    En ce qui me concerne, je me sert de se genre de chose pour rechercher une machine sur un réseau local, alors qu'aucun serveur n'est encore connu (ou pour chercher un nouveau serveur)

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    /**
     * petit programme multicast UDP.
     * ce programme peut 
     *  soit envoyer un message sur un groupe multicast, 
     *  soit se mettre en écoute du même groupe et afficher les message reçus.
     * testé avec cygwin et codegear2009 (c++builder) avec xp et vista.
     * *devrait* fonctionner sous VC++ et unixoides.
     * si compilé sous Visual / borland, WIN32 doit être défini
     */
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
     
    #ifdef WIN32
    #include <Winsock2.h>
    #include <ws2ipdef.h>
    #include <ws2tcpip.h>
    #ifdef __BORLANDC__
    #pragma link "Ws2_32.lib"
    #else
    #pragma comment(lib, "Ws2_32.lib")
    #endif
    #else
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
     
    #endif
     
     
    # define BUFSZ 512
    # define MULTICAST_PORT  7766
    # define MULTICAST_GROUP "224.0.0.1"
     
     
    /**
     * socket creation function.
     * this function will create a multicast socket for reading or writing.
     * @param[out] sock: structure sockaddr_in used in recv/sendto functions
     * @param[in] type: type of socket: 'r' for reading, 'w' for writing
     * @return a opened socket. Exit program on error (exit() called)
     */
    int socket_init(struct sockaddr_in *sock, char type)
    {
     
        int sd;
        unsigned char ttl = 1;
     
        /* create socket */
        sd = socket(PF_INET, SOCK_DGRAM, 0);
        if (sd < 0) {
            perror("socket");
            exit(EXIT_FAILURE);
        }
        /* initialize sock descriptor */
        memset(sock, 0, sizeof(struct sockaddr_in));
     
        switch (type) {
        /* receive mode */
        case 'r':
            sock->sin_family = AF_INET;
            sock->sin_port = htons(MULTICAST_PORT);
            sock->sin_addr.s_addr = htonl(INADDR_ANY);
            /* bind */
            if (bind(sd, (struct sockaddr *) sock, sizeof(struct sockaddr_in))
                < 0) {
                perror("bind");
                exit(1);
            }
            /* enable multicast */
            {
                struct ip_mreq imr;
     
                imr.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);        /* multicast group to join */
                imr.imr_interface.s_addr = htonl(INADDR_ANY);       /* interface to read on */
     
                /* set GROUP option */
                if (setsockopt
                    (sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &imr,
                     sizeof(struct ip_mreq)) < 0) {
                    perror("setsockopt: IP_ADD_MEMBERSHIP");
                    exit(1);
                }
     
                /* enable multicast */
                if (0 !=
                    setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
                               sizeof(ttl))) {
                    perror("setsockopt");
                    exit(1);
                }
            }
     
     
            break;
        /* transmission mode */
        case 'w':
            sock->sin_family = AF_INET;
            sock->sin_port = htons(MULTICAST_PORT);
            sock->sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
            {
                /* enable multicast */
                if (setsockopt
                    (sd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
                     sizeof(ttl)) == -1) {
                    perror("setsockopt: IP_MULTICAST_TTL");
                    exit(EXIT_FAILURE);
                }
            }
            break;
        default:
            printf("socket_init: unknown type /%c/\n", type);
            exit(EXIT_FAILURE);
        }
        return sd;
    }
     
     
    void m_receive(void)
    {
        struct sockaddr_in from;
        socklen_t len = sizeof(from);
        /* create the reception socket */
        int sd = socket_init(&from, 'r');
        int cnt;
        char buf[BUFSZ];
        /* infinite loop */
        while (1) {
            /* try to receive from socket */
            cnt =
                recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *) &from,
                         &len);
            if (cnt < 0) {
                /* something bad happened, quit */
                perror("recvfrom");
                exit(1);
            } else if (cnt == 0) {
                /* socket closed (udp should never goes here) exit while loop */
                break;
            }
            /* all goes right, write the received message */
            buf[cnt] = 0;
            printf("%s\n", buf);
        }
        printf("m_receive: done\n");
    }
     
     
     
    /**
     * transmission function.
     * @param buf: message to send.
     */
    void m_send(const char *buf)
    {
        struct sockaddr_in to;
        int len = sizeof(to);
        /* create the transmission socket */
        int sd = socket_init(&to, 'w');
        int cnt;
     
        /* send the message (just like we whoumd have done with regular
           socket */
        cnt = sendto(sd, buf, strlen(buf), 0, (struct sockaddr *) &to, len);
        if (cnt < 0) {
            perror("sendto");
            exit(1);
        }
     
    }
     
     
    /** usage : 
     *      cmd.exe r
     *      cmd.exe w message  
     */
    void usage(const char *name) {
        printf("usage :\n\n");
        printf("reception mode\n");
        printf("\t %s r\n\n", name);
        printf("transmission mode\n");
        printf("\t %s w message to send\n", name);
    }
     
    /**
     * Application entry point
     */
    int main(int argc, char **argv)
    {
    #ifdef WIN32
        WSADATA wsaData;
        int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (ret != 0) {
            printf("WSAStartup failed: %d\n", ret);
            return 1;
        }
    #endif
     
     
        if (argc < 2) {
            usage(*argv);
     
        } else {
        switch (*argv[1]) {
        case 'r':
                /* go in receive mode */
            m_receive();
            break;
        case 'w':
                /* note that this method is not optimized : we create a socket
                   of each word of the message to send. */
                {
                    int i;
            for (i = 2; i != argc; ++i) {
                        /* send each parameter given to program*/
                m_send(argv[i]);
            }
                }
     
            break;
        default:
                usage(*argv);
            }
        }
    #ifdef WIN32
        WSACleanup();
    #endif
        return 0;
    }

  2. #2
    Membre Expert Avatar de orfix
    Homme Profil pro Mounir Orfi
    Inscrit en
    avril 2007
    Messages
    706
    Détails du profil
    Informations personnelles :
    Nom : Homme Mounir Orfi
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : avril 2007
    Messages : 706
    Points : 1 075
    Points
    1 075

    Par défaut

    Pourquoi ne pas faire ressortir à l'extérieur du switch les blocs communs aux deux types r/w histoire de ne garder que ceci pour le 'w':
    Code :
    1
    2
    3
    case 'w':
        sock->sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
        break;
    Si c'est pour faciliter l'ajout de d'autres types dans le futur alors je comprends

    Merci en tout cas pour ce bout de code fort utile.
    To start press any key. (reading screen) Where's the "any" key? I see Esc, Catarl, and Pig Up. There doesn't seem to be any "any" key. Wo! All this computer hacking is making me thirsty. I think I'll order a Tab. (presses TAB key). -- HOMER --

  3. #3
    Invité(e)
    Invité(e)

    Par défaut

    Citation Envoyé par ssmario2 Voir le message
    Pourquoi ne pas faire ressortir à l'extérieur du switch les blocs communs aux deux types r/w histoire de ne garder que ceci pour le 'w':[...]
    Deux raisons :

    Je ne conçois pas de séparer l'affectation des différents champs de SOCKADDR_IN.

    Aussi à l'origine ce code contenait de quoi créer des sockets UDP unicast, cela explique pourquoi on a du code redondant dans le switch.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •