UDP Multicast recvfrom多次读取相同的数据报

时间:2016-03-24 02:05:32

标签: c++ multithreading sockets udp multicast

我有一个简单的UDP多播程序,其中主线程产生两个工作线程。这三个共享一个UDP多播套接字。现在这个程序可以工作,虽然recvfrom调用每个数据包发生两次。也许是第一次调用它时,它没有正确清除接收缓冲区?如果是这样,我将如何解决此问题。

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string>
#include <pthread.h>
#include <unistd.h>

#define MULTICAST_PORT 23456
#define MULTICAST_ADDRESS "239.255.24.25"
#define MESSAGE_BUFFER_SIZE 256

using namespace std;

struct sockaddr_in sendaddr;
socklen_t sendaddrlen;
int sock;
string username;
pthread_mutex_t mut;

void print(string message) {
    pthread_mutex_lock(&mut);
    printf("%s\n", message.c_str());
    pthread_mutex_unlock(&mut);
}

void *sender_actor(void *arg) {

    // Prepare Message
    string message = "ANNOUNCE " + username;
    long bytes_sent;

    while (true) {
        print("sender thread: preparing to send message");
        bytes_sent = sendto(sock, message.c_str(), message.length() + 1, 0, (struct sockaddr *)&sendaddr, sendaddrlen);
        print("sender thread: sent message");
        if (bytes_sent < 0) {
            cerr << "sendto failed" << endl;
            exit(EXIT_FAILURE);
        }
        sleep(60);
    }

    return 0;
}

void *recipient_actor(void *arg) {

    // Declare Address
    struct sockaddr_in other;
    socklen_t otherlen;

    // Prepare Buffer
    long bytes_received;
    char message_buffer[MESSAGE_BUFFER_SIZE];

    while (true) {
        print("receiver thread: preparing to receive message");
        bytes_received = recvfrom(sock, message_buffer, MESSAGE_BUFFER_SIZE, 0, (struct sockaddr *)&other, &otherlen);
        if (bytes_received < 0) {
            cerr << "recvfrom failed" << endl;
            exit(EXIT_FAILURE);
        }
        print("receiver thread: received message:");
        print(message_buffer);
    }

    return 0;
}

int main(int argc, const char * argv[]) {

    // Check arguments:
    if (argc != 2) {
        cerr << "invalid number of arguments" << endl;
        exit(EXIT_FAILURE);
    }

    // Extract username:
    username = argv[1];

    // Create a UDP socket:
    sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
    if (sock < 0) {
        cerr << "failed to create socket" << endl;
        exit(EXIT_FAILURE);
    }

    // Allow multiple sockets for the port:
    u_int yes = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
        perror("Reusing ADDR failed");
        exit(1);
    }

    // Setup destination address:
    struct sockaddr_in recvaddr;
    memset(&recvaddr,0,sizeof(recvaddr));
    recvaddr.sin_family = AF_INET;
    recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    recvaddr.sin_port = htons(MULTICAST_PORT);
    socklen_t recvaddrlen = sizeof(recvaddr);

    // Bind the socket to the address:
    if (bind(sock,(struct sockaddr *) &recvaddr, sizeof(recvaddr)) < 0) {
        cerr << "bind failed" << endl;
        exit(EXIT_FAILURE);
    }

    // Join multicast group:
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        cerr << "setsockop failed" << endl;
        exit(EXIT_FAILURE);
    }

    // Create sender thread:
    pthread_t sender_thread;
    pthread_create(&sender_thread, NULL, sender_actor, NULL);

    // Create recipient thread:
    pthread_t recipient_thread;
    pthread_create(&recipient_thread, NULL, recipient_actor, NULL);

    // Initialize Send Address
    memset(&sendaddr,0,sizeof(sendaddr));
    sendaddr.sin_family = AF_INET;
    sendaddr.sin_addr.s_addr = inet_addr(MULTICAST_ADDRESS);
    sendaddr.sin_port = htons(MULTICAST_PORT);
    sendaddrlen = sizeof(sendaddr);

    // Read input and send messages:
    long bytes_sent;
    string message;
    while (true) {
        getline(cin, message);
        message = "FROM:" + username + " " + message;
        print("main thread: preparing to send message");
        bytes_sent = sendto(sock,message.c_str(), message.length() + 1, 0, (struct sockaddr *)&sendaddr, sendaddrlen);
        print("main thread: sent message");
        if (bytes_sent < 0) {
            cerr << "sendto failed" << endl;
            exit(EXIT_FAILURE);
        }
    }

    return 0;
}

0 个答案:

没有答案