Java-Gaming.org    
Featured games (78)
games approved by the League of Dukes
Games in Showcase (426)
Games in Android Showcase (89)
games submitted by our members
Games in WIP (466)
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  
  When do Sockets block?  (Read 899 times)
0 Members and 1 Guest are viewing this topic.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Posted 2010-09-04 02:24:50 »

Hey all,

One massive hole in my knowledge is networking. I decided I wanted to make a simple game networking library to insert into the rest of my personal game library, so I was messing around with making a simple chat program that sits on top of this framework.

For now, I'm just giving every client their own Thread. No crazy smart stuff is happening yet.

One issue I'm seeing is that just creating the ObjectOutputStream seems to be blocking the Thread.

Basically, when the connection is first established, I am doing this:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
try
{
   in = new ObjectInputStream(connection.getInputStream());
   out = new ObjectOutputStream(connection.getOutputStream());
   out.flush();
}
catch (Exception e)
{
   System.err.println("Error creating streams to connection.");
   e.printStackTrace();
   isConnected = false;
   return;
}


Along with some other junk. The interesting thing is that the Thread seems to be blocking just from calling connection.getInputStream() (connection is a Socket). I was hoping I could just store the streams and then use them for subsequent operations. Is it actually necessary for me to create a new stream every time I want to send/read data? I looked at a game I made a long while ago while I was at school and it was actually doing this. Seems wasteful.

These streams are being created as the result of a ServerSocket.accept() call.

See my work:
OTC Software
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #1 - Posted 2010-09-04 02:28:57 »

I found this finally.

1  
The ObjectInputStream constructor blocks until it completes reading the serialization stream header. Code which waits for an ObjectInputStream to be constructed before creating the corresponding ObjectOutputStream for that stream will deadlock, since the ObjectInputStream constructor will block until a header is written to the stream, and the header will not be written to the stream until the ObjectOutputStream constructor executes. This problem can be resolved by creating the ObjectOutputStream before the ObjectInputStream, or otherwise removing the timing dependency between completion of ObjectInputStream construction and the creation of the ObjectOutputStream.


I was making the ObjectOutputStream second. Amusing.

See my work:
OTC Software
Offline Riven
Showcase Moderator

JGO Overlord


Medals: 612
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2010-09-04 12:10:02 »

Always wrap your socket streams in buffered streams, otherwise you are very likely to end up with a handful of bytes in each tcp-packet, which is hugely inefficient.

When you're new to networking, it is a good idea to keep things simple. Just like you should write your first program in notepad instead of an IDE, you should write your first networking code using DataInputStream/DataOutputStream instead of ObjectInputStream/ObjectOutputStream. The latter has it's quirks, while the first is fully transparant about what it does.

As always: start simple, don't try to add multiplayer into an existing game. Try to write a CLI chatroom, post the result and let us join your 'channel'. Once you are confident that the basics work... it's time to write some abstraction-layers on top of your network-code, so you don't have to deal with the raw bytes everytime.

Note: a chatroom is 'hard enough' to get right. People will login, leave, disconnect, timeout. It's all multithreaded, so you'll have to do some synchronization (which IIRC is/was also rather new territory for you). You can't get away with the classic request/response architecture, because you can write messages at any moment, and read messages at any moment. The first implementation would probably have 1 thread per stream (as opposed to one thread per connection). Once that works (reliably), try to change the protocol into request/response, where you poll the server for updates. Note that this doesn't makes much sense technically, but it's all about experience for later apps.

So *please* try to start simple, it will save you hours upon hours. You'll actually understand what's happening, as opposed to hoping it will work.

Oh, and never even look at NIO for the next two or so years: it will probably turn your hair grey and you'll pull the remaining hairs out. One by one. You'll love the feeling of being alive.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #3 - Posted 2010-09-07 18:21:34 »

Yup, not bothering with NIO at this point.

Also, even though I haven't coded much networking stuff before, I have a pretty good understanding of how it works, at least.

I got the chat client working via multi-threading. The server has a thread to listen for new connections, a thread for each connected client, and a thread to kill client connections that haven't sent anything in a certain time interval (currently a minute). I've got a lot of methods in here that appropriately synchronized, and have had no concurrency issues so far (with my limited testing). It's quite wasteful in the number of threads I have, but in 99% of my personal cases this will be no big deal.

The client has one thread that listens for data, and one thread that constantly sends out heartbeat data (basically an empty object gets sent to the server every interval, currently 10 seconds). I'm aware that the latter thread could easily be coded into the game loop, but I decided I just wanted to keep things simple and clean - I shouldn't need to bother with heartbeats or anything in any games or programs that implement this "framework."

I've also implemented separate hooks for the following situations:
- A client disconnects manually
- A client times out and so is disconnected
- The server shuts down on purpose
- The server shuts down unexpectedly
- A new client has connected
- The server checks that everything is legal before it sends it back to clients

As far as I've been able to tell given my limited testing, all the functionality works when the framework is implemented into the chat client.

I then started do a very very simple networked game - basically each player controls one Entity (which is just a drawn oval), their keyboard input is sent to the server, and the server then sends back any entities that have been updated. I almost had this done then realized that I was implementing it stupidly (I was allowing the client to do a lot of stuff which would allow hackers to run rampant) so I scrapped it and started again.

Once I've got that solid, I'll slowly add a few features to it and make it some sort of very simple game. Then I'll post that up here and we can try to break it.

From there, I'll start implementing it into actual projects. Overall I'm not worried, because although I haven't spent much time doing networking myself I'm frequently exposed to clean, working, code.

The one complication with my game implementation (input is sent to the server, the server sends back new positions) is that in very laggy circumstances this will get very annoying. I've played games that do it this way and it is very very far from acceptable. I've been cooking up hybrid approaches, like allowing movement to be pretty much free reign to a certain point (client controls movement and sends updates to server unless the delta is too large) but all important actions like attacking and such must be verified by the server first. But then, of course, depending on the type of game it is, there can end up being large deltas between what the client sees and what the server sees.

So, in summary, I'm only worried about figuring out how to deal with latency at this point - the actual implementation is simple enough for now that I'm fine.

See my work:
OTC Software
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.

xsi3rr4x (75 views)
2014-04-15 18:08:23

BurntPizza (68 views)
2014-04-15 03:46:01

UprightPath (80 views)
2014-04-14 17:39:50

UprightPath (65 views)
2014-04-14 17:35:47

Porlus (81 views)
2014-04-14 15:48:38

tom_mai78101 (105 views)
2014-04-10 04:04:31

BurntPizza (165 views)
2014-04-08 23:06:04

tom_mai78101 (261 views)
2014-04-05 13:34:39

trollwarrior1 (210 views)
2014-04-04 12:06:45

CJLetsGame (220 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
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!