• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Ron McLeod
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

Java Object Server-Client Relay

 
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I wrote the vast majority of this code from scratch, this is actually only my third java program... Crossing over from JS/PHP/C has been interesting.

I'm getting an error on line 95 in the client... the "login" function works but I can't relay messages for some reason. I've been changing around things for three hours and finally decided to create an account here (awesome forum by the way, you guys and stackexchange pretty much taught me how to program).

Objects are shared in the class file Packet.java to prevent a (server.Client.objx can not turn into server.Server.objx) error that tripped me up for a good bit of time...

Error Code:

java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1361)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
>>> at server.Client.run(Client.java:95)
at java.lang.Thread.run(Thread.java:744)

My objects that are relayed...

Packet.java



Here is my server code, I've debugged it moderately (for my skill level) well IMHO.

Server.java


And finally the client;

Client.java


Also using a Byte converter which I found online, this is not my code, everything else, above, is however.

 
Bartender
Posts: 15743
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Trapper, welcome to CodeRanch!

You might start by using Java code conventions. Please try to put different top-level classes in different source files, and capitalize the first letter of class names. This will make it much easier to find class definitions, and also to recognize that an identifier refers to a type, rather than a method name or variable. You should also use sensible package structuring. Don't bundle classes carrier and message in a source file called Packet. Put classes called Carrier and Message in separate source files.

You are also using a lot of package private fields. You should make fields as private and final as possible. A class called Message should hold a private and final field called message.

Your classes use very non-descriptive field names. I get that oisu stands for ObjectInputStream (not sure what the u stands for though), but it tells me nothing what you're going to do with that stream.

Actually a large problem with the code is that it's not clear what the purpose of much of it is. What's your code supposed to do in the first place? It will help others, and yourself, if you put separate classes in separate files, and clearly document what the responsibilities of those classes and their methods are. You'll sometimes find that you actually don't have a clear idea what one particular class is supposed to do, and that's often a sign it needs to be split up, or disappear.
 
Stephan van Hulst
Bartender
Posts: 15743
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Another thing, you're not using the exception mechanism as you should. It seems exceptions are just an annoyance to you that you want to ignore and go on with your program. Consider however what happens when your line serverSocket = new ServerSocket(portNumber); throws an exception. You simply catch the exception and proceed to say "Server has started.". I think you can hardly say a server has started if it can't accept incoming connections.
 
Trapper Thompson
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Hi Trapper, welcome to CodeRanch!

You might start by using Java code conventions. Please try to put different top-level classes in different source files, and capitalize the first letter of class names. This will make it much easier to find class definitions, and also to recognize that an identifier refers to a type, rather than a method name or variable. You should also use sensible package structuring. Don't bundle classes carrier and message in a source file called Packet. Put classes called Carrier and Message in separate source files.



Ok I did this, any adapted the rest of the code but I'm getting fatal compilation errors now...

Stephan van Hulst wrote:
You are also using a lot of package private fields. You should make fields as private and final as possible. A class called Message should hold a private and final field called message.



When you say field do mean function? Or like String/byte[]/int variable?

I tried to make everything as private and final as possible, but I don't necessarily understand the implications that this has on the program... I know private classes (and functions) can only be accessed by the classes they're contained in; but does this look right to you?

Message.java


I also modified my error handling (yes I did see it as a nuisance at first :P)...

Here is a bit of my server code, does this look programmatically correct to you?



I'm still debugging the server to accommodate the class file changes, I might just start from scratch... I should probably pick up a book (or ebook) on java and actually learn the language in a "proper" manner.

Thank you so much for your help and time Stephan, it means a lot as I'm just getting started .
 
Trapper Thompson
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think I fixed the error on line 95 on the client... I was reading from the object stream continuously without checking whether or not I was actually receiving "Carriers"

I made this addition to the client.


it works!!! Success!
I was reading a buffered line of input to determine its existence and then reading a blank line.


Now I just need to integrate some elliptical curve cryptography and I'll be happy...
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Trapper Thompson wrote:I made this addition to the client.


Seems rather verbose. What about:and you could get rid of the try...catch altogether by simply having the method throw whatever Exception(s) readObject() throws.

HIH

Winston
 
Trapper Thompson
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:

Trapper Thompson wrote:I made this addition to the client.


Seems rather verbose. What about:and you could get rid of the try...catch altogether by simply having the method throw whatever Exception(s) readObject() throws.

HIH

Winston



Hi Winston, thanks for the suggestion! I'll try it out and see what happens.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Trapper Thompson wrote:Hi Winston, thanks for the suggestion! I'll try it out and see what happens.


OK. However, the main thing is to understand why it works, not just parrot it.

Good luck.

Winston
 
Trapper Thompson
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:

Trapper Thompson wrote:Hi Winston, thanks for the suggestion! I'll try it out and see what happens.


OK. However, the main thing is to understand why it works, not just parrot it.

Good luck.

Winston



Thanks, I do indeed wish to learn java to the fullest extent possible ... I stuck with my original code because it was easier to modify :P, from a newcomer's perspective at least. However, now I keep getting null pointer exception errors right after the first object is relayed, successfully...

Here is my server code...
Server.java


Client.java


I can send one message successfully but then I get:

Exception in thread "Thread-0" java.lang.NullPointerException
at server.clientThread.run(Server.java:144)

I've moved everything around several times and nothing seems to work :/... How long does it take to become fluent in java? I started as a hobbyist two weeks ago and the learning curve from something like PHP has been steep.
 
