Skip to main content
GameDev.net gamedev.net
🔒 Locked

UDP Question...

Started by Miraj Mar 15, 2000 at 12:48 AM 12 replies 2.2k views
Original Post
Miraj
Miraj
Does anyone have any sample source code of getting data from a client, then echoing it out to all clients? Or any tutorials that might cover the topic? I can have the server echo the data back to the one client that originally sent it but I don''t know how to update them all. I''m using UDP. Any help would be great, thanks. -Miraj
-Miraj
SiCrane
SiCrane
I''m assuming you''re using winsock.

Ok, currently, once you''ve recvfrom()''d from one socket, you sendto() out that same buffer you just received. So instead sento() to all the current client. Just keep a list of all your clients and their sockaddr data structures, and you should have no problem.

I do have to say, that the system you seem to want to set up would work better in a connection oriented protocol.
Miraj
Miraj
Hi,

I am using Winsock. I understand what your saying. So what if i did this. Upon the client logging into the server, it would hand over its hostname or IP, the server would then add it to its table of addresses, then when the time comes to update everyone do a sendto() to all the IP''s in the table. Am I on the right track or am i forgetting something? And if so, what would you say the best method is for keeping track off all the hostnames, an array maybe?



-Miraj
-Miraj
SiCrane
SiCrane
Well, you don''t need the client to explicitly handover it''s hostname. All you need to do is check to see if the packet is a "login" packet. The recvfrom() call should fill a sockaddr structure. You can get the IP from that struct. Probably an array would be easiest. IP addresses occupy only a long int, so storing up a thousand would only take up 4K memory. If you''re a fan of STL (I''m not) probably the best structure would be a vector.
Miraj
Miraj
Okay, I think I''m getting this.

So if I wanted to get the IP from the sockaddr structure what would I use, gethostbyaddr()?

I''ve tried a few variations, just messing around and I can''t really get it to work. Before getting into anything like actually storing all the addresses I just tried to printf the address, something like:

printf("Address is:", &data);

I tried getting some information on MSDN and there isn''t much there. Maybe I''m just missing something...
-Miraj
Jeff K
Jeff K
struct sockaddr_in addr;
int len, addr_len;
char buf[8192];

addr_len = sizeof(addr);
len = recvfrom(sock, buf, sizeof(buf), (struct sockaddr*)&addr, &addr_len);

