🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

I'm really confused how to do some things in UDP!

Started by
6 comments, last by kalldrex 23 years, 4 months ago
I can''t really figure out how to figure out which client matches up with each IP address yet without code modifications. Like if someone crashes and doesn''t come back on how do i send checks to him and not to anyone else and when i get a message that he timedout disconnect only his ip address not any others? I also need this for sending messages only to certain players and some other things. Could someone please explain in detail i''d really appreciate this. Thanks
ALL YOUR BASE ARE BELONG TO US!!!!
Advertisement
You haven''t mentioned whether you are using TCP or UDP, so I''ll describe both. I''ll assume that you keep a list of remote hosts, each of which is a RemoteHost struct.

* UDP: You create and bind a single socket to communicate with all of the other hosts. When you first get a packet from someone using recvfrom(), you create a new RemoteHost and store the IP address/port in it. When you get another packet, you use it''s IP address/port to find an existing RemoteHost or create a new one. When you want to send a packet to someone, you just sendto() the IP address/port that he talks to you, the one from his RemoteHost struct.

* TCP Server: You create and bind a listener socket. When you get an incoming connection request, you call accept() to create a new socket for that connection. You store the new socket ID (and optionally the IP address/port of the host) in your RemoteHost structure. When you recv() or send() data, you just use the socket stored in the RemoteHost structure -- you never need the IP address after the connection has been established.

* TCP Client: You create a socket and connect() to a server, and create a RemoteHost structure with that socket and IP address. When you recv() or send() data, you just use the socket stored in the RemoteHost structure -- you never need the IP address after the connection has been established.

The tricky part is not recognizing who sent you data, or sending data to a particular RemoteHost, but just *finding* a host the first time -- whether the user enters it or you contact some sort of master server to get a current game list.

Matt Slot / Bitwise Operator / Ambrosia Software, Inc.
Well from my title Itsays i''m talking about UDP so....

I still don''t know how you would have the game:
1-detect if an ip address holding structure is in use or not
2-having the server pick out which client to send which info!
3-Having the game create more sturcts to store ip address when no more are available. Remember i''m trying to make an MMORPG so we need lots of ip holding structs and we can''t have it limited, unless it''s impossible any other ways.

Can anyone tell me information on doing these things? thx
ALL YOUR BASE ARE BELONG TO US!!!!
Ive written several tcp/ip based client-server programs, my most sophisticated one is a telnet ¥port 23¤ chat/test server that accept clients and proccesses them using the windows asynchrous message api via winsock© I decided to use a linked list to store clients so it would be unlimited© However, if I was writing a game server I wouldnt use linked lists, I would probably use a static array of pointers to structs, ie:

typedef struct RemotePlayer
{
SOCKET socket;
unsigned long id;
char username[16];
void *otherdata;
}

#define MAX_PLAYERS 512
RemotePlayer *lpPlayers[MAX_PLAYERS];

Each lpPlayer pointer should be initialised to NULL, when a client connects you can cycle through them until you find a NULL one and allocate memory for it© When you have finished, you set it back to NULL© If all of them are in use and there are none which arent allocated to NULL then you know the server has reached its max© You can easily cycle through at exit and dealloc each one too like a linked list© This also has the advantage of only taking up 4-bytes, the size of a pointer unless it is initiaized© If you dont use a pointer, theyw would all take up sizeof¥RemotePlayer¤ bytes which could take a lot of memory if the struct is big, ie, stores lots of player info©

That way, you could stop too many players from connecting easier, and then when you reach the maximum amount of players you can reject any others that try to connect, another way to do it would be to use linked lists© The only limit is the amount of memory you have, so its best to implement a physical limit otherwise if too many people connect you will have alot of problems© Also, some operating systems like win98/win95/winme/winse have a limit of the total amount of open sockets© I beleive its 127 in those operating systems, winnt/bsd/linux/unix can handle many many more, but you still have to worry about your connection/bandwidth© This is how you would implement a linked list:

typedef struct RemotePlayerList
{
SOCKET socket;
unsigned long id;
char username[16];
void *otherdata;

/* Next item */
RemotePlayerList *next;
}

RemotePlayerList *lpPlayerList;

This is slightly more involved, you can also use a double-linked list but I prefer this method for its simplicity© This is versatile than the previos method, you can allocate and deallocate items as you wish© To add an item, use a pointer to cycle to the end, to traverse a linked list like this you can do something like this:

RemotePlayerList *lpTemp;

lpTemp = lpPlayerList;
while ¥lpTemp != NULL¤
lpTemp = lpTemp->next;

You can then go through each client performing operations on it, find the last client and add a client to the end of it using the next pointer on it or remove a client by making sure the RemotePlayerList structs ¥if they exist¤ before and after it change their next values to reflect the fact that it no longer exists©

