I'm writing a server/client program. The client sends "Request"s (which are objects designed for this purpose) to the server and server decodes them using an ObjectInputStream. All the "Request" objects are of the same class and just differ in data fields.
Everything usually works; but in some particular states (maybe when the Request object is a bit larger, not however more than 200 kb!) the readObject() on the serverside just blocks with no exception.
Any idea?!
The server code:
public class ConnectionThread extends Thread {
Socket con;
Request request;
public ConnectionThread(Socket s) {
con = s;
try {
ObjectInputStream in = new ObjectInputStream(con.getInputStream());
// Works till here; the object "in" is initialized.
request = (Request) in.readObject();
// This line is not reached, in particular cases.
} catch (ClassNotFoundException ex) {
Logger.getLogger(ConnectionThread.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ConnectionThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
...
}
The client code:
public static void saveStoreDataForTable(DataTable tb) {
try {
Socket s = new Socket("localhost", portNo);
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
out.writeObject(new Request("saveStoreData",
new Object[]
{tb.getEdited(), tb.getRemoved(), tb.getNewTables(), tb.getAlterations()}));
out.flush();
// These lines work. But I can't get servers respone; again, in some particular cases.
...
}
You should move that I/O from the constructor to the start() method. At the moment you're doing the I/O in the thread that constructs this thread, which is almost certsinly the wrong thread.
Related
I want to integrate a server with multiple clients for a blackjack game I created, and thus I began practicing with servers in java. I create a thread, that when ran, forces the server to listen for input and produce an output. Then I added a feature to stop the server. However, the server randomly produces the correct output, and sometimes fails to connect. Here is the code for when the user hosts a server:
st = new ServerThread(); //this is a field of type ServerThread
st.start(); //this runs the server concurrently as a new thread
Here is the code for when they close a server:
st.stopThread();
Finally, here is the source for the serverThread:
public class ServerThread extends Thread {
private volatile boolean isRunning = true;
private Socket socket;
private static final int PORTNUM = 1342;
#Override
public void run() {
while (isRunning) { //should run only when the
try {
ServerSocket serverSocket = new ServerSocket(PORTNUM); //uses the same port number, which I made a constant
//Reading the an object of type Information from the client
socket = serverSocket.accept();
ObjectInputStream serverInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream serverOutputStream = new ObjectOutputStream(socket.getOutputStream());
Information i = (Information) serverInputStream.readObject();
//arbitrarily changes the data stored in the information object to verify connection with server
i.setI(100);
i.setS("new string");
i.setD(4.4);
//sends the modified object back to the client
serverOutputStream.writeObject(i);
serverInputStream.close();
serverOutputStream.close();
socket.close();
} catch (IOException e) {
//System.out.println("IOException");
//e.printStackTrace();
} catch (ClassNotFoundException e) {
//System.out.println("ClassNotFoundException");
//e.printStackTrace();
} finally {
try {
if (socket != null) { //avoid null pointer if no connections have been established
socket.close();
}
} catch (IOException ex) {
//Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public void stopThread() {
isRunning = false;
}
}
Any suggestions on edits to make my code perform correctly and consistently would be welcome. Thanks.
I would move the socket definition away from being an instance variable i.e,
while (isRunning) {
Socket socket = null;
try {
...
I am currently learning networking, specifically client-server classes.
I have done much research and implemented various test programs but I can't figure out why/when one would need to use the flush() method.
How can there be data mistakenly left in the output stream if it is always read in by the input stream? As dictated by the client-server code.
I tried to test my basic echo client server program by omitting the flush() but I could not break it.
When testing the flush() by writing twice from the client side and only reading once for the server's reply all that happened was a backlog (I assume the stream acts like a queue?) in the server's replies.
Then I took the same code and added flush() before and after the second write and it made no difference. It's as if the flush() doesn't actually clear the stream.
So can someone please explain in what scenario with regards to client/server stream interactions would flush() be required?
Server:
public class ServerApp
{
private ServerSocket listener;
private Socket clientCon;
public ServerApp()
{
try
{
listener = new ServerSocket(1234, 10);
} catch (IOException e)
{
e.printStackTrace();
}
}
public void listen()
{
try
{
System.out.println("Server is listening!");
clientCon = listener.accept();
System.out.println("Server: Connection made with Client");
processClient();
} catch (IOException e)
{
e.printStackTrace();
}
}
public void processClient()
{
try(ObjectOutputStream out = new ObjectOutputStream(clientCon.getOutputStream()); ObjectInputStream in = new ObjectInputStream(clientCon.getInputStream()))
{
String msg;
while(!(msg = (String)in.readObject()).equalsIgnoreCase("Shutdown"))
{
out.writeObject("Server: " + msg);
out.flush();
}
out.writeObject("Server is powering down...");
out.close();
in.close();
} catch (IOException | ClassNotFoundException e)
{
e.printStackTrace();
}
}
public static void main (String args[])
{
ServerApp sa = new ServerApp();
sa.listen();
}
}
Client:
public class ClientApp
{
private Socket serverCon;
public ClientApp()
{
try
{
serverCon = new Socket("127.0.0.1", 1234);
} catch (IOException e)
{
e.printStackTrace();
}
}
public void communicate()
{
try (ObjectOutputStream out = new ObjectOutputStream(serverCon.getOutputStream()); ObjectInputStream in = new ObjectInputStream(serverCon.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)))
{
String response = null;
do
{
System.out.println("Enter your message for server: ");
out.writeObject(br.readLine());
out.flush();
out.writeObject("Flush not working");
out.flush();
response = (String) in.readObject();
System.out.println(response);
response = (String) in.readObject();
System.out.println(response);
} while (!response.equalsIgnoreCase("Server is powering down..."));
} catch (IOException | ClassNotFoundException e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
ClientApp ca = new ClientApp();
ca.communicate();
}
}
The method flush() is used to flush out any internal buffers that may be in use. For example using a BufferedOutputStream the contents are written in chunks to improve performance (it's slower to write each byte as they come).
Depending on usage, you might never have to call flush(). However let's say you send a small String (converted to byte[]) and it fits nicely in the internal buffer. The contents of the buffer won't be sent until the buffer is full or flush() is called.
Now let's say you're writing over the network, and you expect the other side to answer something to your small String. Since it's still in the buffer, the other side won't receive it and it can result in both sides waiting forever.
Object streams are another beast, and I'm a little disappointed that so many beginners are using them. There should be a warning in the class saying "Objects may be more difficult to send/receive than they appear".
ObjectOutputStream delegates the flush() call to its internal BlockDataOutputStream which has 3 buffers sized 1024, 5 and 256 for "blockdata", header data and characters respectively.
Try it with new ObjectOutputStream(new BufferedOutputStream(clientCon.getOutputStream())) and you'll see a difference with and without flush(). It causes flushing of the underlying buffered output stream. Without a buffered stream there is no buffer to flush so it does nothing.
I am programming a external Taskmanager and i need to send the process list via tcp to my server application. But i don't know how to start and how this works.
Edit:
I have the processlist i only have to send it via TCP to the Serverside.
Thx for your help.
If you already have a processlist, then it's not so hard to make client-server logic for your purposes with Java. First of all, you need to make a server side:
public class ServerSide {
public static void main(String[] args) {
try
{
ServerSocket myServerSocket = new ServerSocket(9999);
Socket skt = myServerSocket.accept();
List<Process> objects = null;
try {
ObjectInputStream objectInput = new ObjectInputStream(skt.getInputStream());
try {
Object object = objectInput.readObject();
objects = (ArrayList<Process>) object;
System.out.println(objects);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Wich will use a ServerSocket to listen on specified port, in this case is 9999. Then connection accepted (take a look at myServerSocket.accept(), it stops the execution, until any connection is accepted), it creates a Socket and you can get it's InputStream and get an object from it. In this example server stops after first accepted connection, you should make it accept any number of connections with infinity loop for example.
When you have a server, you can make a client side, which will send a list of Processes to the Server:
public class ClientSide {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1",9999);
ArrayList<Process> my = new ArrayList<Process>();
my.add(new Process("Test1"));
my.add(new Process("Test2"));
try
{
ObjectOutputStream objectOutput = new ObjectOutputStream(socket.getOutputStream());
objectOutput.writeObject(my);
}
catch (IOException e)
{
e.printStackTrace();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In this case, you'll create a Socket by youself, give an eddress and port number to it, where it will send a data. Then you can get an OutputStream and pass your data through it. In example above, you pass an Array of Process object instances. The Process class looks like:
public class Process implements Serializable {
private String processName = null;
public Process(String processName) {
this.processName = processName;
}
#Override
public String toString() {
return processName;
}
}
The main thing in case of Process class, it should implement the Serializable interface. In that case, you don't need to make some logic for it's serialization.
But if you have to make a client with Java, but not a server, then it could be a little bit harder. You may take a look here, to see some kind of example, how Java-client communicates with C++ server. Anyway, in Java-part you should use a Socket and it's OutputStream, only the data representation will differ.
I have two apps that work in conjunction with one another. One is a "server" type app that does not have any GUI interface and handles queries to a database and processes requests from a client. The other is a "client" that is primarily a GUI and is for users to interact with database information in a structured manner.
ISSUE / TROUBLE / HELP NEEDED WITH
The problem that I am having is that I can send one Object (a String[]) to the server successfully and with no problems. Client app sends it, Server app receives it an processes it successfully.
If I try and send a second String[], the the client compiles the array and thinks it gets sent, but the server never receives is (gets only null) and produces a IOException.
This is even with Arrays that contain the exact same number of positions and the exact same text in the exact same format and positions.
The error produced by the printStackTrace() is:
Java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1367)
at java.io.ObjectInputStream.readObject (ObjectInputStream.java:369)
at server.ConnectionThread.processClientRequests(ConnectionThread:204)
at server.ConnectionThread.processClientRequests(ConnectionThread:50)
at javalang.Thread.run(Thread.java:722)
The code at line 204 that is the point where the ObjectStream is being read from:
String[] addArray = (String[]) ois.readObject();
ois is an ObjectInputStream and is initialized as follows:
private ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
CLIENT CODE
The client code used to send these objects TO the server app is:
ObjectToServer.writeObject(String[] var);
ObjectToServer.flush();
ObjectToServer.reset();
COMMENTS
What does NOT make sense to me is that this exact same code format is used to successfully send a number of String[] over the objectOutputStream from the SERVER to the CLIENT app without ever sending a "null"
I have Google searched this and all to absolute no avail.
Someone please help if you can!!
ADDITIONAL CODE
// CONNECTION THREAD IS ON SERVER APP, SETS UP STREAMS AND WAITS FOR MESSAGES FROM CLIENT
// HANDLES COMMUNICATION FROM CLIENT AND REST OF SERVER
public class ConnectionThread implements Runnable
{
private Socket socket;
private SystemCore core;
//Streams for connections
private InputStream is;
private OutputStream os;
//Writers and readers for communication of Strings
private PrintWriter toClient;
private BufferedReader fromClient;
// Writers and readers for sending and receiving Objects between server and client.
private ObjectInputStream ois = null;
private ObjectOutputStream oos = null;
//Protocol
static final String CLIENT_QUITTING = "Exit";
public ConnectionThread(Socket s, SystemCore aSysCore)
{
socket = s;
// State of the SystemCore as taken from HelloServer
core = aSysCore;
}
public void run()
{
try
{
openStreams();
toClient.println(MESSAGE_TO_CLIENT);
processClientRequests();
closeStreams();
this.socket.close();
}
catch (OptionalDataException ode )
{
System.out.println("OptionalDataException: ");
System.out.println("length is: " + ode.length);
}
catch (IOException ioe)
{
System.out.println("IO trouble with a connection in ConnectionThread run() " + ioe.getMessage());
ioe.printStackTrace();
}
catch (ClassNotFoundException cnf)
{
System.out.println("Class trouble with a connection in ConnectionThread run() " + cnf.getMessage());
cnf.printStackTrace();
}
catch(ParseException pe)
{
System.out.println("Parse trouble with a connection in ConnectionThread run() " + pe.getMessage());
pe.printStackTrace();
}
}
/**
* Opens streams between the server and the client.
*
* #throws IOException
*/
private void openStreams() throws IOException
{
final boolean AUTO_FLUSH = true;
this.is = this.socket.getInputStream();
this.fromClient = new BufferedReader(new InputStreamReader(is));
this.os = this.socket.getOutputStream();
this.toClient = new PrintWriter(os, AUTO_FLUSH);
//Object streams.
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
System.out.println("...Streams set up");
}
/**
* Private method that accepts arguments from a client and executes the related
* commands in the systemcore as long as the command passed from the client
* is not CLIENT_QUITTING.
*
* #throws IOException
* #throws ClassNotFoundException
*/
private void processClientRequests() throws IOException, ClassNotFoundException, ParseException
{
String commandFromClient;
commandFromClient = fromClient.readLine();
while (!(commandFromClient.equals(CLIENT_QUITTING)))
{
if (commandFromClient.equals("addProjectPrepare"))
{
String[] addArray = (String[]) ois.readObject();
core.addProjectPrepare(addArray);
}
if (commandFromClient.equals("editProjectPrepareDetails"))
{
String[] editArray = (String[]) ois.readObject();
recruit.editProjectPrepareDetails(editArray);
}
}
commandFromClient = fromClient.readLine();
}
**// CLIENT SIDE (User GUI) CODE THAT SENDS STRING[] TO THE SERVER**
public void saveAction()
{
// TEST TO SEE IF THE DATE ENTERED IS CORRECT FORMAT, IF NOT NO SAVE OCCURRS
boolean parsedOk = false;
if (this.arrivalDateTextField.getText().isEmpty() == false)
{
try
{
// Check if date is correct format. Nothing will be done with
// the testDate object
MyDate testDate = new MyDate(
this.arrivalDateTextField.getText());
//Allow write to server to occur.
parsedOk = true;
//If date is okay, send form data to server.
}
catch (ParseException pe)
{
this.arrivalDateTextField.setText(""); // Set text field to blank
int messageIcon = javax.swing.JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(this, "Invalid date",
"Warning", messageIcon);
}
}
else
{
parsedOk = true; // No date entered so allow blank.
}
if (parsedOk == true)
{
// WRITE DATA TO SERVER OCCURS HERE:
try
{
**//getPersonDetails() returns a String[]**
ManageClientConnections.toServer.println("addNewData");
ManageClientConnections.objectToServer.writeObject(this.getPersonDetails());
ManageClientConnections.objectToServer.flush();
ManageClientConnections.objectToServer.reset();
}
catch (IOException ioe)
{
System.out.println(
"While writing new person to server, there was an error: " + ioe.getMessage());
}
// And dispose of the GUI, inside the parseok if clause
this.dispose();
}
}
You can't create multiple input/output streams over the same socket input/output streams. that doesn't work. you need to pick one type of stream and stick with it. Since you need to send structured data, you should use only the Object streams and ditch the Print streams. if you need to send different types of messages from client to server, then you should consider using a wrapping Serializable object type (e.g. Message) which can contain different types of messages.
So the end result of my program is an updating game client, but what i have so far is a server that is able to accept multiple connections, and a client that connects to the server. this is the code for the client portion:
public void client() {
Socket socket = null;
ObjectInputStream in = null;
ObjectOutputStream out = null;
try {
socket = new Socket(IP, Integer.parseInt(port));
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
do {
// have a conversation
try {
message = (String) in.readObject();
System.out.println("\n" + message);
} catch (Exception e) {
System.out.println("\n idk wtf that user sent!");
}
} while (!message.equals("CLIENT - END")); // When the user types "END"
System.err.println("CLOSED!!!");
System.exit(0);
}
and this is the code for the server portion:
public void run() {
// where everything happens
System.out.println("server- connected");
try {
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject("hi");
out.flush();
Thread.sleep(5000);
out.writeObject("close");
out.flush();
System.out.println("closed");
} catch (Exception e) {
e.printStackTrace();
}
}
now, i am running into this problem where, when my server sends the object "hi" the client appears to not receive it. i'm not totally sure if it does, but if it is getting it, it isnt printing it out like i wanted. i previously have made a chat program that does this same thing, and i pretty much copied it to this, but it isnt communicating. the most i get is the confirmation that they are connected. im not sure what is going on, but any help would be appreciated! thanks in advance!
create the ObjectOutputStreams before the ObjectInputStreams and flush them immediately after creation.
the constructor of an ObjectInputStream reads the stream header. this stream header is written by the constructor of the ObjectOutputStream (kind of an ugly implementation, but it is what it is). if you construct the OIS's first, they hang waiting for the header bytes.