Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (516)
Games in Android Showcase (122)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [UDP] Packets getting clogged up in server  (Read 3042 times)
0 Members and 1 Guest are viewing this topic.
Offline roland
« Posted 2011-12-28 12:31:21 »

Hi, I've been making a server and client program. It is mostly going well, apart from the fact when clients join and send lots of packets to the server, the server starts to get behind in responding to the clients. The strange thing is that i have a while loop executed each frame in the server that doesn't break until there is a timeout(no more messages to receive). And I only reply to the most recent message from each client and discard the rest. The server works fine with say 2 clients sending at 30 packets per second, but if i keep adding clients (say 4 or 5), this problem starts occurring.

The only reason I think that this could happen is if the clients are sending so many packets that the server gets stuck in the while loop forever, but this isn't the case. The server replies, it just can't reply as fast as the clients are sending the packets, and over time it is replying to packets that clients sent 20 or 30 seconds ago or even longer if I just leave it there. I don't know why it is replying to old packets though - my while loop should receive every message and remove all the old messages. It shouldn't be replying to messages it received 20 seconds ago when there are packets that have just arrived.

Does anyone know why this could be?
Thanks,
roland

Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #1 - Posted 2011-12-28 13:20:35 »

Sounds like a bug to me. The While loop is not really doing what you think its doing. Or its taking a long time to do something.

Perhaps you could post code?

I have no special talents. I am only passionately curious.--Albert Einstein
Offline roland
« Reply #2 - Posted 2011-12-28 13:38:44 »

Here's some hopefully relevant code. I took a lot out.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
//Server thread, created when server starts
public void run()
{
   while(m_bRunning)
   {
      Process(); //includes sending packets if possible
      try{Thread.sleep(SLEEP_TIME);} catch (InterruptedException e){} //sleep time is 5ms just to not use all the cpu
      Thread.yield();
   }
   Release();
}


private void Process()
{
   if (!m_bRunning)
      return;
   
   ReceivePackets();
   
   //UDPConnectedClient contains stuff like client address and port, packets received, packet waiting to be sent, etc.
   
   for (UDPConnectedClient client: m_clients.values())
   {
      byte[] packet = client.GetReceivedPacket(); //returns the last received packet (pops off a stack of received packets that are cleared each ReceivePackets())
     
      if (packet != null)
      {
         ProcessPacket(packet,client);
         if (System.currentTimeMillis() - client.GetLastSendTime() > PACKET_INTERVAL) //can take this out for instant reply to received packet
            SendPacket(client);
      }
      else
      if (System.currentTimeMillis() - client.GetLastSendTime() > PACKET_INTERVAL) //packet interval = 1000/30
      {
         SendPacket(client);
      }
   }
   
   //other code here for checking client disconnects etc.
   ...
}

protected void ReceivePackets()
{
   if (!m_bRunning)
      return;
   
   for (UDPConnectedClient c: m_clients.values())
   {
      c.ClearReceivedPackets();
   }
   
   while(true)
   {
      try
      {
         byte[] data = new byte[PACKET_SIZE]; //1500 bytes
         
         DatagramPacket recievedPacket = new DatagramPacket(data, data.length);
         m_serverSocket.receive(recievedPacket);

         // get the client details
         InetAddress clientAddress = recievedPacket.getAddress();
         int clientPort = recievedPacket.getPort();
         UDPClientInfo info = new UDPClientInfo(clientAddress, clientPort);
         
         UDPConnectedClient client = m_clients.get(info); //find the client that matches the ip/port from a hashmap
         if (client != null)
         {
            client.AddReceivedPacket(data); //pushes the packet onto the top of the client's received packet stack.
            continue;
         }
         //Else It's a join message and process it seperately
         ProcessOtherPacket(info,data);
      }
      catch(SocketTimeoutException e) //times out after 1ms if there is no message
      {
         //THAT's OK, there just isn't any message.
         return;
         //AddDebugMessage("Timeout: "+e.getMessage());
      }
      catch (IOException e)
      {
         AddDebugMessage(e.getMessage()); //never had this occur yet
         return;
      }
     
   }
}

private void ProcessPacket(byte[] data, UDPConnectedClient client)
{
      //read the packet, add an acknowledgement of the packets sequence number to the client's next packet to be sent,
      //discard the packet if it is corrupted or the sequence number is lower than the last received packet
      //calculate ping from the ack inside the packet
      //send chat messages back to clients
      //etc...
}
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #3 - Posted 2011-12-28 13:59:28 »