if (len > 0)
printf("received %d bytes from %s:%d\n", len,
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
Miraj
Miraj
Okay, I''ve got that much working. Thanks Jeff, I was missing the "inet_ntoa(addr.sin_addr), nto (addr.sin_port));" part

What I decided to do was create a linked list and use that to hold all of the IP''s. But it is not working. Here is the code, its not all of it, just the relevant part of the data handling.

-----------------------------------------------------------
struct sockaddr_in addr; // Address
char buffer[PACKET_SIZE]; // Maximum size of packets
int Read;
int Sent;
int len = sizeof (SOCKADDR); // Number of bytes...
struct sockaddr_in NewIP; // Hold any new addresses...

struct IPEntries // Client database structure...
{
struct sockaddr_in IP; // IP number
struct IPEntries *next;
} start, *node;

start.next = NULL; // Empty List...
node = &start // Point to beginning of list...

// Handle data...
memset (buffer, ''\0'', PACKET_SIZE);
// Listen for packets...
Read = recvfrom (ServerSocket, buffer, PACKET_SIZE, 0, (struct sockaddr*)&addr , &len);

// If no packets begin again...
if (Read == -1)
return;

node->next = (struct IPEntries *) malloc(sizeof(struct IPEntries));
NewIP = addr; // Put our new address in NewIP.
node = node->next;
node->IP = NewIP; // Add it to the list...
node->next = NULL; //....

printf ("Packet : \"%s\", %d bytes, ", buffer,Read);
printf ("echoed %d bytes back\n", Sent);
printf("received %d bytes from %s:%d\n", len, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

// update clients...
Sent = sendto(ServerSocket, buffer, strlen(buffer), 0, (SOCKADDR *)&IPEntries, sizeof (SOCKADDR));

Now I know this is all wrong but am I at least on the right track? If you can find any exact problems here and offer any solutions that''d be great.

Thanks...


-Miraj
-Miraj
SiCrane
SiCrane
I''m pretty sure you can''t simply do assignment on your sockaddr_in structs. You''ll probably need to memcpy the contents.
Also your sendto() is being called on IPEntries... which is a struct definition. Did that even compile?
You''ll need iterate through your needs and call the sendto() on the acutal pointer to the sockaddr_in struct in each node.
Miraj
Miraj
Oh it compiled, with about 30 warnings

Okay, after thinking about arrays I had a moment of weakness
and thought I would go the route of Linked lists. Much too complicated (for me anyway ).

So I''ve gone back to the original idea, of arrays. I''ve memcpy''d the address like you suggested and it is much better.

So doing away with the LLists, I now have memcpy which copies &addr, into &IPList. IPList has looks like this...

IPList[1000];

then i sendto &IPList, and it works, in a sense, because it is echoed back to the original sender, but still not to to both. (I''m testing this with 3 computers, you have no idea how annoying it is to have to get up every 2 minutes after changing the code and testing all three again, on and on, all night ... doh).

After some thinking, I realized one of the reasons (and something that could cause problems down the line) is that the server will only know the client exists once it has recieved at least one login packet and been added to the list. I think that is what you were talking about earlier as well, so I had them each send a login packet first, and tried and still nothing.

So I guess what I need to do is figure out a way to add a new address to the array, but somehow make sure the next new address doesn''t overwrite the previous one in the first byte of IPEntries. Then repeating that and so on, up to 1000, or whatever. Once I have that going, It should work flawlessly i think. But how?





-Miraj
-Miraj
Jeff K
Jeff K

#define MAX_IP 1000
struct sockaddr_in iplist[MAX_IP];
int ipcount = 0;

int ipequal(struct sockaddr_in *a, struct sockaddr_in *b)
{
if (a->sin_addr.s_addr != b->sin_addr.s_addr) return 0;
if (a->sin_port != b->sin_port) return 0;
return 1;
}
void add_ip(struct sockaddr_in *addr)
{
int i;
if (ipcount >= MAX_IP) return;
for (i = 0; i < ipcount; i++) {
/* avoid adding duplicates */
if (ipequal(addr, &iplist[i])) return;
}
iplist[ipcount] = *addr;
ipcount++;
}
void server_loop(int server_socket)
{
char buf[8192];
struct sockaddr_in addr;
int i, len, addr_len;

while (1) {
addr_len = sizeof(addr);
len = recvfrom(server_socket, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &addr_len);
if (len < 0) break;
printf("received %d bytes from %s:%d\n", len, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
add_ip(&addr);
for (i = 0; i < ipcount; i++) {
if (ipequal(&addr, &iplist[i])) continue;
sendto(server_socket, buf, len, 0, (struct sockaddr *)&iplist[i], sizeof(iplist[i]));
}
}
}

After about a dozen edits I finally get this formatting code right...

Edited by - Jeff K on 3/16/00 9:28:48 AM
Miraj
Miraj
Well, one tumor and three days later I think (I THINK) the pieces of the puzzle are finally fitting

Thanks guys for helping out. I seriously couldn''t have done this without the help/snippets. I learned a hell of alot about Winsock, thats for sure.

I wanted to refrain from bothering anyone anymore about this but I do have this one minor glitch that is happening

Is there any possible reason why the client would freeze after recieving a packet? ;( I''ve checked *everything* over and over, numerous times and I just can''t see what would cause it to do that. I have all the nessecary code in order to process the information and don''t get it at all...

-Miraj
-Miraj
daveb
daveb
You might try making sure the socket you're reading-from/writing-to is operating in non-blocking mode. A blocking select or recvfrom() call could be causing this.

Edited by - daveb on 3/21/00 4:29:06 PM
Volition, Inc.
kressilac
kressilac
Miraj,

While reading this post, I noticed something that you are doing that needs to be addressed. In your linked list implementation you were calling send(... IPEntries...) and in your array implementation you called IPList. I think you need to look into iterating and traversing lists of data structures. Both of these issues in your code were related to traversing the list. Jeff fixed it in his. Take note of how he used a for loop to iterate the array list using the index instead of just passing the pointer to the array thinking it will iterate itself.

To iterate an array use his code.

for (int counter = 0; counter == MAX_COUNTER; counter++) {
Do something using the array[counter].
}

To iterate a linked list use the following if you are sure you will always ready every node.

for (Node *pnode = ListHead; !pnode; pnode = pnode->next) {
Do something for pnode->value.
}

Use a while loop instead of a for loop if you think you will stop iterating midway through the linked list. I hope this helps and sorry to get a listtle off topic there, but figured it needed to be mentioned.

Kressilac

Edited by - kressilac on 3/22/00 9:26:14 AM
Derek Licciardi (Kressilac)Elysian Productions Inc.
Miraj
Miraj
Daveb, Kressilac,

Thanks for the input guys. I finally got everything working thanks to all the great responses.

Daveb: You were right about the blocking, that was the problem. I set the appropriate flag and it stopped. I don''t know how I overlooked that.

Kressilac: Thanks for pointing that out. I''m really not that experienced with linked lists yet. It seemed like a reasonable solution to what I wanted to do but I was definatly weak on the implementation of it.

Thanks again!






-Miraj
-Miraj

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.