I created a client that sends broadcast messages over my local network:
#define SERVER_PORT "7777"
int main(int argc, char** argv)
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
if (argc != 3) {
fprintf(stderr,"usage: client ip message\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVER_PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("talker: socket");
continue;
}
break;
}
int broadcast = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1)
{
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
std::cout << "type any number to start: ";
int temp = 0;
std::cin >> temp;
while(1)
{
if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, p->ai_addr, p->ai_addrlen)) == -1)
{
std::cout << "[ERROR] sendto error: " << errno << std::endl;
continue;
}
std::cout << "[INFO] sended: " << numbytes << " bytes!" << std::endl;
sleep(5);
}
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
Yes I'm using while(1) loop without a chance for exit (that's doesn't matter).
This client successfully sends broadcast messages. But how to handle them from the server side? I tried to do it next way (server was written as a class. Here is to main methods):
virtual void Init() override
{
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
int iRes = -1;
if((iRes = getaddrinfo(m_sIpAddress.c_str(), std::to_string(m_iPort).c_str(), &hints, &m_pAddr)) != 0)
{
std::cout << "getaddrinfo error: " << gai_strerror(iRes) << std::endl;
exit(-1);
}
std::cout << "getaddrinfo success!" << std::endl;
m_iSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(m_iSocket == -1)
{
std::cout << "socket error: " << errno << std::endl;
exit(-1);
}
std::cout << "socket created!" << std::endl;
if((iRes = bind(m_iSocket, m_pAddr->ai_addr, m_pAddr->ai_addrlen)) == -1)
{
std::cout << "bind error: " << errno << std::endl;
exit(-1);
}
std::cout << "binded successfully!" << std::endl;
}
virtual void Listen() override
{
int iNumOfReadBytes = -1;
std::string msg;
msg.resize(1024);
sockaddr_in clientAddr;
socklen_t addrLen = sizeof(sockaddr);
while(true)
{
if((iNumOfReadBytes = recvfrom(m_iSocket, const_cast<char*>(msg.c_str()), 1024-1, 0, reinterpret_cast<sockaddr*>(&clientAddr), &addrLen)) == -1)
{
std::cout << "recvfrom error: " << errno << std::endl;
continue;
}
char ip[16]; //string for ip
inet_ntop(AF_INET, &(clientAddr.sin_addr), ip, 16);
std::cout << "[";
for (int i = 0; i < 16; i )
{
std::cout << ip[i];
}
std::cout << "]";
std::cout << msg << std::endl;
}
}
Init method is responsible for initializing of the socket and Listen method for handling broadcast messages.
Lets imagine that server has 192.168.88.123 ip address while client sends broadcast messages on 192.168.88.255 ip.Server should get messages from client, I suppose, but it never actually receives them.
I also tried to configure client to send messages to the 255.255.255.255 ip. Messages were sent, but server didn't get them.
So is it code's fault? Or something with IPs (if it is so, that's very weird)?
P.S. I read the Beej's networking guide. There was a broadcast example, but only from client side. But I'm interesting in handling of such messages from server side.
Thanks!
CodePudding user response:
The code looks fine (though, there are some things I would suggest tweaking, like specifying the IPPROTO_UDP
protocol when calling getaddrinfo()
, and including the AI_PASSIVE
flag on the server side).
Not all network routers allow UDP broadcasts by default. So check your router configuration, as well as your OS firewall. Use a packet sniffer, like WireShark, to make sure the packets are actually leaving the sender's NIC and arriving on the receiver's NIC, that they are not being blocked during transit.
Also, double check to make sure your client socket and server socket are bound to the same subnet, and that the client is sending to the correct broadcast IP for that subnet. Given the server IP of 192.168.88.123
, the broadcast IP would be 192.168.88.255
only if the subnet mask is 255.255.255.0
, is that the case in your environment?
Also, check if you have the same problem if your server binds to 0.0.0.0
(listens on all local NICs) instead of binds to 192.168.88.123
(listens on just 1 NIC).