Stephan van Hulst
Bartender
Posts: 15743
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Your run() method is almost 70 lines long, with lots of nested statements. It's no wonder you're getting exceptions that are hard to debug.

Make smaller methods, that perform smaller tasks.

You should really think about what a method is supposed to do, and not just patch code around until it looks like it works. Your exception handling looks very painful. Don't worry though, Java is difficult, and it takes a long time to figure out the general concepts.

Here's a very simple and generic server I wrote. It may overwhelm you at first, but it introduces a lot of concepts you may find useful. Use it as inspiration to write your own code (please don't copy it without understanding it):- My server uses ClientHandler to deal with incoming connections. When it accepts a connection, it passes the socket to a ClientHandler, which knows how to communicate with the Client. This way, you can use the same Server code for different applications.

- Since you want the server to go back to listening for more incoming connections as soon as possible, you handle clients in separate threads. However, you shouldn't work with raw threads. Instead, Java provides ExecutorService which manages threads for you. So my server requires an ExecutorService which it can pass jobs to (handling the clients), and then go back to its own job. You should think of an ExecutorService as a pool of threads that sit around doing nothing until you have another task for them.

- Server's constructor sets up the socket to listen for incoming connections, and initializes the client handler and the executor service. If it's not able to set up the socket, it just throws an IOException. There's no point in dealing with the exception within the constructor. If it fails, it fails.

- After creating a new server, it doesn't start listening immediately. You should do this in a separate method, because the act of listening is *not* required to create a server. Think about what a constructor is conceptually supposed to do. It only creates an object, it shouldn't perform other tasks.

- The server listens only once. After you close the server, it's done. Create a new server to start listening again. The started field keeps track of whether the server was already started once. The closed field makes sure that the server stops listening when another thread signals that the server should close. These fields are volatile, because they are updated and read from different threads, and not synchronized using the object monitor. If this went over your head, read up on Java's synchronization mechanism.

- When the server accepts a new connection, it tells the executor: "Try to handle the socket. If an exception occurs, don't deal with that exception just yet. Finally, try to close the socket. If an exception occurs while closing the socket, log that exception". It does this by passing the executor a an anonymous subclass of Callable. The call() method throws an exception if the handler fails. The reason we deal with the exception if closing the socket fails, is because you may *never* throw an exception from the finally-clause. The finally-clause should always terminate normally.

- At the end of the listen() method, we catch SocketException, and log it as an info message. The reason is that when we close the server, and the listening thread is blocked at the accept() method, it will throw a SocketException before exiting the loop. This is expected and normal behavior. We know it will happen and we thought about it.

So how do you use this server? Here's an example:What's happening here? I create the handler that will interact with all the clients, HANDLER. The pool of threads that will deal with all the various tasks is EXECUTOR. I create a new Server, and have a separate thread listen to incoming connections. The main thread waits for 10 seconds, automatically closes the server (using try-with-resource), and finally shuts down the executor. After the server has closed, and the executor has shut down, the program doesn't abruptly stop. The server simply doesn't accept new connections any longer, the executor won't perform any new tasks, but any threads that are already handling clients will keep on running normally until they are finished.

Note that I also use try-with-resources to declare the streams in and out. These will automatically be closed when the try-clause is done. I don't declare the ObjectInputStream and ObjectOutputStream as auto-closeable resources, because this will cause a subtle problem that may trigger deadlock.
 
Trapper Thompson
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Here's a very simple and generic server I wrote...


Thank you for the detailed explanation and example. I was definitely overwhelmed at first but I'm guessing I'll eventually figure it all out.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Trapper Thompson wrote:Thank you for the detailed explanation and example. I was definitely overwhelmed at first but I'm guessing I'll eventually figure it all out.


Trapper,

1. You don't need to include the entire original quote when you reply - especially if it's huge. Just include enough to make it obvious what you're replying to.
I've edited your last post as an example.

2. Part of the art of programming (and what Stephan was trying to illustrate) is breaking things down into tasks, and putting those tasks into methods; but in order to do that you need to think before you code.

A 70-line run() method says to us that you were probably just coding like a stream of consciousness, simply adding things as they occurred to you (or as they cropped up), and that's a bad habit to get into. It may work while you're in the early stages of learning and problems are reasonably simple but, as a technique, it doesn't scale well (as I suspect you're starting to discover).
You may find the StopCoding (←click→) and WhatNotHow pages worth reading on this subject.

Another tip: Another part of the "art" is making your code as readable as possible. For one thing, it allows us to help you more easily; and it'll also help YOU if you ever need to come back to a program after a few months. And one thing you could do on that score is to provide names for your Carrier "types", either in the form of public constants,
viz:
public static final int TYPE_TWO = 2; // the 'final' is VERY important
(obviously, you should choose something more descriptive than 'TYPE_TWO')

Or in the form of an enum (probably much better).

HIH

Winston

PS: Your code lines are much too long, which makes your thread very hard to read.
I'd break them up myself, but you have tons of them, so I suggest you read the link and edit your original post accordingly. Thanks.
 
Trapper Thompson
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sorry for the quotes, it is considered the norm at another forum from which I came.

The stream of consciousness coding vs. pre planned coding issue is something I'm trying to remedy, however I don't quite know yet how to transfer my thoughts into java code :/. I guess time and practice will help.

Thank you for your time and advice, I will take it to heart,

Trapper
 
I knew that guy would be trouble! Thanks tiny ad!
Clean our rivers and oceans from home
https://www.kickstarter.com/projects/paulwheaton/willow-feeders
reply
    Bookmark Topic Watch Topic
  • New Topic