Well there is some odd code there... I will start with what looks like the biggest issues first.

The ReadPackets method will never return if there are packets getting sent all the time. This is already going to create unintended behavour pattens once there is any load at all. The proper way to do this to have that method run in a different thread then use thread safe structures between the send/receive parts or the code.

The lines
1  
2  
if (System.currentTimeMillis() - client.GetLastSendTime() > PACKET_INTERVAL) //can take this out for instant reply to received packet
           SendPacket(client);

make no sense to me. why is that conditional? if you need to send something as a reply... you need to send it, why is it conditional?

A style comment, methods don't start with capitals as  a java convention. Only class names do or static fields which are typically all caps. Its a good idea to stick to conventions.

My last comment is why are you using UDP?

 

I have no special talents. I am only passionately curious.--Albert Einstein
Offline roland
« Reply #4 - Posted 2011-12-28 19:12:06 »

Thanks for the reply delt0r  Smiley

Well there is some odd code there... I will start with what looks like the biggest issues first.

The ReadPackets method will never return if there are packets getting sent all the time. This is already going to create unintended behavour pattens once there is any load at all. The proper way to do this to have that method run in a different thread then use thread safe structures between the send/receive parts or the code.

Ok, I will do that. Thanks
EDIT: what's a good structure for making sure that you aren't sending a packet in one thread at the same time as reading a packet from another thread (using the same socket)?
EDIT 2: does it matter if i use DatagramSocket.send() and DatagramSocket.receive() at the same time?


The lines
1  
2  
if (System.currentTimeMillis() - client.GetLastSendTime() > PACKET_INTERVAL) //can take this out for instant reply to received packet
           SendPacket(client);

make no sense to me. why is that conditional? if you need to send something as a reply... you need to send it, why is it conditional?
Because I want to limit the amount of packets sent to 30 per second... I will reply, and because my model allows for dropped/out of order packets it doesn't matter if i send the packet 15 ms late. If you know a better way of limiting the packet rate but still replying instantly please let me know. This is a real time game btw.


A style comment, methods don't start with capitals as  a java convention. Only class names do or static fields which are typically all caps. Its a good idea to stick to conventions.
 

Yeah, I've been programming in C++ for atleast 3 years, I'm trying to switch over...  Clueless
It also helps differentiating between my methods and other people's xD although that is a really bad excuse I know


My last comment is why are you using UDP?
 

I know you think that TCP is just as or nearly as fast as UDP. I don't agree with you there - there is a lot of information about it, I've asked people about it, seen what GOOD networked games use, and concluded that UDP is the better option. anyway, 95% of my data is unreliable, so I see no point in using TCP just for the last 5%.





Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #5 - Posted 2011-12-28 19:58:33 »

I have been working in networking for a long time. I have done the seti online thing for other projects and i have quite a bit of deployed network code of my from my commercial life  monitoring some very large teleco networks. I assure you i base my assertions on fact and experience. Seriously. UPD and TCP use IP packets on the same network. Why do you think the ones that are TCP somehow travel slower?

Also most games out there do *not* have good networking. Read their forums if you don't believe me. In fact after looking at how some behave with even a small amount of jitter and lag, many big games have very poorly implemented network layers.

UPD is only better if you don't need flow control and don't care about order and don't care about receiving the packets. Quake3 fits this very nicely. New games are starting to use TCP more and more now. ie WoW.

Also based on the code you have very little experience with networking and reading between the lines i think perhaps you have some pretty fundamental gaps in how it all works. Even if you still want to use UDP, i would recommend trying TCP as an intro into networking.

Otherwise you need to get up to speed with basic networking from a Coders perspective. For example why would you not be able to send at the same time you receive?  What does one have to do with the other? So yea, you can do both. Typically in different threads... You need to read up on how to sync threads if you need to or use thread safe data structures etc.

Also when you limit your packets... this really is not how you should do it... in fact i think you just miss sending anything in this case. Also why would you only send packets if you receive them? If there is something to send... send it. Flow control is a hard problem of course, one that TCP got wrong originally and has been refined over the years. But again having different threads makes this much easier. However if you have more to send ... then what? the que fills up till you run out of ram? Again... not as easy as it looks...

Sure you can do it, but its a lot of work, and quite advanced work at that.

I have no special talents. I am only passionately curious.--Albert Einstein
Offline roland
« Reply #6 - Posted 2011-12-28 21:28:00 »

