Simple chat client and chat server [duplicate] - java

This question already has an answer here:
ObjectInputStream(socket.getInputStream()); does not work
(1 answer)
Closed 7 years ago.
I'm doing a simple echo chat and server, but methods send and receive in class Connection don't work with ObjectInputStream and ObjectOutputStream, but with PrintWriter and BufferedReader work fine.
Now I'm trying to understand the serialization using sockets, help me to understand why this code does not work:
Client
public class Client {
private Connection connection;
private String getServerAddress() {
return "localhost";
}
private int getServerPort() {
return 4444;
}
public void run() {
BufferedReader bis = new BufferedReader(new InputStreamReader(System.in));
try {
connection = new Connection(new Socket(getServerAddress(), getServerPort()));
SocketThread socketThread = new SocketThread();
socketThread.setDaemon(true);
socketThread.start();
while (true) {
String text = bis.readLine();
if (text.equalsIgnoreCase("exit"))
break;
connection.send(text);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client client = new Client();
client.run();
}
public class SocketThread extends Thread {
#Override
public void run() {
try {
while (true) {
String message = connection.receive();
System.out.println(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Connection
public class Connection implements Closeable {
private final Socket socket;
private final ObjectInputStream in;
private final ObjectOutputStream out;
public Connection(Socket socket) throws Exception {
this.socket = socket;
this.in = new ObjectInputStream(socket.getInputStream());
this.out = new ObjectOutputStream(socket.getOutputStream());
}
public void send(String message) throws Exception {
out.writeObject(message);
}
public String receive() throws Exception {
return (String) in.readObject();
}
#Override
public void close() throws IOException {
in.close();
out.close();
socket.close();
}
}
Server
public class Server {
public static void main(String[] args) {
int port = 4444;
try (ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
Socket socket = serverSocket.accept();
new Handler(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class Handler extends Thread {
private Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try (Connection connection = new Connection(socket)) {
while (true) {
String message = connection.receive();
if (message.equals("exit"))
break;
System.out.println(message);
connection.send("Echo: " + message);
}
} catch (Exception e) {
}
}
}
}

This is because ObjectInputStream blocks trying to read the stream header written by an ObjectOutputStream in its constructor, and you are creating both of your input streams before the output streams. You can solve this by switching the order that you create the object streams in:
this.out = new ObjectOutputStream(socket.getOutputStream());
this.in = new ObjectInputStream(socket.getInputStream());
The javadoc for the ObjectOutputStream constructor also notes that you might want to flush the stream after creating it to ensure the header is sent.

Related

Java - establish a chat between two clients

Im trying to code a simple server that creates a chat between any two clients that connect to the server. (for any two new clients the server will open a new chat thred/s and then will wait to the next two clients)
i have tried the followןng solution:
Server:
public class Server
{
public Server() throws IOException
{
ServerSocket sc = new ServerSocket(7777);
Socket s1, s2;
while(true)
{
s1 = sc.accept();
s2 = sc.accept();
new ServerThread(s1, s2).start();
new ServerThread(s2, s1).start();
}
}
}
Server threads (two threads as explained in the comment above the class)
/*
Receives message from sender socket and pass them to the recipient socket
*/
public class ServerThread extends Thread
{
Socket sender;
Socket recipient;
public ServerThread(Socket sender, Socket recipient)
{
this.sender = sender;
this.recipient = recipient;
}
#Override
public void run()
{
try {
handle();
} catch (IOException e) {
e.printStackTrace();
}
}
public void handle() throws IOException
{
String msg;
// Create output stream for the recipient
OutputStream outputStream = recipient.getOutputStream();
ObjectOutputStream objOutputStream = new ObjectOutputStream(outputStream);
// Create input stream for the recipient
InputStream inputStream = sender.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
while(true) //sender.isConnected())
{
msg = objectInputStream.readUTF();
if(true) //recipient.isConnected())
objOutputStream.writeUTF(msg);
else
break;
}
sender.close();
recipient.close();
}
}
(Please note that i removed the condotion in the "while" and "if" since i wanted to eliminate anything that will might appear because of it)
Clients main:
public class ClientMain
{
public static void main(String[] args)
{
String s;
Scanner scan = new Scanner(System.in);
try {
ClientChat chat = new ClientChat("localhost", 7777);
//while true gets messages if any and print them to the console
chat.getMessages();
s = scan.nextLine();
while(!s.equals("1"))
{
chat.sendMessage(s);
s = scan.nextLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Clients Thread:
public class ClientChat
{
Socket socket;
String ip;
int port;
OutputStream outputStream;
ObjectOutputStream objOutputStream;
InputStream inputStream;
ObjectInputStream objectInputStream;
public ClientChat(String ip, int port) throws UnknownHostException, IOException
{
this.ip = ip;
this.port = port;
socket = new Socket(ip, port);
// Create output stream for the recipient
outputStream = socket.getOutputStream();
objOutputStream = new ObjectOutputStream(outputStream);
// Create input stream for the recipient
inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
}
public void getMessages() throws IOException
{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(true)//socket.isConnected())
{
String msg;
try {
msg = objectInputStream.readUTF();
System.out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
t.start();
}
public void sendMessage(String message)
{
try {
objOutputStream.writeUTF(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Well, this code doesn't work,
I have run the server and two clients, the clients do connect to the server, and you can
enter input to readLine() method, but nothing happen.
i have tried to dubug the server, what i found is that it stack on the line:
msg = objectInputStream.readUTF();
that all the relevant info i have, if you need some more information please comment
You need to call the flush() method from the ObjectOutputStream object. If you don't the data to send are stored in an internal buffer. It will get only send when the buffer is full or when you explicit call the flush() method.

ObjectInputStream DeadLock

I'm developing a client-server app, and my server can receive connection requests from 2 types of clients, therefore I instanciate the ObjectInputStream directly in my server, to recognize the client type (client or worker) and then I have a Thread for each type of client.
While initializing the thread, I pass as an argument the socket which I created in the server. (code below)
public class Server {
public int PORT;
private ArrayList<DealWithClient> connectedClients;
private ArrayList<DealWithWorker> connectedWorkers;
private ArrayList<String> types = new ArrayList<>();
private BlockingQueue<Runnable> tasks = new BlockingQueue<>();
private SearchTypes searchTypes;
private ObjectOutputStream out;
private ObjectInputStream in;
public static void main(String[] args) {
new Server(args[0]);
}
public Server(String port) {
this.PORT = Integer.parseInt(port);
startServing();
}
public void startServing() {
connectedClients = new ArrayList<>();
connectedWorkers = new ArrayList<>();
try {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Lançou ServerSocket: " + s);
try {
while (true) {
Socket socket = s.accept();
inscription(socket);
}
} finally {
s.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void inscription(Socket socket) {
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
Object obj = in.readObject();
if(obj instanceof String) {
String inscriptionMessage = (String) obj;
System.out.println("Mensagem recebida: " + obj);
if(inscriptionMessage.contains("Inscrição cliente")) {
DealWithClient dwc = new DealWithClient(socket, this);
dwc.start();
addClient(dwc);
out.writeObject(searchTypes);
}
if(inscriptionMessage.contains("Inscrição worker")) {
String[] worker = inscriptionMessage.split(" ");
searchTypes = new SearchTypes(worker[4]);
DealWithWorker dww = new DealWithWorker(socket, this);
dww.start();
addWorker(dww);
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public void addClient(DealWithClient client) {
connectedClients.add(client);
System.out.println("Cliente adicionado! »» " + client.toString());
}
public void addWorker(DealWithWorker worker) {
connectedWorkers.add(worker);
System.out.println("Worker adicionado! »» " + worker.toString());
}
My DealWithClient code below, is where I'm having the problem, since that I can not reach the System.out.println("BBB"), because it gets stuck in the instanciation of ObjectInputStream.
public class DealWithClient extends Thread{
private Socket socket;
private Server server;
private ObjectInputStream in;
private ObjectOutputStream out;
private Client client;
public DealWithClient(Socket socket, Server server) {
this.server = server;
this.socket = socket;
}
#Override
public void run() {
try {
connectToServer();
} catch (IOException e) {
e.printStackTrace();
}
while(!interrupted()) {
treatClientRequests();
}
}
private void connectToServer() throws IOException {
out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("AAA");
in = new ObjectInputStream(socket.getInputStream());
System.out.println("BBB");
}
I've looked for similar questions around here, but I didn't managed to find one that could solve my issue.
My question is, once I instanciate the ObjectInput and ObjectOutput streams in the server, I cannot do it again inside my Thread?
Thanks!
You are most likely getting a deadlock error because the socket is still being used by ObjectOutputStream when you are trying to get an Input stream from the same socket. Try calling the close() method on out before instantiating the ObjectInputStream below. Calling the close() method will free up resources.

How to fix "no communication between server and client"

This is code provided to me for a class. I am trying trying to fix a connection problem between the client and server. Even when both are started they do not connect.
This is for a Java based game of Battleship that will allow two users on separate devices to play one another. I'm not sure why the two do not connect and even the debugger has not been much help in directing me to the problem.
public class GameClient
{
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void openConnection(String ip, int port)
{
try
{
clientSocket = new Socket(ip, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
catch (Exception e)
{
System.out.println("Error opening client socket");
}
}
public String sendMessage(String msg)
{
String resp = "";
try
{
out.println(msg);
resp = in.readLine();
}
catch (Exception e)
{
System.out.println("Error sending message from Client");
}
return resp;
}
public void stop()
{
try
{
in.close();
out.close();
clientSocket.close();
}
catch (Exception e)
{
System.out.println("Error stopping client");
}
}
public static void main(String[] args)
{
GameClient client = new GameClient();
client.openConnection("10.7.232.200", 3333);
String response = client.sendMessage("1,2");
System.out.println(response);
client.stop();
}
}
public class GameServer
{
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void start(int port)
{
try
{
serverSocket = new ServerSocket(port);
clientSocket = serverSocket.accept();
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String move = in.readLine();
System.out.println(move);
out.println("6,1");
}
catch (Exception e)
{
System.out.println("Socket opening error");
}
}
public void stop()
{
try
{
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
catch (Exception e)
{
System.out.println("Error closing sockets");
}
}
public static void main(String [] args)
{
GameServer server = new GameServer();
server.start(3333);
server.stop();
}
}
public class PlayBattleship
{
public static void main(String[] args)
{
GameClient client = new GameClient();
client.openConnection("10.7.232.200", 3333);
//System.out.println(response);
BattleshipGame game = new BattleshipGame();
while (!game.checkEndgame())
{
game.getGuess(client);
}
client.stop();
}
}
The client and server should connect and stay connected till the game has reached completion
EDIT: I have thoroughly read the API documentation but still cannot understand the problem.
The Server in your code isn't waiting for the incoming requests, it only serves a single incoming request and then kills itself due to the nature of the main method which starts it.
You need to have the server wait for the requests and do not die. Check the code snippet below to understand the logic.
Plus, always try to throw the exceptions if you can't do anything meaningful with it within the method it is caught in. In your code the main method of the server will anyway execute even if there is an exception caught in the start method
public class GameServer {
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public ServerSocket start(int port) throws IOException {
serverSocket = new ServerSocket(port);
return serverSocket;
}
public void stop() throws IOException {
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
// This method accepts and serves the incoming requests
public void acceptConnection(ServerSocket serverSocket) throws IOException {
clientSocket = serverSocket.accept();
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String move = in.readLine();
System.out.println(move);
out.println("6,1");
}
public static void main(String[] args) throws IOException {
GameServer server = new GameServer();
ServerSocket serverSocket = server.start(3333);
System.out.println("Server Started");
// The effective change you need to make
// Loop through the incoming requests
while(true) {
server.acceptConnection(serverSocket);
}
}
}
public class GameClient {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void openConnection(String ip, int port) throws IOException {
clientSocket = new Socket(ip, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
public String sendMessage(String msg) throws IOException {
String resp = "";
out.println(msg);
resp = in.readLine();
return resp;
}
public void stop() throws IOException {
in.close();
out.close();
clientSocket.close();
}
public static void main(String[] args) throws IOException {
GameClient client = new GameClient();
client.openConnection("10.7.232.200", 3333);
String response = client.sendMessage("1,2");
System.out.println(response);
client.stop();
}
}

Java socket handle multiple clients

I have a server and a client the client already connects successfully to the server even if i start another client it connects successfully and here is my problem the clients can send data to the server (its basically only a string)the server gets the data of both clients but the clients only get their own data back and i would like to have that both clients get the same data from the server back.
Server:
public class Server extends Application {
#Override
public void start(Stage primaryStage) {
}
static ServerSocket serverSocket;
static Socket socket;
static DataOutputStream out;
static DataInputStream in;
static Users[] user = new Users[10];
public static void main(String[] args) throws IOException {
System.out.println("Starting server...");
serverSocket = new ServerSocket(7777);
System.out.println("Server started");
while(true){
socket = serverSocket.accept();
for(int i = 0;i < 10; i++){
System.out.println("Connection from:" + socket.getInetAddress());
out = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
if(user[i] == null){
user[i] = new Users(out,in,user);
Thread thread = new Thread(user[i]);
thread.start();
break;
}
}
}
}
private static class Users implements Runnable{
DataOutputStream out;
DataInputStream in;
Users[] user = new Users[10];
String name;
public Users(DataOutputStream out,DataInputStream in,Users[] user){
this.out = out;
this.in = in;
this.user = user;
}
#Override
public void run() {
while(true){
try {
String recievingData = in.readUTF();
System.out.println(recievingData);
out.writeUTF(recievingData);
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}}}
Client(both are the same):
public class ServerClient {
static Socket socket;
static DataInputStream in;
static DataOutputStream out;
public ServerClient() throws IOException{
System.out.println("Connecting");
socket = new Socket("localhost",7777);
System.out.println("Connecting succesful");
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
System.out.println("Recieving");
Input input = new Input(in);
Thread thread = new Thread(input);
thread.start();
}
public static void UploadPos(){
try {
out.writeUTF("TEST");
} catch (IOException ex) {
Logger.getLogger(ServerClient.class.getName()).log(Level.SEVERE, null, ex);
}
}}
class Input implements Runnable{
DataOutputStream out;
DataInputStream in;
public Input(DataInputStream in){
this.in = in;
}
#Override
public void run() {
while(true){
try {
String data = in.readUTF();
System.out.println(data);
} catch (IOException ex) {
Logger.getLogger(Input.class.getName()).log(Level.SEVERE, null, ex);
}
}
}}
Create a list of output streams.
List<DataOutputStream> clientOuts = new ArrayList<>();
after
out = new DataOutputStream(socket.getOutputStream());
add
clientOuts.add(out);
then replace
out.writeUTF(recievingData);
with
for(DataOutputStream cout :clientOutputs) {
cout.writeUTF(recievingData);
}

Java "NotSerializableException: java.net.Socket" When Not Sending A Socket

So I send a Server object to a client with this thread:
public ConnectionThread(final Server server) {
super(new Runnable() {
public void run() {
try {
Socket client = server.serverSocket.accept();
server.clients.add(client);
ObjectInputStream in = new ObjectInputStream(
client.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(
client.getOutputStream());
System.out.println("Connected client: "
+ client.getRemoteSocketAddress());
server.launchNewThread();
Object input;
while (!client.isClosed()) {
input = in.readObject();
if (input != null) {
if (input.toString().equals("server")) {
out.writeObject(server);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
And when I call out.writeObject(server) I get this exception:
java.io.NotSerializableException: java.net.Socket
Here is the Server class:
public class Server implements Serializable {
private static final long serialVersionUID = 4634111951586948020L;
public ServerArgs args;
public ArrayList<Socket> clients = new ArrayList<Socket>();
public ServerSocket serverSocket;
public Server(int port) throws IOException {
serverSocket = new ServerSocket(port);
launchNewThread();
}
public void launchNewThread() {
ConnectionThread thread = new ConnectionThread(this);
thread.start();
}
public static void main(String[] args) throws IOException {
new Server(27015);
}
}
public ArrayList<Socket> clients = new ArrayList<Socket>();
public ServerSocket serverSocket;
You have plenty of non-serializable sockets right there. It's very unclear what the purpose of "sending a server" is, but perhaps you should either just send the ServerArgs or mark those two fields transient.

Categories

Resources