I hope you find this useful, I havent really made any networked games yet© All my knowledge of sockets is mainly from writing programs that show the basics of networking and from reading tutorials© If anyone finds anything incorrect with what ive said, feel free to correct me©
CorsairK8@Fnemesis.comLinux Debian/GNU RulezThis is my signitory!C Is Tha Best!
It seems my browser is terribly screwed up and is inserting strange symbols everywhere©
CorsairK8@Fnemesis.comLinux Debian/GNU RulezThis is my signitory!C Is Tha Best!
wow thanks a lot that helped except for one thing. You really didn''t explain how to do like you said and have it check if it''s null or not or even how to define the ip players thing. could you explain that a little more other than that thanks a lot!
ALL YOUR BASE ARE BELONG TO US!!!!
kalldrex: Its quite easy to check if something is null, basically an pointer type can either have a normal value or be set to NULL© The value NULL should be defined as ¥void *¤0 I think and its best to keep pointers at that value unless its pointed to something useful© Otherwise you could end up accessing memory that doesnt belong to you© To check a value for null:

void *data;

if ¥!data¤ printf¥"The value ''data'' is NULL\n"¤;

You can also do it like this:

if ¥data == NULL¤ printf¥"The value ''data'' is NULL\n"¤;

Im sure you can figure out how to apply this to what you need to do, if you want to check whether the next item in a linked list exists you can check lpTemp->next is null, or if it points to the next item©

Also, there is a very easy way to determine the IP address from a UDP socket© Im not sure if this only applies to TCP/IP as I have very limited knowledge of UDP but this is how it would be done in TCP/IP:

sockaddr_in socket_addr;
getsockname¥socket, ¥sockaddr_in *¤ &socket_addr, sizeof¥sockaddr_in¤¤;

Rember that sockaddr_in and sockaddr occupy the same amount of memory, they are two different structs that can be used to represent the same information© However, sockaddr_in is specifically used for the PF_INET protocol© Therefor, we should use that© There are functions that can convert between sockaddr_in/sockaddr and an ascii string but for now just imagine that sockaddr_in is a struct that contains the ip and port of the connection made by socket©

You should be able to use sendto/recvfrom to send to that hostname© Im not exactly sure how UDP works though, I think multiple clients can share a single socket while in TCP/IP everything is connection based and a socket represents a connection to a single client© You will most likely have to look at your documentation/help files to find out how it works©

Id suggest keeping track of the sockaddr structure you should get when accepting a connection from a client and then use that for subsequent sends© If you use my method of storing each clients infomation in a structure then you can easily add one© Id reccomend:

typedef struct RemotePlayerList
{
SOCKET socket;
unsigned long id;
char username[16];

RemotePlayerGameData *gamedata; /* You might wanna use a struct to store game data like hps, items carried ect until its flushed to a save file / data file for that player© */

time_t connected; /* Good to keep record of when clietn connect */

int logged_on; /* Flag to see if hes logged on */
sockaddr_in *sockaddr; /* Pointer to sockaddr struct */

/* Next item */
RemotePlayerList *next;
}

When you want to send something, you can then do soemthing like this:

#ifndef TRUE
#define TRUE
#endif

#ifndef FALSE
#define FALSE
#endif

extern int bytes_left_from_last_send;

/* Sends any number of bytes of data to a specific player, returns FALSE on failure, TRUE of success */
int send_to_player¥RemotePlayerList *player, const void *data, unsigned long size¤
{
/* Invalid Player */
if ¥player == NULL¤ return FALSE;

/* A bit too much data */
if ¥size > 4096¤ return FALSE;

/* Send data to the client, you might not wanna use flag MSG_DONTWAIT, I beleive this is used to make it not block, but this is accordign to my linux manual page, it might not apply to windows/async sockets© */
int success = sendto¥player->socket, data, size, MSG_DONTWAIT, player->sockaddr, sizeof¥sockaddr¤¤;

/* We couldnt send it */
if ¥succcess <= 0¤ return FALSE;

/* Check how much we sent, sendto returns amount of bytes sent or less than 0 for error */
if ¥success == size¤ return TRUE;

/* This should never happen, if it does then soemthing has gone terribly wrong© We cannot send more bytes of data than we have told it to */
if ¥success > size¤ exit¥1¤;

/* Use this in debug builds */
/* assert¥!¥success > size¤¤; */

/* We have sent some info, but not all, we need to send the rest ¥not sure about udp, but in tcp we must¤ */
bytes_left_from_last_send = size - success;
}

I hope this helps :¤
CorsairK8@Fnemesis.comLinux Debian/GNU RulezThis is my signitory!C Is Tha Best!
Sorry kelldrex, my browser is very retarted© Ive got to switch back to netscape or reinstall it© Basically all the ''¥'' symbols are open brackets and ''¤'' is the closed brackets©

Ive just realised that UDP is connectionless, therefor you need to grab the persons sockaddr info the moment they send their first packet and create your RemotePlayerList struct based on that information© You should be able bind the address from that onto the socket and use that socket to send/recv data to any or all clients©

CorsairK8
CorsairK8@Fnemesis.comLinux Debian/GNU RulezThis is my signitory!C Is Tha Best!

This topic is closed to new replies.

Advertisement