Java sockets - Client doesn't read the strings from server's socket - java

I have two Java projects that communicate with sockets through strings. One is a client and the other is a server. The server accepts the connection trough the "ServerSocket" and creates a new "Session" (Thread) with a freshly created "Socket".
Meanwhile, the client only has a "Socket", once that socket is connected, the client creates a "ClientSession" (Thread, pretty similar to "Session).
What I want is the server to ask the client his username through the "USERNAME" string, and the client to answers with his username. But the answer never come back. I think it's maybe a synchronisation problem with the BufferedReader and the PrintWriter lines fired at the wrong place.
-----------Server Code---------------
Login Class:
public class Login implements Runnable {
private ArrayList<Session> sessions;
private int port;
private Thread thread;
private ServerSocket serverSocket;
private Game game;
public Login(int port, Game game) throws Exception {
this.sessions = new ArrayList();
this.port = port;
this.serverSocket = new ServerSocket(port);
this.game = game;
this.thread = new Thread(this);
this.thread.start();
}
#Override
public void run() {
while(true) {
Socket socket;
try {
System.out.println("[Server Network] Waiting for a new player to log in.");
socket = serverSocket.accept();
sessions.add(new Session(socket,this));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void addPlayer(Player p) {
this.game.addPlayer(p);
}
}
Session Class:
public class Session implements Runnable {
private String username;
private Thread thread;
private Socket socket;
private BufferedReader br;
private OutputStreamWriter os;
private PrintWriter out;
private Login login;
private boolean ready;
public Session(Socket socket, Login login) throws IOException {
this.login = login;
this.socket = socket;
this.ready = false;
this.br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.os = new OutputStreamWriter(socket.getOutputStream());
this.out = new PrintWriter(os);
System.out.println("[Server network] Session created for client with ip: "+socket.getInetAddress().getHostAddress());
this.thread = new Thread(this);
this.thread.start();
}
public void send(String m) {
System.out.println("[Server network] Sending message: "+m);
out.write(m);
out.flush();
System.out.println("[Server network] Message sent: "+m);
}
#Override
public void run() {
while (true) {
if (!ready) {
try {
this.send("USERNAME");
this.username = br.readLine();
this.ready = true;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
String request = br.readLine();
System.out.println(request);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
-----------Client Code-------------
Game Class:
public class Game {
private Window window;
private LocalPlayer localPlayer;
private ArrayList<Player> players;
private Map map;
private String username;
private String serverIpAddress;
private ClientSession clientSession;
private static int port = 23123;
public Game(Window window, Map map) throws UnknownHostException, IOException {
System.out.println("Game Launched.");
//Asks for the server ip address and creates a session.
//this.serverIpAddress = JOptionPane.showInputDialog(null,"Please enter the server ip address.",JOptionPane.QUESTION_MESSAGE);
this.serverIpAddress = "localhost";
//this.username = JOptionPane.showInputDialog(null,"What is your username?",JOptionPane.QUESTION_MESSAGE);
this.username = "GriffinBabe";
this.clientSession = new ClientSession(new Socket(serverIpAddress,port),this);
this.window = window;
this.localPlayer = new LocalPlayer(new Warrior(),this.username,'R');
this.map = map;
}
public LocalPlayer getLocalPlayer() {
return this.localPlayer;
}
public Map getMap() {
return map;
}
}
ClientSession Class:
public class ClientSession implements Runnable {
private Socket socket;
private Thread thread;
private BufferedReader br;
private OutputStreamWriter os;
private PrintWriter out;
private Game game;
public ClientSession(Socket socket, Game game) throws IOException {
this.game = game;
this.socket = socket;
this.br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.os = new OutputStreamWriter(this.socket.getOutputStream());
this.out = new PrintWriter(os);
System.out.println("[Client network] Session created for server with ip: "+socket.getInetAddress().getHostAddress());
this.thread = new Thread(this);
this.thread.start();
}
public void send(String m) {
System.out.println("[Client network] Sending message: "+m);
out.write(m);
out.flush();
System.out.println("[Client network] Message sent: "+m);
}
#Override
public void run() {
while(true) {
try {
String request = br.readLine();
System.out.println(request);
switch (request) {
case "USERNAME":
send(game.getLocalPlayer().getUsername());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Here are the Console logs:
Server (launched first, of course):
Client :

Your server sends "USERNAME" and then waits. The client reads the next line, and blocks until it receives it. So you have a deadlock, since the server never sends an EOL character. If the client reads a line, the server should send a line.

In your send methods, try changing out.write(m) to out.println(m).
The readLine() method will keep reading until it hits a line terminator or end of stream, whichever comes first. The println() method will automatically put a line terminatorat the end of the string you are trying to send.
https://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#println()

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.

Get server response using Threads and sockets

I am in the process of building a client that connects to a server and sends messages. I have that part down, the server is getting the messages, but the issue I have is having my client listen for messages from the server. Essentially it is like a chat room where I will have to send messages to the server, and my client also needs to receive messages from the server and print them out as the server sends them.
I did not build the server, or have access to the server code, but I do know the server works. Below is what I have for the Client, the SendThread is working just fine, but when I add a GetThread, the send thread no longer works so I can not get 2 threads working, one listening and one sending.
Client.java
public class Client {
public static void main(String[] args) throws IOException {
// String name = args[0];
String name = "Brandon";
Socket socket = new Socket("localhost", 4688);
Thread sendThread = new SendThread(socket, name);
Thread getThread = new GetThread(socket);
sendThread.start();
getThread.start();
}
}
SendThread.java
public class SendThread extends Thread {
Socket socket;
String name;
SendThread(Socket s, String n) {
socket = s;
this.name = n;
}
public void run(){
try{
String message;
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println("connect Brandon");
BufferedReader bufferedReaderFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(bufferedReaderFromClient.readLine());
BufferedReader bufferedReader = new java.io.BufferedReader(new InputStreamReader(System.in));
while(true) {
String readerInput = bufferedReader.readLine();
printWriter.println(name + ": " + readerInput);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
GetThread.java
public class GetThread extends Thread {
Socket socket;
GetThread(Socket s) {
socket = s;
}
public void run(){
try{
String message;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while((message = bufferedReader.readLine()) != null) {
System.out.println("Incoming: " + message);
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Don't create a second BufferedReader. Use the same one for the life of the socket. You are losing data that the first reader has already buffered.
You need to break out of your read loop if readLine() returns null.
Looks like a race condition. readLine() is blocking until a message is sent, and when that happens, either GetThread or SendThread will grab it, leaving the other waiting once more. If you need the message in both threads, to avoid concurrency problems you should consider a monitor:
public class Monitor {
private String msg;
private boolean hasMsg = false;
public synchronized void newMsg(String msg) {
this.msg = msg;
hasMsg = true;
notifyAll();
}
public synchronized String getMsg() {
try {
while (!hasMsg) wait();
} catch (InterruptedException e) {};
hasMsg = false;
return msg;
}
}
public class Client {
// ...
Monitor m = new Monitor();
Thread sendThread = new SendThread(m, socket, name);
Thread getThread = new GetThread(m, socket);
// ...
}
public class GetThread extends Thread {
private Monitor monitor;
private Socket socket;
public GetThread(Monitor m, Socket s) {
monitor = m;
socket = s;
}
public void run() {
// ...
while((message = bufferedReader.readLine()) != null) {
monitor.newMsg(message);
System.out.println("Incoming: "+message);
}
// ...
}
}
public class SendThread extends Thread {
private Socket socket;
private Monitor monitor;
private String name;
public SendThread(Monitor m, Socket s, String n) {
monitor = m;
socket = s;
name = n;
}
public void run() {
// ...
String readerInput = monitor.getMsg();
printWriter.println(name + ": "+readerInput);
// ...
}
}

Why does server not respond in this programme? Client Server Java

I'm watching a client server java tutorial and in there tutor is developing a chat application. On the package there are two folders. In one folder , there are login ui (code), client connection and main class. In the other folder there are Server connection , Server Client connection (In this class includes to identify client in an unique way, tutor uses random generating number for one client) and main class.
When I'm running the application UI displays, But in console server and client outputs are not showing. Here is my Client code.
public class Client extends javax.swing.JFrame {
private String name,address;
private int port;
private DatagramSocket socket;
private InetAddress ip;
private Thread send;
public Client()
{
}
public Client(String name,String address, int port) {
this.name=name;
this.address=address;
this.port=port;
initComponents();
boolean connect = openConnection(address);
if(!connect){
System.err.println("Connection failed!");
console("Connection failed!");
}
console("Attempting to connection to"+ address+":"+port+",user:"+name);
String connection = "/c/"+name;
send(connection.getBytes());
}
private boolean openConnection(String address){
try{
socket =new DatagramSocket();
ip = InetAddress.getByName(address);
}catch(UnknownHostException e){
e.printStackTrace();
return false;
}catch(SocketException e){
e.printStackTrace();
return false;
}
return true;
}
//receive packets part //
private String receive(){
byte[]data=new byte[1024];
DatagramPacket packet = new DatagramPacket(data,data.length);
try{
socket.receive(packet);
}catch(IOException e){
e.printStackTrace();
}
String message =new String(packet.getData());
return message;
}
//send data
private void send(final byte[] data){
send = new Thread("send"){
public void run(){
DatagramPacket packet = new DatagramPacket (data,data.length,ip,port);
try{
socket.send(packet);
}catch(IOException e){
e.printStackTrace();
}
}
};
send.start();
}
private void send(String message){
if(message.equals(""))
return;
message= name+":"+message;
console(message);
send(message.getBytes());
txtMessage.setText("");
}
Server class (This includes in a sperate folder)
public class Server implements Runnable {
private List<ServerClient> clients = new ArrayList<ServerClient>();
private DatagramSocket socket;
private int port;
private boolean running = false;
private Thread run, manage, send, receive;
public Server(int port) {
this.port = port;
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
return;
}
run = new Thread(this, "Server");
run.start();
}
public void run() {
running = true;
System.out.println("Server started on port " + port);
manageClients();
receive();
}
private void manageClients() {
manage = new Thread("Manage") {
public void run() {
while (running) {
// Managing
}
}
};
manage.start();
}
private void receive() {
receive = new Thread("Receive") {
public void run() {
while (running) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
String string = new String(packet.getData());
System.out.println(string);
}
}
};
receive.start();
}
private void process(DatagramPacket packet){
String string = new String(packet.getData());
if(string.startsWith("/c/")){
UUID id= UUID.randomUUID();
System.out.println(id.toString());
clients.add(new ServerClient(string.substring(3,string.length()),packet.getAddress(),packet.getPort(),50));
System.out.println(string.substring(3,string.length()));
}else{
System.out.println(string);
}
}
In tutorial ,tutor runs this server code without main method. But It doesn't run in netbeans.
In Server class package main method
public class ServerMain {
private int port;
private Server server;
public ServerMain(int port){
this.port=port;
server = new Server(port);
}
public static void main(String[] args){
int port;
if(args.length!=1){
System.out.println("Usage: java-jar MyChat.jar[port]");
return;
}
port=Integer.parseInt(args[0]);
new ServerMain(port);
}
In client chat package main method.
public class YakaaChat {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
}
}

Simple chat client and chat server [duplicate]

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.

Categories

Resources