我有一个简单的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;
}