I'm trying to make a client-server socket connection that will send message objects (type,sender,reciever,time,message).
When my client tries connecting the server recognises the connection but the client keeps waiting on objectInputStream = new ObjectInputStream(socket.getInputStream());
.
I've seen answers on here suggesting that you should make the outputsream first and then the input but it didn't change anything. I am not sure what I am missing.
Client:
class Message {
//...
}
public class ChatClient extends Thread
{
protected int serverPort = 1234;
public static void main(String[] args) throws Exception {
new ChatClient();
}
public ChatClient() throws Exception {
Socket socket = null;
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
// connect to the chat server
try {
System.out.println("[system] connecting to chat server ...");
socket = new Socket("localhost", serverPort); // create socket connection
objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); // create output stream for sending messages
// works until here
objectInputStream = new ObjectInputStream(socket.getInputStream()); // create input stream for listening for incoming messages
// GETS STUCK HERE
System.out.println("[system] connected");
ChatClientMessageReceiver message_receiver = new ChatClientMessageReceiver(objectInputStream); // create a separate thread for listening to messages from the chat server
message_receiver.start(); // run the new thread
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
// reading stuff from terminal and sending messages to the chat server
this.sendMessage(tmp, objectOutputStream); // send the message to the chat server
// cleanup
objectOutputStream.close();
objectInputStream.close();
std_in.close();
socket.close();
}
private void sendMessage(Message message, ObjectOutputStream objectOutputStream) {
try {
objectOutputStream.writeObject(message); // send the message to the chat server
objectOutputStream.flush(); // ensure the message has been sent
} catch (IOException e) {
System.err.println("[system] could not send message");
e.printStackTrace(System.err);
}
}
}
// wait for messages from the chat server and print the out
class ChatClientMessageReceiver extends Thread {
private ObjectInputStream objectInputStream;
public ChatClientMessageReceiver(ObjectInputStream objectInputStream) {
this.objectInputStream = objectInputStream;
}
public void run() {
try {
Message message;
message = (Message)objectInputStream.readObject();
System.out.println("["+message.sender+"] " + message.message);
} catch (Exception e) {
System.err.println("[system] could not read message");
e.printStackTrace(System.err);
System.exit(1);
}
}
}
Server:
class Message {
//...
}
public class ChatServer {
protected int serverPort = 1234;
protected List<Socket> clients = new ArrayList<Socket>(); // list of clients
public static void main(String[] args) throws Exception {
new ChatServer();
}
public ChatServer() {
ServerSocket serverSocket = null;
// create socket
try {
serverSocket = new ServerSocket(this.serverPort); // create the ServerSocket
} catch (Exception e) {
System.err.println("[system] could not create socket on port " + this.serverPort);
e.printStackTrace(System.err);
System.exit(1);
}
System.out.println("[system] listening ...");
try {
while (true) {
Socket newClientSocket = serverSocket.accept(); // wait for a new client connection
synchronized(this) {
clients.add(newClientSocket); // add client to the list of clients
}
ChatServerConnector conn = new ChatServerConnector(this, newClientSocket); // create a new thread for communication with the new client
conn.start(); // run the new thread
}
} catch (Exception e) {
System.err.println("[error] Accept failed.");
e.printStackTrace(System.err);
System.exit(1);
}
// close socket
System.out.println("[system] closing server socket ...");
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
// send a message to all clients connected to the server
public void sendToAllClients(Message message) throws Exception {
//...
}
//...
public void removeClient(Socket socket) {
synchronized(this) {
names.remove(socket.getPort());
}
}
}
class ChatServerConnector extends Thread {
private ChatServer server;
private Socket socket;
private ObjectInputStream objectInputStream;
private Message message;
public ChatServerConnector(ChatServer server, Socket socket) {
this.server = server;
this.socket = socket;
}
public void run() {
try {
objectInputStream = new ObjectInputStream(this.socket.getInputStream()); // create input stream for listening for incoming messages
System.out.println("[system] connected with " + this.socket.getInetAddress().getHostName() + ":" + this.socket.getPort());
} catch (IOException e) {
System.err.println("[system] could not open input stream!");
//...
return;
}
while (true) { // infinite loop in which this thread waits for incoming messages and processes them
message = new Message();
try {
message = (Message)objectInputStream.readObject();
} catch (Exception e) {
//...
}
switch(message.type) {
//...
case "public":
try {
this.server.sendToAllClients(message); // send message to all clients
} catch (Exception e) {
//..
}
return;
default:
//...
}
}
}
}
The ObjectInputStream
constructor already tries to read the header data (documentation):
A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.
So most likely what happens is that both your client and your server create an ObjectInputStream
listening for the message from the other one. But because neither of them has written anything yet, both get stuck.
Maybe this could be solved by creating the ObjectInputStream
inside the client thread.
Also, please only use ObjectInputStream
for hobby projects; it should be avoided nowadays, especially for untrusted data. See also the Secure Coding Guidelines for Java. It has already lead to dozens of remote code execution vulnerabilities in the past. Instead prefer other more secure serialization frameworks, for example Gson or Jackson for JSON, or Protocol Buffers, ...