simple udp send/receive app

Started by
4 comments, last by MrShmoo 20 years, 11 months ago
hi...my friend and i are writing a game that we would like to use udp networking with...but we're having some trouble getting started with just sending simple text messages back and forth. our send function is printing out 'sent' but our receiver isn't getting anything. here is the header file for our class and the code: struct myaddrT { int port; char* ip; }; class CUDPConnection { public: CUDPConnection(); CUDPConnection(int port); ~CUDPConnection(); bool m_send(char* dat); bool m_recieve(char* dat); bool m_sendaddr(char* dat, myaddrT addr); bool m_sendaddr(char* dat, char* ip, int port); void m_setaddr(char* ip, int port); void m_setaddr(myaddrT addr); void m_setmsglen(int len); bool m_checkrecieve(); void m_closeconnection(); private: sockaddr_in m_myaddr; sockaddr_in m_remoteaddr; sockaddr_in m_recaddr; SOCKET m_recsocket; SOCKET m_sensocket; timeval m_to; int m_msglen; }; CUDPConnection::CUDPConnection() { CUDPConnection(5555); } CUDPConnection::CUDPConnection(int port) { m_to.tv_sec = 0; m_to.tv_usec = 0; memset((char*)&m_myaddr, 0,sizeof(m_myaddr)); m_myaddr.sin_family = AF_INET; m_myaddr.sin_addr.s_addr = htonl(INADDR_ANY); m_myaddr.sin_port = htons(port); m_recsocket = socket(AF_INET, SOCK_DGRAM, 0); m_sensocket = socket(AF_INET, SOCK_DGRAM, 0); bind( m_recsocket, (sockaddr*)&m_myaddr, sizeof(m_myaddr)); m_msglen = 0; } CUDPConnection::~CUDPConnection() { m_closeconnection(); } bool CUDPConnection::m_recieve(char* dat) { memset((char*)&m_recaddr,0,sizeof(m_recaddr)); int sockaddrlen = sizeof(SOCKADDR_IN); int status = recvfrom(m_recsocket, dat, m_msglen, 0, (sockaddr*)&m_recaddr, &sockaddrlen); if(status == SOCKET_ERROR) return false; return true; } bool CUDPConnection::m_send(char* dat) { int status = sendto(m_sensocket, dat, m_msglen, 0, (sockaddr*)&m_remoteaddr, sizeof(m_remoteaddr)); if(status == SOCKET_ERROR) return false; return true; } bool CUDPConnection::m_sendaddr(char* dat, myaddrT addr) { m_setaddr(addr); return m_send(dat); } bool CUDPConnection::m_sendaddr(char* dat, char* ip, int port) { m_setaddr(ip, port); return m_send(dat); } void CUDPConnection::m_setaddr(char* ip, int port) { memset((char*)&m_remoteaddr,0,sizeof(m_remoteaddr)); m_remoteaddr.sin_addr.s_addr = inet_addr(ip); m_remoteaddr.sin_family = AF_INET; m_remoteaddr.sin_port = port; } void CUDPConnection::m_setaddr(myaddrT addr) { memset((char*)&m_remoteaddr,0,sizeof(m_remoteaddr)); m_remoteaddr.sin_addr.s_addr = inet_addr(addr.ip); m_remoteaddr.sin_family = AF_INET; m_remoteaddr.sin_port = addr.port; } void CUDPConnection::m_setmsglen(int len) { m_msglen = len; } void CUDPConnection::m_closeconnection() { closesocket(m_recsocket); closesocket(m_sensocket); } void send_msg(CUDPConnection* sender) { sender->m_setmsglen(32); if(sender->m_sendaddr("b","10.13.30.203",5555)) //hardcoded in for now cout << "sent\n"; } void receive_msg(CUDPConnection* receiver) { receiver->m_setmsglen(32); char data[32]; if(receiver->m_recieve(data)) { cout << "I'm receiving!!!!! " << data << endl; } } thanks [edited by - MrShmoo on May 5, 2003 5:28:14 PM]
Advertisement
1. Don't have to do a 'm_myaddr.sin_addr.s_addr = htonl(INADDR_ANY);'.
Just do 'm_myaddr.sin_addr.s_addr = INADDR_ANY;'...

2. Below is my code. It is ugly and there's no error checking, etc... It is the worst example of how to code networking apps, but it works. Don't copy it blindly (it will probably crash your app when you try to upgrade it), but look and compare it with yours.

---------------------------------------------------------

#include <sys/socket.h>
#include <sys/types.h>
#include <resolv.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

//////////////////////////////
// the socket class
//////////////////////////////

class Socket
{

public:

Socket (short int port);
~Socket ();

void send_message (char * address, short int port, void * message);
void receive_message (void * message);

private:

int sd;
struct sockaddr_in * addr;

};

Socket::Socket (short int port)
{

addr = new struct sockaddr_in;
addr->sin_family = AF_INET;
addr->sin_port = htons (port);
addr->sin_addr.s_addr = INADDR_ANY;

if ((sd = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
perror ("socket");
if ((bind (sd, reinterpret_cast (addr), sizeof(struct sockaddr))) < 0)
perror ("bind");
}

Socket::~Socket ()
{
close (sd);
delete addr;
}

void Socket::send_message (char * address, short int port, void * message, short message_length)
{

struct sockaddr_in dest;

dest.sin_family = AF_INET;
dest.sin_port = htons (port);
inet_aton(address, &dest.sin_addr);

printf ("%s : %d << %s\n", inet_ntoa (dest.sin_addr), port, message);
if (sendto(sd, message, message_length, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0)
perror ("sendto");

}

void Socket::receive_message (void * message, short message_length)
{

unsigned int addr_size = sizeof (struct sockaddr_in);
// WARNING!!! Buffer overflow!!!!!!
if ((recvfrom (sd, message, message_length, 0, (struct sockaddr*)addr, &addr_size)) < 0)
perror ("recvfrom");
printf ("%s : %d >> %s\n", inet_ntoa(addr->sin_addr),
ntohs (addr->sin_port), message);

}

-----------------------------------------------------

It's quite clear. Simply create a socket on a certain port and use its methods to send messages and receive messages to and from your peers.

I would also recommend you visiting these pages:
http://www.linuxgazette.com/issue74/tougher.html
http://www.linuxsocket.org/books/Sockets/programs/


"I'll be Bach!" (c) Johann Sebastian Schwarzenegger


[edited by - x33 on May 5, 2003 10:07:08 PM]
"I'll be Bach!" (c) Johann Sebastian Schwarzenegger
Hi, we fixed our original problem! But we have some questions about the code you posted, x33.

unsigned int addr_size = sizeof (struct sockaddr_in);
// WARNING!!! Buffer overflow!!!!!!
if ((recvfrom (sd, message, message_length, 0, (struct sockaddr*)addr, &addr_size)) < 0)

We were wondering what you mean in your comments "Buffer overflow!!!!!!".

Also we noticed that you are using a void* in your recvfrom function, but not your send function. Why can you do that?

Thanks a bunch!

[edited by - mrshmoo on May 6, 2003 7:51:25 PM]
The buffer overflow warning stands there because there could be problems with this code.
Imagine we pass a char[10] to the receive function as the 'void * message' and decimal 40 as the 'short message_length'.
Now we got our application screwed, because there could be situations when the recvfrom actually received bigger amount of data than our buffer (10 bytes long) can hold. The 11th byte gets written to the 11th element of the buffer (but there's no 11th element allocated, so the write operation gets us out of the buffer boundaries (buffer overflow)). Segmentation fault is caused then. So you have to do checking for that to avoid problematic situations. (Hey, I warned you that code is UGLY ). Ofcourse, these situations never occur when you have fixed-sized buffers, but what if you want to transfer variable-sized data? Yep, problems appear (this type of mistake is easy to localize and fix in such a simple app, but in a more complex structure you could get you brain boiled until you found the reason of the 'unknown crashes'...)

I'm using void* for the data buffer in both send_message() and receive_message() just to avoid anoying type checking. (AGAIN, UGLY code). I can pass data of any type and transfer it correctly on machines with the same architecture / bit-endianness... I don't recommend you using that.

One more thing: buffer overflow is one of the most dangerous types of mistakes for the network environment, because you can never be sure whether the user is not intending to crash your server using your apps 'weak places'... Be extremely careful with that!


"I'll be Bach!" (c) Johann Sebastian Schwarzenegger

[edited by - x33 on May 6, 2003 12:42:59 AM]
"I'll be Bach!" (c) Johann Sebastian Schwarzenegger
Pointers are just integers once the front end is done parsing them.
Thanks you guys. This helps a lot.

This topic is closed to new replies.

Advertisement