I am trying to follow this tutorial on how to send UDP packages in C++. Unfortunately I cannot get it to work.
I tracked loopback traffic with Wireshark on port 30001, but it did not display any packets, so it seems like the sending is already failing.
I added my executable to the firewall to ensure it's not getting blocked, and ran the program in two separate terminal windows using sudo ./main receiver
or sender
(Also without sudo
). I am on Mac OS, which is why I have not implemented the Windows-specific code yet.
I would really appreciate some help, since I am a bit stuck, and I am quite a beginner in networking on this level.
Here is my code:
Main.cpp
#include <iostream>
#include "Socket.h"
#include "Address.h"
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " [sender|receiver]" << std::endl;
return 1;
}
const std::string mode = argv[1];
if (mode == "sender")
{
int port = 30001;
Address sendAddress = Address(127, 0, 0, 1, 30000);
Socket socket;
if(!socket.Open(port))
{
std::cout << "Failed to open socket!" << std::endl;
return 1;
}
const char data[] = "Hello World!";
if(!socket.Send(sendAddress, data, sizeof(data))
{
std::cout << "Failed to send message!" << std::endl;
}
}
else if (mode == "receiver")
{
Socket socket;
int port = 30000;
if(!socket.Open(port))
{
std::cout << "Failed to open socket!" << std::endl;
return 1;
}
while(true)
{
Address sender;
unsigned char buffer[512];
int bytes_read = socket.Receive(sender, buffer, sizeof(buffer));
if(!bytes_read){
break;
}
if(bytes_read > 0)
{
std::cout << "Received " << bytes_read << " bytes" << std::endl;
std::cout << buffer << std::endl;
}
else
{
std::cout << "." << std::endl;
}
}
}
else
{
std::cout << "Invalid mode! Use 'sender' or 'receiver'." << std::endl;
return 1;
}
std::cout << "Program closing! Good bye!" << std::endl;
return 0;
}
Socket.cpp
#define PLATFORM_WINDOWS 1
#define PLATFORM_MAC 2
#define PLATFORM_UNIX 3
#if defined(_WIN32)
#define PLATFORM PLATFORM_WINDOWS
#elif defined(__APPLE__)
#define PLATFORM PLATFORM_MAC
#else
#define PLATFORM PLATFORM_UNIX
#endif
#if PLATFORM == PLATFORM_WINDOWS
#include <winsock2.h>
#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include "Socket.h"
#include "Address.h"
#include <iostream>
Socket::Socket()
{
}
Socket::~Socket()
{
Close();
}
bool Socket::Open(unsigned short port)
{
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (handle <= 0){
std::cout <<("Failed to create socket")<<std::endl;
return false;
}
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons((unsigned short) port);
if(bind(handle, (const sockaddr*) &address, sizeof(sockaddr_in)) < 0)
{
std::cout <<("Failed to bind socket")<<std::endl;
return false;
}
#if PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
int nonBlocking = 1;
if ( fcntl( handle, F_SETFL, O_NONBLOCK, nonBlocking ) == -1 )
{
printf( "failed to set non-blocking\n" );
return false;
}
#elif PLATFORM == PLATFORM_WINDOWS
DWORD nonBlocking = 1;
if ( ioctlsocket( handle, FIONBIO, &nonBlocking ) != 0 )
{
printf( "failed to set non-blocking\n" );
return false;
}
#endif
return true;
}
void Socket::Close()
{
#if PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
close( handle );
#elif PLATFORM == PLATFORM_WINDOWS
closesocket( socket );
#endif
}
bool Socket::Send(const Address& destination, const void* packet_data, int packet_size)
{
int sent_bytes = sendto(
handle,
(const char*)packet_data,
packet_size,
0,
(sockaddr*)&destination,
sizeof(sockaddr_in));
if(sent_bytes != packet_size )
{
printf( "failed to send packet\n" );
return false;
}
std::cout << "Sent " << sent_bytes << " bytes" << std::endl;
return true;
}
int Socket::Receive(Address& sender, void * data, int size)
{
#if PLATFORM == PLATFORM_WINDOWS
typedef int socklen_t;
#endif
unsigned char packet_data[size];
unsigned int max_packet_size = sizeof( packet_data );
sockaddr_in from;
socklen_t fromLength = sizeof( from );
int bytes = recvfrom(handle,
(char*)packet_data,
max_packet_size,
0,
(sockaddr*)&from,
&fromLength );
if ( bytes <= 0 )
return -1;
unsigned int from_address = ntohl( from.sin_addr.s_addr );
unsigned int from_port = ntohs( from.sin_port );
sender = Address( from_address, from_port );
return bytes;
}
Address.cpp
#define PLATFORM_WINDOWS 1
#define PLATFORM_MAC 2
#define PLATFORM_UNIX 3
#if defined(_WIN32)
#define PLATFORM PLATFORM_WINDOWS
#elif defined(__APPLE__)
#define PLATFORM PLATFORM_MAC
#else
#define PLATFORM PLATFORM_UNIX
#endif
#if PLATFORM == PLATFORM_WINDOWS
#include <winsock2.h>
#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#endif
#include "Address.h"
Address::Address()
{
}
Address::Address(unsigned char a, unsigned char b, unsigned char c, unsigned char d, unsigned short port)
{
unsigned int address = ( a << 24 ) |
( b << 16 ) |
( c << 8 ) |
d;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl( address );
addr.sin_port = htons( port );
Address::port = port;
Address::address = address;
}
Address::Address(unsigned int address, unsigned short port)
{
Address::port = port;
Address::address = address;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl( address );
addr.sin_port = htons( port );
}
unsigned int Address::GetAddress() const
{
return address;
}
unsigned char Address::GetA() const
{
return ( GetAddress() >> 24 ) & 0xFF;
}
unsigned char Address::GetB() const
{
return ( GetAddress() >> 16 ) & 0xFF;
}
unsigned char Address::GetC() const
{
return ( GetAddress() >> 8 ) & 0xFF;
}
unsigned char Address::GetD() const
{
return GetAddress() & 0xFF;
}
unsigned short Address::GetPort() const
{
return port;
}
As requested here are my header files as well: Socket.h
#pragma once
class Socket
{
public:
Socket();
~Socket();
bool Open(unsigned short port);
void Close();
bool IsOpen() const;
bool Send(const class Address& destination , const void * packet_data, int packet_size);
int Receive(class Address& sender, void * data, int size);
private:
int handle;
};
Address.h
#pragma once
class Address
{
public:
Address();
Address(unsigned char a,
unsigned char b,
unsigned char c,
unsigned char d,
unsigned short port );
Address(unsigned int address, unsigned short port );
unsigned int GetAddress() const;
unsigned char GetA() const;
unsigned char GetB() const;
unsigned char GetC() const;
unsigned char GetD() const;
unsigned short GetPort() const;
private:
unsigned int address;
unsigned short port;
};