I have been working in networking for a long time. I have done the seti online thing for other projects and i have quite a bit of deployed network code of my from my commercial life  monitoring some very large teleco networks. I assure you i base my assertions on fact and experience. Seriously. UPD and TCP use IP packets on the same network. Why do you think the ones that are TCP somehow travel slower?

Also most games out there do *not* have good networking. Read their forums if you don't believe me. In fact after looking at how some behave with even a small amount of jitter and lag, many big games have very poorly implemented network layers.

UPD is only better if you don't need flow control and don't care about order and don't care about receiving the packets. Quake3 fits this very nicely. New games are starting to use TCP more and more now. ie WoW.

Also based on the code you have very little experience with networking and reading between the lines i think perhaps you have some pretty fundamental gaps in how it all works. Even if you still want to use UDP, i would recommend trying TCP as an intro into networking.

Otherwise you need to get up to speed with basic networking from a Coders perspective. For example why would you not be able to send at the same time you receive?  What does one have to do with the other? So yea, you can do both. Typically in different threads... You need to read up on how to sync threads if you need to or use thread safe data structures etc.

Also when you limit your packets... this really is not how you should do it... in fact i think you just miss sending anything in this case. Also why would you only send packets if you receive them? If there is something to send... send it. Flow control is a hard problem of course, one that TCP got wrong originally and has been refined over the years. But again having different threads makes this much easier. However if you have more to send ... then what? the que fills up till you run out of ram? Again... not as easy as it looks...

Sure you can do it, but its a lot of work, and quite advanced work at that.

Yes, I am very new to UDP (Not UPD  Tongue), I have to learn somehow. Why would I be asking for help in the first place if my code was ultra perfect? I can't just make TCP apps all the time and expect that it will teach me how to use UDP. I agree that TCP is in most cases the best option, but when every ms counts UDP is better. I know that TCP must Acknowledge every packet, which does slow it down. The quake 3 model is faster than TCP because it doesnt care about dropped packets, it just sends the unacked data in every packet. I am using the quake 3 model, and no, I don't want to use TCP, not even if "WoW" uses it. I didn't say lots of games had good networking. I said the games I knew that had good networking used UDP.
Googling "tcp vs udp multiplayer real time game", TCP seems ok for MMORPG but for FPS games not really. I'm not afraid of doing extra work if the outcome is better.



Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #7 - Posted 2011-12-28 22:36:56 »

TCP does *not* need to wait for ACK before packets are avalible and the sender sends packets ahead of ACKs with the assumption it will receive them soon. So on a network with low packet loss, you get the data with exactly the ms delay as you do with UDP, sometimes even faster depending on the isp DSLAM settings. I have tested this quite a bit. Its quite easy to verify. These IP packets don't travel slower. UDP is faster is a mostly a myth perpetuated by the gaming industry, its the same ip packets over a the same network. And if every ms counts, you don't use a network where players are going to be having a ping of 20-200ms over the internet. UDP can't beat the ping. And network jitter over the internet can get quite bad ie you gain and loose 10s of ms all the time. You can't need something to count on every ms. 

I suggested TCP not because your errors are UDP specific but because they are quite general to network api concepts in general. I have my doubts you've done this with TCP before.

A FPS where the total player count is low is one area where UDP is a good choice. But they use a much simpler method to do things. This is basically the q3 protocol and googlling can give you some details. First the server sends the whole state of the game out at a fixed rate. ie this is just part of the game loop on the server. Then the clients just take the most recent ignoring anything it has seen before. Finally the game clients just send packets when needed of player actions, (move, point shoot). These are just send as needed. However you can rate limit if you want, this would be done with a thread that just empties the "action que" once every n ms by combining them into one packet. I would just use Thread.sleep for that. Its good enough. But this does add artificial delay. 

Note that this protocol on its own does not give you ping times.... Since there is never a response that is caused by receiving a packet. I do believe in quake this was done with special "heartbeat" packets.
 

I have no special talents. I am only passionately curious.--Albert Einstein
Offline roland
« Reply #8 - Posted 2011-12-29 08:01:13 »

So I could send full packets at fixed intervals of 30 ms or whatever, but whenever i receive a packet i could instantly send an acknowledgement for that packet?
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #9 - Posted 2011-12-29 10:47:09 »

Why do you need to send an acknowledgment? If that packet didn't get through, you send another one in 30ms anyway right?

