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);
// ...
}
}
Related
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.
I'm creating a NetUtils class which extends thread to handle socket communications in a GUI without blocking the main thread. My code looks like the following (assume all import are accounted for):
Main method
public static void main(String[] args) {
EventQueue.invokeLater( () -> {
new Window().setVisible(true);
});
}
Window class
public class Window { // normally would extend JFrame bc this is a gui
// ...
NetUtils comms;
public Window() {
// ...
comms = new NetUtils("192.168.1.1", 288); // this ip/port info works fine
comms.start();
// ...
}
// other methods....
}
NetUtils class
public class NetUtils extends Thread {
private String ip;
private int port;
public NetUtils(String ip, int port) {
this.ip = ip;
this.port = port;
}
#Override
public void run() {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(ip, port), 10000); // timeout 10s
System.out.println("Socket started: " + socket); // correctly prints
while (true) { // during the life of the thread
String line = readLine(socket); // throws SocketException here (socket closed error)
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String readLine(Socket socket) {
// uses inputstream to read bytes and such
String line;
boolean isDone = false;
while (!isDone) {
try (InputStreamReader isr = new InputStreamReader(socket.getInputStream))) {
if (isr.ready()) {
line += (char) isr.read();
}
if (!isr.ready() && line != "") {
isDone = true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return line;
}
}
What am I doing that would cause the socket to close? I ran the NetUtils code directly in the main method (I didnt separate out the readLine method) and it ran as I expected it to which lead me to believe the problem has to do with the socket being in a thread. Thanks for the help.
Clearly 'this part works' is closing the socket or its input or output stream.
NB You aren't checking for end of stream in the code you posted. I don't see the need for the readLine() method. Just replace your loop with this:
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
reader.close();
[exception handling omitted.]
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()
I'm trying to write a little SocketServer and a fitting ClientApplet. The connection works (I echo out incoming/closing connections), but the server does not get any InputStream.
I just can't fix the problem and feel a bit lost :/
The complete project is here.
Here is the responsible part of my server:
MessageService.java
public class MessageService implements Runnable {
private final Socket client;
private final ServerSocket serverSocket;
MessageService(ServerSocket serverSocket, Socket client) {
this.client = client;
this.serverSocket = serverSocket;
}
#Override
public void run() {
PrintWriter out = null;
BufferedReader in = null;
String clientName = client.getInetAddress().toString();
try {
out = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String line;
System.out.println("Waiting for "+clientName);
/* HERE I TRY TO GET THE STREAM */
while((line = in.readLine()) != null) {
System.out.println(clientName + ": " + line);
out.println(line);
out.flush();
}
}
catch (IOException e) {
System.out.println("Server/MessageService: IOException");
}
finally {
if(!client.isClosed()) {
System.out.println("Server: Client disconnected");
try {
client.close();
}
catch (IOException e) {}
}
}
}
}
Part of Client
QueueOut.java
public class QueueOut extends Thread {
Socket socket;
public ConcurrentLinkedQueue<String> queue;
PrintWriter out;
public QueueOut(Socket socket) {
super();
this.socket = socket;
this.queue = new ConcurrentLinkedQueue<String>();
System.out.print("OutputQueue started");
}
#Override
public void start() {
try {
out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
System.out.println("Running outputqueue");
while(true) {
if(this.queue.size() > 0) {
String message = this.queue.poll();
System.out.println("Sending "+message);
out.println(message+"\n");
}
}
}
catch (IOException ex) {
System.out.println("Outputqueue: IOException");
}
}
public synchronized void add(String msg) {
this.queue.add(msg);
}
}
I have reduced my post to the (as i think) necessary parts :)
Try getting your input stream before you get the output stream, even though you're not using it, you should match the inverse order on your client and your server (as discussed in another similar threads).
Edit:
Also see Socket programming
Good Luck!
I am working on a Distributed System , the current state it's more of a client/server application as i'm missing the key part that makes it a distributed system. I don't know how to implement my client thread classs c_thread to pass a 'message' to all the worker threads w_thread that are running.
import java.net.*;
import java.io.*;
public class w_thread extends Thread {
private Socket socket = null;
private tracker track = null;
private int tID;
//Constructor method
public w_thread(tracker t, Socket s) {
super("w_thread");
this.track = t;
this.socket = s;
tID = track.add();
}
public void run() {
try {
String inputLine, outputLine;
PrintWriter worker_out;
BufferedReader worker_in;
//set up IO to worker
worker_out = new PrintWriter(socket.getOutputStream(), true);
worker_in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//Get inputLine from c_thread?
//...
/*
worker_out.close();
worker_in.close();
socket.close();
*/
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.net.*;
import java.io.*;
public class c_thread extends Thread {
private Socket socket = null;
private tracker track = null;
//Constructor method
public c_thread(tracker t, Socket s) {
super("c_thread");
this.track = t;
this.socket = s;
}
public void run() {
try {
String inputLine, outputLine;
PrintWriter client_out;
BufferedReader client_in;
//set up IO to client
client_out = new PrintWriter(socket.getOutputStream(), true);
client_in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
inputLine = client_in.readLine();
if (track.numOfConnections() == 0) {
outputLine = "No resources available!";
}
else {
//send inputline to all w_threads
outputLine = "Resources was available!";
}
client_out.println(outputLine);
/*
client_out.close();
client_in.close();
//close connection
socket.close();
*/
} catch (IOException e) {
e.printStackTrace();
}
}
}
My previous question describes what I'm am trying to implement: Distributed System
I have solved this problem by storing an array of the w_threads in the shared object tracker.
private ArrayList<w_thread> threadlist = new ArrayList<w_thread>();
Meaning that from the c_thread class I now have access to all the w_threads.
for(int i=0;i<track.numOfConnections();i++) {
worker = track.get_thread(i);
worker.sendWork(inputLine);
}