I'm writing an all-in-one java chat program which will either act as a client or a server. I'm currently having this problem where, after the connection is established, the program only successfully recieves (or sends?) some of the messages. I've used a loop to spam through a load of junk and I've seen that the other end will only pick up some of the messages. I've never got a message to send manually.
Here is the code:
public class ConnectionThread implements Runnable {
private Connection c = Connection.getInstance();
private ChatInterface chatInterface;
private static ConnectionThread serverThread;
private ServerSocket serverSocket;
private Socket socket;
private ObjectInputStream dataIn;
private ObjectOutputStream dataOut;
public ConnectionThread() {}
public static synchronized ConnectionThread getInstance() {
if (serverThread == null) {
serverThread = new ConnectionThread();
}
return serverThread;
}
public void run() {
// If the programs role is server, set up the server
if (c.getRole() == ConnectionRole.SERVER) {
try {
setupServer();
waitForConnection();
setupStreams();
} catch (IOException e) {
e.printStackTrace();
}
do {
try {
chatInterface.addToChatHistory(dataIn.readUTF());
} catch (IOException e) {
e.printStackTrace();
}
} while (c.getRole() == ConnectionRole.SERVER);
}
// If the programs role is client, set up a connection to the server
if (c.getRole() == ConnectionRole.CLIENT) {
try {
setupClient();
setupStreams();
} catch (IOException e) {
e.printStackTrace();
}
do {
try {
chatInterface.addToChatHistory(dataIn.readUTF());
} catch (IOException e) {
e.printStackTrace();
}
} while (c.getRole() == ConnectionRole.CLIENT);
}
}
private void setupClient() throws IOException {
System.out.println("ATTEMPTING TO CONNECT...");
socket = new Socket("127.0.0.1", 8080);
System.out.println("CONNECTED!");
}
private void setupServer() throws IOException {
System.out.println("SETTING UP SERVER..");
serverSocket = new ServerSocket(8080, 1);
System.out.println("SERVER SETUP");
}
private void waitForConnection() throws IOException {
System.out.println("WAITING FOR A CONNECTION...");
socket = serverSocket.accept();
System.out.println("CONNECTION RECIEVED");
}
private void setupStreams() throws IOException {
System.out.println("SETTING UP STREAMS...");
dataOut = new ObjectOutputStream(socket.getOutputStream());
dataIn = new ObjectInputStream(socket.getInputStream());
chatInterface = ChatInterface.getInstance();
System.out.println("STREAMS SETUP");
}
public void sendMessage(String message) throws IOException {
System.out.println("SENDING MESSAGE...");
dataOut.writeUTF(message);
chatInterface.addToChatHistory(message);
System.out.println("MESSAGE SENT!");
}
}
Can anyone tell me why not all messages are being sent/picked up properly? I've been playing with it for quite a while now and I can't figure out why.
I found out after following EJP's recommendation to switch to DataInput/OutputStreams which worked straight away. Although I did need to be using ObjectInput/OutputStreams so I switched back. I found that I got the same issue again, until I switched to write/readObject instead of write/readUTF. If I cast the readObject to (String) it would then manage to receive every message.
So if anyone is having the same problem with ObjectInput/OutputStreams using write/readUTF try using write/readObject instead.
Related
I have an application that has to send data via TCP socket to another application. This is a 1 way stream from client to server. When sending data the client must retry/reconnect and try to insure all data is sent should the receiver/listener/server die/disappear or drop the connection. My code is as follow:
public class TCPSocket implements Closeable {
private static final int SIXTY_FOUR_KB = 65536;
private final String ip;
private final int port;
private Socket socket;
private BufferedOutputStream writer;
public TCPSocket(String ip, int port) {
this.ip = ip;
this.port = port;
}
public TCPSocket connect() throws ConnectException {
try {
socket = new Socket(ip, port);
socket.setSendBufferSize(SIXTY_FOUR_KB);
writer = new BufferedOutputStream(socket.getOutputStream(), SIXTY_FOUR_KB);
} catch (Exception e) {
throw new ConnectException(e.getMessage());
}
return this;
}
public void write(String message) throws InterruptedException {
boolean succeeded = true;
do {
try {
writer.write(message.getBytes(StandardCharsets.UTF_8));
writer.write("\n".getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
System.out.println(e.getMessage());
succeeded = false;
// Exponential backoff to go here
try {
System.out.println("Attempting reconnection");
tryClose();
connect();
} catch (ConnectException connectException) {
System.out.println(connectException.getMessage());
}
}
} while (!succeeded);
}
private void tryClose() {
try {
close();
} catch (Exception ex) {
System.out.println("Failed closing TCPSocket");
}
}
#Override
public void close() throws IOException {
if (writer != null) {
writer.flush();
writer.close();
writer = null;
}
if (socket != null && !socket.isClosed()) {
socket.close();
socket = null;
}
}
}
N.B: Reason for using the BufferedOutputStream is because I'm sending small messages and all other methods couldn't get the same throughput in real world test scenario.
This all works as expected for me however I have a few points.
Is this the right way to do this or totally insane and will cause
serious problems?
When trying to clean up and close connections and the writer before
opening a new connection the following error is thrown and I am
unable to close the bufferedOutputStream
java.net.SocketException: Connection reset by peer: socket write error
If I socket.shutdownOutput(); before attempting to close the output stream then that also throws an exception. What is the correct way to clean up and reconnect?
I'm writing a server/client application for school.
Every time I close the client, the server throws 'java.net.SocketException: Connection reset'. I think, I have to close the socket in the client before closing the JavaFX-window, but where? Or what do you think?
I've seen a similar question, but I don't know how to implement it correctly in my programm.
Exception:
20:05:27.132 [Thread-2] ERROR OnlineBank - java.net.BindException: Address already in use: JVM_Bind
19:51:06.580 [Thread-1] ERROR ServerHandler - java.net.SocketException: Connection reset
19:51:06.580 [Thread-2] ERROR ServerHandler - java.net.SocketException: Connection reset
MyProgramm:
private MyProgramm() {
server = new MyServer(Constants.REMOTE_PORT);
try
server.start();
} catch (ClassNotFoundException | IOException e) {
logger.error(e);
}
}
MyServer:
public void start() throws ClassNotFoundException, IOException {
try {
serverSocket = new ServerSocket(this.port);
while (true) {
Socket client = serverSocket.accept();
logger.debug(getClass().getName() + " accepts");
Thread threadHandler = new Thread(new ServerHandler(client));
threadHandler.start();
}
} finally {
if (serverSocket != null) {
serverSocket.close();
}
}
}
ServerHandler:
#Override
public void run() {
try (InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
ObjectInputStream oin = new ObjectInputStream(in);
ObjectOutputStream oos = new ObjectOutputStream(out)) {
while (true) {
try {
Object receivedObject = oin.readObject();
handleReceivedObject(oos, receivedObject);
} catch (ClassNotFoundException e) {
logger.error(e);
break;
}
}
} catch (IOException e) {
logger.error(e);
}
}
MainClient:
public class MainClient extends Application {
private static Client client;
public static void main(String[] args) {
launch(args);
try {
client = new Client();
} catch (IOException e) {
logger.error(e);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/welcome.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() throws Exception {
super.stop();
// to avoid NullPointerException
if (Client != null && Client.getSocket() != null) {
Client.getSocket().close();
}
}
}
Client:
public class Client {
private Socket socket;
public Client(String remoteHost, int port) throws UnknownHostException, IOException {
if (getSocket() == null) {
socket = new Socket(remoteHost, port);
}
}
public Client() throws UnknownHostException, IOException {
this(Constants.REMOTE_HOST, Constants.REMOTE_PORT);
}
public Socket getSocket() {
return socket;
}
}
You are correct. You have to close the client socket properly before exiting the client. Otherwise the operating system may reset the connection instead of closing it. Not being an Android guy I cannot advise you where this closure should be placed.
Your server has a problem too. It needs to catch EOFException in the read loop and silently break. At present you aren't handling end of stream correctly: you will catch it via catch (EOFException ) and log it as an error, which it isn't really.
I finished writing a Client/Server Socket communication program that works fine. Now I'm trying to figure out how to make it so that I can have multiple Client connections to the Server at once. I've looked around and there seems to be more than a couple of different ways to do this. so I've come here to ask you guys for help/suggestions.
My Server:
public class Server {
private ServerSocket serverSocket = null;
private Socket clientSocket = null;
public Server() {
try {
serverSocket = new ServerSocket(7003);
} catch (IOException e) {
System.err.println("Could not listen on port: 7003");
System.exit(1);
}
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed");
System.exit(1);
}
}
public void startServer() throws IOException {
PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine, outputLine;
outputLine = "Connected to Server";
output.println(outputLine);
while ((inputLine = input.readLine()) != null) {
// This just determines users input and server ruturns output based on that
outputLine = this.getServerOutput(inputLine);
output.println(outputLine);
if (outputLine.equals("Bye"))
break;
}
output.close();
input.close();
clientSocket.close();
serverSocket.close();
}
}
Would I need to make my constructor create threads and startServer() or would be my run method?
You should use ExecutorService. Your client request processing would be the run() of a Runnable and after each accept you can call ExecutorService.submit(runnableTask) to asynchronously service the client.
A sample using ExecutorService.
public class MyServer {
private static MyServer server;
private ServerSocket serverSocket;
/**
* This executor service has 10 threads.
* So it means your server can process max 10 concurrent requests.
*/
private ExecutorService executorService = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws IOException {
server = new MyServer();
server.runServer();
}
private void runServer() {
int serverPort = 8085;
try {
System.out.println("Starting Server");
serverSocket = new ServerSocket(serverPort);
while(true) {
System.out.println("Waiting for request");
try {
Socket s = serverSocket.accept();
System.out.println("Processing request");
executorService.submit(new ServiceRequest(s));
} catch(IOException ioe) {
System.out.println("Error accepting connection");
ioe.printStackTrace();
}
}
}catch(IOException e) {
System.out.println("Error starting Server on "+serverPort);
e.printStackTrace();
}
}
//Call the method when you want to stop your server
private void stopServer() {
//Stop the executor service.
executorService.shutdownNow();
try {
//Stop accepting requests.
serverSocket.close();
} catch (IOException e) {
System.out.println("Error in server shutdown");
e.printStackTrace();
}
System.exit(0);
}
class ServiceRequest implements Runnable {
private Socket socket;
public ServiceRequest(Socket connection) {
this.socket = connection;
}
public void run() {
//Do your logic here. You have the `socket` available to read/write data.
//Make sure to close
try {
socket.close();
}catch(IOException ioe) {
System.out.println("Error closing client connection");
}
}
}
}
how to make it so that I can have multiple Client connections to the Server at once
Right now you are starting your server and immediately waiting for a single client to connect in the constructor.
clientSocket = serverSocket.accept();
Then you handle that single socket connection inside of your startServer() method. This means that no other clients will be handled.
public void startServer() throws IOException {
PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);
...
Typically with a server pattern like this, you would do something like the following:
Setup your server socket in the constructor.
Create an acceptClients() method which would loop waiting for a client to be accepted. This could fork a thread to accept the clients in a thread of its own in the background.
For each client, either fork a thread to handle the connection, passing the thread the clients socket. Better would be to, as #basiljames shows, use an ExecutorService to manage the threads for you.
Here's some sample code:
public class Server {
private ServerSocket serverSocket = null;
public Server(int portNumber) throws IOException {
serverSocket = new ServerSocket(portNumber);
}
// this could be run in a thread in the background
public void acceptClients() throws IOException {
// create an open ended thread-pool
ExecutorService threadPool = Executors.newCachedThreadPool();
try {
while (!Thread.currentThread().isInterrupted()) {
// wait for a client to connect
Socket clientSocket = serverSocket.accept();
// create a new client handler object for that socket,
// and fork it in a background thread
threadPool.submit(new ClientHandler(clientSocket));
}
} finally {
// we _have_ to shutdown the thread-pool when we are done
threadPool.shutdown();
}
}
// if server is running in background, you stop it by killing the socket
public void stop() throws IOException {
serverSocket.close();
}
// this class handles each client connection
private static class ClientHandler implements Runnable {
private final Socket clientSocket;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
// use the client socket to handle the client connection
...
}
}
}
Using the ExecutorService thread-pools is recommended for just about all Thread implementations like this. If, however, you are stuck to using raw Thread for some reason, you can do the following instead in your acceptClients() method:
public void acceptClients() throws IOException {
while (!Thread.currentThread().isInterrupted()) {
// wait for a client to connect
Socket clientSocket = serverSocket.accept();
// fork a background client thread
new Thread(new ClientHandler(clientSocket)).start();
}
}
Change this: public void startServer() throws IOException
To this: public void startServer(Socket clientSocket) throws IOException
Then all you need to do is:
public Server()
{
try
{
serverSocket = new ServerSocket(7003);
}
catch (IOException e)
{
System.err.println("Could not listen on port: 7003");
System.exit(1);
}
try
{
while(true) {
final Socket socket = serverSocket.accept();
new Thread(new Runnable() {
public void run() {
try {
startServer(socket);
} catch(IOException e) {e.printStackTrace();}
}
}).start();
}
}
catch(IOException e)
{
System.err.println("Accept failed");
System.exit(1);
}
}
And lastly, you can remove private Socket clientSocket = null;
That should get you there. Or at least pretty close.
private static final int SERVER_PORT = 35706;
private ServerSocket serverSocket;
private final ArrayList<ClientThread> activeClients = new ArrayList<>();
public void startServer() {
try {
serverSocket = new ServerSocket(SERVER_PORT);
final ExecutorService clientPool = Executors.newCachedThreadPool();
while (!serverSocket.isClosed()) {
try {
Future<Socket> future = clientPool.submit(() -> {
Socket socket = serverSocket.accept();
ClientThread clientThread= new ClientThread(socket);
return (socket);
});
activeClients.add(future.get());
} catch (IOException e) {
clientPool.shutdownNow();
System.out.println(e.getMessage());
} catch (InterruptedException | ExecutionException e) {
System.out.println(e.getMessage());
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public void stopServer() {
try {
serverSocket.close();
activeClients.forEach(socket -> {
try {
socket.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
});
} catch (IOException ex) {
System.out.println(e.getMessage());
}
}
private static class ClientThread implements Runnable{
private final Socket socket;
public ClientThread(Socket socket) throws IOException {
this.socket = socket;
}
#Override
public void run() {
/* Your implementation */
}
}
I'm having a problem with a little game I'm designing in my class.
The problem is that I got two clients connected to a server. (client1 and client2) They are each running a game, which in the end, closes the window. As the game window is a JDialog, it will then, when it's closed, send a message, through a socket, to the server, telling it that it's done. I want the server to know which of the two clients were completed first. They are reporting through a PrintWriter on the sockets' OutputStream.
What I did was this:
in1 = new BufferedReader(new InputStreamReader(client.getInputStream()));
in2 = new BufferedReader(new InputStreamReader(client2.getInputStream()));
try {
in1.readLine();
} catch (IOException ex) {
Logger.getLogger(gameServer.class.getName()).log(Level.SEVERE, null, ex);
}
try {
in2.readLine();
} catch (IOException ex) {
Logger.getLogger(gameServer.class.getName()).log(Level.SEVERE, null, ex);
}
Problem is that it waits for the first input, before it even starts listening on the second. How can I make it listen on both at the same time? Or solve my problem some other way.
Thanks!
Server connection should work like this:
Server gameServer = new Server();
ServerSocket server;
try {
server = new ServerSocket(10100);
// .. server setting should be done here
} catch (IOException e) {
System.out.println("Could not start server!");
return ;
}
while (true) {
Socket client = null;
try {
client = server.accept();
gameServer.handleConnection(client);
} catch (IOException e) {
e.printStackTrace();
}
}
In hanleConnection() you start a new thread and run the communication for this client in the created thread. Then the server can accept a new connection (in the old thread).
public class Server {
private ExecutorService executor = Executors.newCachedThreadPool();
public void handleConnection(Socket client) throws IOException {
PlayerConnection newPlayer = new PlayerConnection(this, client);
this.executor.execute(newPlayer);
}
// add methods to handle requests from PlayerConnection
}
The PlayerConnection class:
public class PlayerConnection implements Runnable {
private Server parent;
private Socket socket;
private DataOutputStream out;
private DataInputStream in;
protected PlayerConnection(Server parent, Socket socket) throws IOException {
try {
socket.setSoTimeout(0);
socket.setKeepAlive(true);
} catch (SocketException e) {}
this.parent = parent;
this.socket = socket;
this.out = new DataOutputStream(socket.getOutputStream());;
this.in = new DataInputStream(socket.getInputStream());
}
#Override
public void run() {
while(!this.socket.isClosed()) {
try {
int nextEvent = this.in.readInt();
switch (nextEvent) {
// handle event and inform Server
}
} catch (IOException e) {}
}
try {
this.closeConnection();
} catch (IOException e) {}
}
}
Ok so , i have a thread class called 'Client' every time the server accepts a connection it creates a new Client....The run method listens for messages from the client and i am useing ObjectInputStream ..
do {
ObjectInputStream in = null;
try {
in = new ObjectInputStream(socket.getInputStream());
String message = (String) in.readObject();
System.out.println(message);
}
catch (ClassNotFoundException ex) {
isConnected = false;
System.out.println("Progoramming Error");
}
catch (IOException ex) {
isConnected = false;
System.out.println("Server ShutDown");
System.exit(0);
}
} while(isConnected);
The Problem i have is that why do i have to create a new ObjectInputStream every time it loops...and if i close the input stream at the end of the loop and it loops again for another message i will get a error...Please some one help
Only create the ObjectInputStream once (outside the loop) for a client connection, then put the readObject method into the loop.
Here's a working test class:
public class TestPrg {
public static void main(String... args) throws IOException {
ServerListener server = new ServerListener();
server.start();
Socket socketToServer = new Socket("localhost", 15000);
ObjectOutputStream outStream = new ObjectOutputStream(socketToServer.getOutputStream());
for (int i=1; i<10; i++) {
try {
Thread.sleep((long) (Math.random()*3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Sending object to server ...");
outStream.writeObject("test message #"+i);
}
System.exit(0);
}
static class ServerListener extends Thread {
private ServerSocket serverSocket;
ServerListener() throws IOException {
serverSocket = ServerSocketFactory.getDefault().createServerSocket(15000);
}
#Override
public void run() {
while (true) {
try {
final Socket socketToClient = serverSocket.accept();
ClientHandler clientHandler = new ClientHandler(socketToClient);
clientHandler.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
static class ClientHandler extends Thread{
private Socket socket;
ObjectInputStream inputStream;
ClientHandler(Socket socket) throws IOException {
this.socket = socket;
inputStream = new ObjectInputStream(socket.getInputStream());
}
#Override
public void run() {
while (true) {
try {
Object o = inputStream.readObject();
System.out.println("Read object: "+o);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
In this example Strings are sent trough the ObjectStream. If you get the ClassNotFoundException (http://download.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html#readObject()) and are using an independent client and server program than you might check if both the client and the server have the class of the object to send in their class paths.
The problem i personally had with Sockets and ObjectIOStream, is that it remembers all your object addresses, so each time you send and recive them on the client, if the address of sent object is not changed it will be copied from buffer. So
So
or create new objects each time you send them ( this is not a bad idiea, because ObjectIOStream seems to has limits on this buffer)
or use another Stream for these perpouse