I have no special talents. I am only passionately curious.--Albert Einstein
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline roland
« Reply #10 - Posted 2011-12-29 23:09:24 »

yes
Offline Braddas
« Reply #11 - Posted 2012-01-20 16:54:12 »

If you don't mind me asking delt0r, are you suggesting that Roland use TCP due to lack of experience, or because you think it's a geniunely viable option for real-time mutiplayer gaming? I've been looking into this myself recently and there is a lot of conflicting advice, though the majority say that UDP is more suitable. That said, many comments from people with real networking experience (though not necessarily within games) state that TCP isn't nearly as flawed as is made out.

I recently integrated a TCP solution into my game and with a bit of tweaking it's fine apart from the odd 'hang', which I assume is either a packet that has been delayed/dropped or TCP 'backing off' because of network load. I've been lead to believe that these hangs don't occur with UDP because it doesn't need to guarantee packet delivery - but as far as I know that just applies to sending packets, not receiving them. If TCP packets aren't getting through, could I expect the same delays with UDP? I basically need to be able to receive at least 1 packet per second or the game really suffers.
Offline sproingie

JGO Kernel


Medals: 202



« Reply #12 - Posted 2012-01-20 17:37:48 »

If you need the packets, you need the packets.  If you have to time out for the UDP packet, you're reimplementing TCP badly.  If the network is so congested as to start interfering with TCP, UDP is going do do even worse.
Offline Braddas
« Reply #13 - Posted 2012-01-20 18:19:13 »

If the network is so congested as to start interfering with TCP, UDP is going do do even worse.

Seems so obvious now that you've said it. I'll see if I can improve my implementation, at the very least I can probably reduce the amount of packets I'm sending.
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #14 - Posted 2012-01-20 19:06:55 »

I never mind anyone asking Cheesy

I was saying several different things here. First i was suggesting TCP because it a little bit easier to learn the api IMO. Simply because it behaves just like a stream/pipe/file.

Next i am saying that the vast majority of games network code is written by people who are *not* network people but game coders. So they do what other game coders did. Pretty common problem, but almost always the wrong way to make the decision.

The dogma on the internet out there with TCP==slow is the same as the dogma that java is slow. Sure there are slow java apps, there are also really slow and mem hogging C apps out there... But C is never blamed... Same with UDP... if a game has bad networking, the decision to use UDP is never blamed... perhaps it should be.

For the vast majority of people starting with networking, TCP is the right choice. Switching to UDP if it makes sense is pretty easy. Making UDP behave as TCP is not. It took a planet full of expert network engineers to get TCP as good as it currently is. There was even total network collapse while they where figuring it out (yes in the old days the internet crashed!). It is still a very active area of research. Both linux and windows have updated their flow control algorithms in the last few years.

I assure you, if you have not heard of the 2 Generals problem, don't know what flow control is or why you need it, don't know about MTU and IP packet fragmentation, and/or need packets somewhat reliably delivered. Use TCP! Don't think that because the crap protocol you came up with works well on a lan it will work on the Internets... the tubes can get clogged ya know.

The exception is outlined above...If you can keep the packet at the standard MTU of about 1500 bytes IIRC. [edit] That is including headers, so payload is smaller.

I could go into more detail. But perhaps that is something for its own thread.

I have no special talents. I am only passionately curious.--Albert Einstein
Offline Braddas
« Reply #15 - Posted 2012-01-20 20:30:06 »

Thanks for the input, I'm pretty new to networking in general so it sounds like TCP is my best bet for now. I guess in a way I was hoping UDP was some sort of magic bullet with regards to latency, but the more I read the deeper the rabbit hole gets. It's looking more and more as though the issues I'm experiencing are due to my implementation anyway, although it's a real time game it's not particularly fast-paced and I'm pretty sure TCP is the right choice for me.

Thanks again.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

TehJavaDev (31 views)
2014-10-27 03:28:38

TehJavaDev (26 views)
2014-10-27 03:27:51

DarkCart (40 views)
2014-10-26 19:37:11

Luminem (21 views)
2014-10-26 10:17:50

Luminem (26 views)
2014-10-26 10:14:04

theagentd (32 views)
2014-10-25 15:46:29

Longarmx (61 views)
2014-10-17 03:59:02

Norakomi (57 views)
2014-10-16 15:22:06

Norakomi (46 views)
2014-10-16 15:20:20

lcass (43 views)
2014-10-15 16:18:58
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!