Stopping java threads [duplicate] - java

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 4 years ago.
I wrote a java application for both Server and Client. What I want to do is stop the Client's application(and all of it's threads) when the user enters the word: "logout". I've tried everything I could find so kinda desperate here. Please send help!
Here is my code for Client.java
package client;
//Java implementation for multithreaded chat client
//Save file as Client.java
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client extends Thread
{
final static int ServerPort = 1234;
private volatile static boolean running = true;
public static void main(String args[]) throws UnknownHostException, IOException
{
Scanner scn = new Scanner(System.in);
// getting localhost ip
InetAddress ip = InetAddress.getByName("localhost");
// establish the connection
Socket s = new Socket(ip, ServerPort);
// obtaining input and out streams
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
// sendMessage thread
Thread sendMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (running) {
// read the message to deliver.
try {
String msg = scn.nextLine();
if(msg == "logout") {
running = false;
dis.close();
dos.close();
scn.close();
s.close();
Thread.currentThread().interrupt();
break;
}
dos.writeUTF(msg);
}
catch (IOException e) {
if(!running) {
System.out.println("Closing...");
System.exit(0);
}
}
} }
});
// readMessage thread
Thread readMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (running) {
// read the message sent to this client
try {
String msg = dis.readUTF();
if(sendMessage.isInterrupted()) {
running = false;
dis.close();
dos.close();
scn.close();
s.close();
Thread.currentThread().interrupt();
break;
}
System.out.println(msg);
} catch (IOException e) {
if(!running) {
System.out.println("Closing...");
System.exit(0);
}
}
}
}
});
sendMessage.start();
readMessage.start();
}
}
And this is my Server.java
package server;
//Java implementation of Server side
//It contains two classes : Server and ClientHandler
//Save file as Server.java
import java.io.*;
import java.util.*;
import java.net.*;
//Server class
public class Server
{
// Vector to store active clients
static Vector<ClientHandler> ar = new Vector<>();
// counter for clients
static int i = 0;
public static void main(String[] args) throws IOException
{
// server is listening on port 1234
ServerSocket ss = new ServerSocket(1234);
Socket s;
// running infinite loop for getting
// client request
while (true)
{
// Accept the incoming request
s = ss.accept();
System.out.println("New client request received : " + s);
// obtain input and output streams
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
System.out.println("Creating a new handler for this client...");
// Create a new handler object for handling this request.
ClientHandler mtch = new ClientHandler(s,"client " + i, dis, dos);
// Create a new Thread with this object.
Thread t = new Thread(mtch);
System.out.println("Adding this client to active client list");
// add this client to active clients list
ar.add(mtch);
// start the thread.
t.start();
// increment i for new client.
// i is used for naming only, and can be replaced
// by any naming scheme
i++;
}
}
}
//ClientHandler class
class ClientHandler implements Runnable
{
private String name;
final DataInputStream dis;
final DataOutputStream dos;
Socket s;
boolean isloggedin;
// constructor
public ClientHandler(Socket s, String name,
DataInputStream dis, DataOutputStream dos) {
this.dis = dis;
this.dos = dos;
this.name = name;
this.s = s;
this.isloggedin=true;
}
#Override
public void run() {
String received;
while (true)
{
try
{
// receive the string
received = dis.readUTF();
if(received.equals("logout")){
break;
}
// break the string into message and recipient part
StringTokenizer st = new StringTokenizer(received, "#");
String MsgToSend = st.nextToken();
String recipient = st.nextToken();
// search for the recipient in the connected devices list.
// ar is the vector storing client of active users
for (ClientHandler mc : Server.ar)
{
// if the recipient is found, write on its
// output stream
if (mc.name.equals(recipient) && mc.isloggedin==true)
{
mc.dos.writeUTF(this.name+" : "+MsgToSend);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
try
{
// closing resources
this.dis.close();
this.dos.close();
this.s.close();
this.isloggedin=false;
}catch(IOException e){
e.printStackTrace();
}
}
}
Code reference: Multithread GroupChat 1
Multithread GroupChat 2

Don't compare Strings with == but with equals(). msg == "logout" Should be msg.equals("logout").

Related

How to use existing Objects in an overwritten run() Method?

I'm a beginner in programming and do strugle a bit.
So I'm building a TCP peer to peer Chat and that requires me to divide the tasks -> Threads.
So I want to built a Thread for the "writing" part of that connection (Scanner, DataOutputStream etc.) In order to do that i implemented Runnable and that forces me to write my Thread in the overwritten run() method.
Now I have a bit of a problem, because in Order to send my messages out to the "other end (another client) I need the "socket.getOutputStream" but I cant use it in the run() method and i dont know how to fix this problem, sitting already a week on this problem. Any ideas ?
public class ClientHorcher implements Runnable {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(11111);
System.out.println("Waiting For Connection:-");
Socket socket = serverSocket.accept();
Scanner scanner = new Scanner(System.in);
DataInputStream datenRein = new DataInputStream(socket.getInputStream());
DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
String nickname;
System.out.print("Gib einen Nickname ein: ");
nickname = scanner.nextLine();
while (true) {
String vonMsg = datenRein.readUTF(in);
System.out.println("Client:-" + vonMsg);
if (vonMsg.equals("exit")) {
System.out.println("Beenden!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
serverSocket.close();
System.exit(0);
}
System.out.print(nickname + ":-");
String zuMsg = scanner.nextLine();
datenRaus.writeUTF(zuMsg);
if (zuMsg.equals("exit")) {
System.out.println("Quiting!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
serverSocket.close();
System.exit(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
}
}`
`public class ClientVerbinder implements Runnable {
public static void main(String[] args) {
try {
Socket socket = new Socket("Localhost", 11111);
System.out.println("Connected");
Scanner scanner = new Scanner(System.in);
DataInputStream datenRein = new DataInputStream(socket.getInputStream());
DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
String nickname;
System.out.print("Gib einen Nickname ein: ");
nickname = scanner.nextLine();
while (true) {
System.out.print(nickname+":-");
String zuMsg = scanner.nextLine();
datenRaus.writeUTF(zuMsg);
if (zuMsg.equals("exit")) {
System.out.println("Beenden!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
System.exit(0);
}
String vonMsg = datenRein.readUTF();
System.out.println("CLient"+":-" + vonMsg);
if (vonMsg.equals("exit")) {
System.out.println("Quiting!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
System.exit(0);
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
}
}
Multiple possibilities.
Use static variables. Normally you would not do that, but because your code is all-static, you could
Use member variables in an OO-style code.
If you wanted to do it properly, you'd split the server into two parts:
The ServerSocket listener that only listens to connections (Socket connectionToClient = ss.accept), and whenever a connection comes in, creates a new
ClientHandler, passes in the Socket, and the ClientHandler then starts its own thread internally
This way, the ClientHandler has all the data it needs (again as member variables) and can work on its own concerns (aka 'separation of concerns).
Update
This is what I created. Really simple.
Start Server
Start 1st client
Start 2nd client
In any client, type message
Other client receives it
Classes:
SimpleServer
package stackoverflow.simplemtserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingDeque;
public class SimpleServer { // make it closeable and close sockets if this is not standalone
public static void main(final String[] args) throws IOException {
final int port = 7623;
new SimpleServer(port);
}
final LinkedBlockingDeque<SimpleServerClientHandler> clientHandlers = new LinkedBlockingDeque<>();
private final ServerSocket mServerSocket;
public SimpleServer(final int pPort) throws IOException {
mServerSocket = new ServerSocket(pPort);
final Thread m = new Thread(() -> runLoop(), getClass().getSimpleName() + " Main Loop");
m.start();
}
private void runLoop() {
while (true) {
try {
System.out.println("Server waiting for connection...");
#SuppressWarnings("resource") final Socket cs = mServerSocket.accept(); // do NOT close the socket here, no try-resource, will interrupt threaded communication!
final SimpleServerClientHandler ch = new SimpleServerClientHandler(this, cs);
clientHandlers.add(ch);
System.out.println("Connection accepted, handler started. Handlers active: " + clientHandlers.size());
} catch (final IOException e) {
// handle this how you need it
e.printStackTrace();
}
}
}
public void signOffClientHandler(final SimpleServerClientHandler pClientHandler) {
clientHandlers.remove(pClientHandler); // we could also accommplish this using stack trace to avoid access from outside, but this is the easier solution
}
public void spreadMessageToClients(final String pMessageFromClient, final SimpleServerClientHandler pSimpleServerClientHandler) {
for (final SimpleServerClientHandler ch : clientHandlers) {
if (ch != pSimpleServerClientHandler) ch.relayMessageToClient(pMessageFromClient); // we can work with identity == and != here
}
}
}
SimpleServerClientHandler
package stackoverflow.simplemtserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class SimpleServerClientHandler {
private final SimpleServer mParentServer;
private final Socket mClientSocket;
private final DataInputStream mDIS;
private final DataOutputStream mDOS;
public SimpleServerClientHandler(final SimpleServer pSimpleServer, final Socket pCS) throws IOException {
mParentServer = pSimpleServer;
mClientSocket = pCS;
mDIS = new DataInputStream(mClientSocket.getInputStream());
mDOS = new DataOutputStream(mClientSocket.getOutputStream());
final Thread t = new Thread(() -> runComms(), getClass().getSimpleName() + " Comms Loop");
t.setDaemon(true); // threads now stop once server stops. this is NOT a soft exit
t.start();
}
private void runComms() {
try {
try {
while (true) {
// do all your logic here, work with DIS and DOS
final String messageFromClient = mDIS.readUTF();
if (messageFromClient == null) break;
if (!messageFromClient.startsWith("*")) mParentServer.spreadMessageToClients(messageFromClient, this);
}
} catch (final Exception e) {
// TODO: handle exception
}
} finally {
try {
mClientSocket.close(); // also closes DataIn/Out
} catch (final IOException e) { /* ignore */ }
mParentServer.signOffClientHandler(this);
}
}
public void relayMessageToClient(final String pMessageFromClient) {
try {
mDOS.writeUTF("*" + pMessageFromClient);
} catch (final IOException e) {
// ignore unless needed otherwise
}
}
}
SimpleClient
package stackoverflow.simplemtserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class SimpleClient {
public static void main(final String[] args) throws UnknownHostException, IOException {
final String hostname = "localhost";
final int port = 7623;
try (final Socket s = new Socket(hostname, port);
final DataInputStream dis = new DataInputStream(s.getInputStream());
final DataOutputStream dos = new DataOutputStream(s.getOutputStream());
final Scanner scanner = new Scanner(System.in);) {
final Thread t = new Thread(() -> runListenerLoop(dis), SimpleClient.class.getSimpleName() + " Reader Thread");
t.setDaemon(true);
t.start();
while (true) {
System.out.println("Enter message:");
System.out.flush();
final String msg = scanner.nextLine();
if (msg == null) break;
System.out.println("Spreading message: " + msg);
dos.writeUTF(msg);
}
}
}
private static void runListenerLoop(final DataInputStream pDis) {
while (true) {
try {
System.out.println("Waiting for incoming messages...");
final String msg = pDis.readUTF();
System.out.println("Received: " + msg);
} catch (final SocketException e) {
// if ("java.net.SocketException: Connection reset".equals(e.getMessage()))
break;
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
From here on, there's now more ways you can extend this client/server communication:
use opcodes (read/write int constants or enums before data) to distinguish for special operations and/or messages (like this here puts an asterisk in front of the string to prevent re-re-laying the same message indefinitely over the network)
read multiple strings for user, message, additional options
implement this is a user friendly UI so you dont have to use console I/O
Update 2
The pure peer-to-peer solution is this one.
If the app is run without params, it goes into listening mode, waiting for a connection.
If the app is run with one arguments, it interprets it as listening port and also goes into listening mode.
If the app is un with [hostname] [port] arguments, it will try to connect there
Example:
start first app without arguments (listening)
start second app with arguments "localhost 7642" (connecting)
both apps will now
connect,
then set up I/O resources,
then start the listening thread for incoming messages
then go into the read-keyboard-and-write-to-socket loop
now you can type a message in one of the apps, the other one will receive it
p2p code:
package stackoverflow.simplemtserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class SimplePeerToPeerClient {
static public final int DEFAULT_PORT = 7642;
public static void main(final String[] args) throws UnknownHostException, IOException {
if (args.length == 0) {
System.out.println("Waiting on default port " + DEFAULT_PORT);
waitForConnection(DEFAULT_PORT);
} else if (args.length == 1) {
final int port = Integer.parseInt(args[0]);
System.out.println("Waiting on port " + port);
waitForConnection(port);
} else if (args.length == 2) {
final String hostName = args[0];
final int port = Integer.parseInt(args[1]);
System.out.println("Connecting to " + hostName + " on port " + port);
connectToOtherSide(hostName, port);
} else throw new IllegalArgumentException("Invalid amount of argument! Need none (listen) or 2: [hostname] [port] (connect)");
}
private static void waitForConnection(final int pPort) throws IOException {
try (final ServerSocket ss = new ServerSocket(pPort);) {
#SuppressWarnings("resource") final Socket socket = ss.accept(); // will get closed later
startComms(socket);
} // closes ServerSocket after 1st connection
}
private static void connectToOtherSide(final String pHostName, final int pPort) throws UnknownHostException, IOException {
#SuppressWarnings("resource") final Socket socket = new Socket(pHostName, pPort); // will get closed later
startComms(socket);
}
private static void startComms(final Socket pSocket) throws IOException {
try (
final DataInputStream dis = new DataInputStream(pSocket.getInputStream());
final DataOutputStream dos = new DataOutputStream(pSocket.getOutputStream());
final Scanner scanner = new Scanner(System.in);) {
// run the listener loop
final Thread t = new Thread(() -> runListenerLoop(dis), SimpleClient.class.getSimpleName() + " Reader Thread");
t.setDaemon(true);
t.start();
// run my keyboard-input-send loop
while (true) {
System.out.println("Enter message:");
System.out.flush();
final String msg = scanner.nextLine();
if (msg == null) break; // empty input ends client
System.out.println("Spreading message: " + msg);
dos.writeUTF(msg);
}
} finally {
try {
pSocket.close();
} catch (final IOException e) { /* ignore */ }
}
}
private static void runListenerLoop(final DataInputStream pDis) {
while (true) {
try {
System.out.println("Waiting for incoming messages...");
final String msg = pDis.readUTF();
System.out.println("Received: " + msg);
} catch (final SocketException e) {
// if ("java.net.SocketException: Connection reset".equals(e.getMessage()))
break;
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

In java socket programming chat application, Is it possible to create a individual chat for each clients like whatsapp?

Now I'm done with the application which have the server and client, server accepts the client request and add the client object into the Arraylist and starts a new thread for each clients. when multiple clients connects, clients can list all the clients, and they can send a message to any clients in the list. For example client1, client2, client3 connects to the server client1 and client2 sending a message to the client3,It will be printed in client3 console. all working fine. Now i need to add additional feature that each clients sends a message in individual chat, if client1 opens a chat with client2 the conversation between those two clients only should be displayed, not client3 messages, and vice versa. To do that implementation do i need any additional concept like multi threading. I'm not asking a source code, I'm just asking a idea to implement the above feature.
Can anyone tell me the suggestion or reference to implement separate chats for different clients... Need to keep the old messages until the server goes offline?
Server.java
package server;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.*;
import java.util.Vector;
public class Server {
static Vector<ClientHandler> AllClients = new Vector<ClientHandler>();
public static void main(String args[]) throws Exception {
try {
ServerSocket ss = new ServerSocket(1111);
System.out.println("Server Started");
while(true) {
Socket s = ss.accept();
DataInputStream dis = new DataInputStream(s.getInputStream());
String clientname = dis.readUTF();
System.out.println("Connected With : "+clientname);
ClientHandler client = new ClientHandler(s,clientname);
Thread t = new Thread(client);
AllClients.add(client);
t.start();
System.out.println("Ready to accept connections...");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientHandler.java
package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientHandler extends Thread{
private DataInputStream in;
private DataOutputStream out;
private String ClientName;
private boolean login;
private Socket Socket;
Scanner sc = new Scanner(System.in);
ClientHandler(Socket s,String name) throws Exception{
this.in = new DataInputStream(s.getInputStream());
this.out = new DataOutputStream(s.getOutputStream());
this.login = true;
this.ClientName = name;
this.Socket = s;
}
public void run() {
while(true) {
try {
String received = in.readUTF();
if(received.equalsIgnoreCase("logout")) {
this.login = false;
this.out.writeUTF("logout");
int i;
for(i = 0; i < Server.AllClients.size(); i++) {
if(this.ClientName.equals(Server.AllClients.get(i).ClientName))
break;
}
Server.AllClients.remove(i);
System.out.println(this.ClientName+" logged out");
this.Socket.close();
break;
}
if(received.equalsIgnoreCase("getlist")) {
for(int i = 0; i < Server.AllClients.size(); i++) {
out.writeUTF(i+1 +", "+Server.AllClients.get(i).ClientName);
}
continue;
}
if(received.contains(",")) {
String[] Message = received.split(",");
for(ClientHandler c : Server.AllClients) {
if(c.ClientName.equalsIgnoreCase(Message[1]) && c.login) {
c.out.writeUTF(this.ClientName +" : "+ Message[0]);
c.out.flush();
break;
}
}
}
}catch(Exception e) {
System.out.println("Error :"+e.getMessage());
}
}
try {
this.in.close();
this.out.close();
}catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
Client.java
package client;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client {
static DataInputStream dis;
static DataOutputStream dos;
static Socket s;
public static void main(String args[])throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("Enter Cient Name : ");
String name = sc.nextLine();
s = new Socket("localhost",1111);
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(name);
Thread sendMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (true) {
String msg = sc.nextLine();
try {
dos.writeUTF(msg);
if(msg.equalsIgnoreCase("logout")) {
System.out.println("Logged out");
break;
}
} catch (IOException e) {
System.out.println("Error in send method :"+e.toString());
}
}
}
});
Thread readMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (true) {
try {
String msg = dis.readUTF();
if(msg.equalsIgnoreCase("logout")) {
System.out.println("Logged out");
break;
}
System.out.println(msg);
} catch (IOException e) {
System.out.println("Error in read method :"+e.getMessage());
}
}
}
});
sendMessage.start();
readMessage.start();
}
}
If my code have any irrelevant statements please do suggest a better way to optimise the code
The first answer is: yes it is possible.
The second answer: it's not about threading, you have to think in the first place (it's important, but not in the frist place).
the third answer: as i understand your code, the main data-structre is the collection of clients and their handler. In my opinion there is a further abstraction-layer missing in between.
In the frist place think about a data structure like "chatRoom". A client connecting to server has to send a "chatRoom"-name to the the server. Than the server creates the chatRoom or adds the client to the chatRooom's client-set. From that point a client can send his messages to the chatRoom not to the client directly anymore.
In a further step: To enable sending messages to inidividual clients you can e.g. enforce a chatRoom for every pair of clients (take care: this can be very expansive), so individual communication between clients is still possible.

Server won't connect to more than one client (Java)

my server class
import java.net.*;
import java.io.*;
public class server
{
private Socket socket;
private ServerSocket server;
// constructor with port
public void start(int port){
try {
server = new ServerSocket(port);
while(true){
socket = server.accept();
new ConnectionHandler(socket).run();
}
}catch(IOException i){
}
}
}
class ConnectionHandler implements Runnable{
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream in = null;
public ConnectionHandler(Socket socket){
this.socket=socket;
}
#Override
public void run() {
InputStream inp = null;
BufferedReader brinp = null;
DataOutputStream out = null;
try
{
System.out.println("Waiting for a client ...");
System.out.println(server);
System.out.println("Client accepted");
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String line = "";
// reads message from client until "Over" is sent
while (!line.equals("Over"))
{
try
{
line = in.readUTF();
System.out.println(line);
}
catch(IOException i)
{
System.out.println(i);
}
}
System.out.println("Closing connection");
// close connection
socket.close();
in.close();
}
catch(IOException i)
{
System.out.println(i);
}
}
public static void main(String[] args) {
server serverr = new server();
serverr.start(4000);
}
}
Here's my client class.
import java.net.*;
import java.io.*;
public class Client
{
// initialize socket and input output streams
private Socket socket = null;
private DataInputStream input = null;
private DataOutputStream out = null;
// constructor to put ip address and port
public Client(String address, int port)
{
// establish a connection
try
{
socket = new Socket(address, port);
System.out.println("Connected");
// takes input from terminal
input = new DataInputStream(System.in);
// sends output to the socket
out = new DataOutputStream(socket.getOutputStream());
}
catch(UnknownHostException u)
{
System.out.println(u);
}
catch(IOException i)
{
System.out.println(i);
}
// string to read message from input
String line = "";
// keep reading until "Over" is input
while (!line.equals("Over"))
{
try
{
line = input.readLine();
out.writeUTF(line);
}
catch(IOException i)
{
System.out.println(i);
}
}
// close the connection
try
{
input.close();
out.close();
socket.close();
}
catch(IOException i)
{
System.out.println(i);
}
}
public static void main(String args[])
{
Client client = new Client("127.0.0.1", 4000);
}
}
Trying to develop pretty simple chat application works via terminal, but I think there are plenty of bugs I have in my code.
The server can handle one client, but when another client comes up it doesn't connect to other clients.
What am I have to do now?
I couldn't find out where my problem is, waiting your helps.
Note: I am completely new to socket programming concept.
The ConnectionHandler class is a thread class, and you must wrap its object to a Thread instance and then call start() instead of run().
So in the Server class change
new ConnectionHandler(socket).run();
with
new Thread(ConnectionHandler(socket)).start();

Java Client Server Chat application loses connection

I recently wrote a socket communication program in java where two threads run concurrent on each server and client side handling the read and write operations to the socket allowing continuous message sending and receiving on both sides.
The problem is either of the client or the server stops receiving communication from the other side and then after a while both of them stop working. I can't figure out what's wrong and how the connection is dropping :/
Code for server
import java.net.*;
import java.io.*;
import java.util.Scanner;
public class Server
{
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream in = null;
private DataOutputStream out = null;
private Scanner inp = null;
String line = "";
String iline = "";
public Server(int port)
{
try
{
server = new ServerSocket(port);
System.out.println("Server started");
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted");
// takes input from the client socket
out=new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(new
BufferedInputStream(socket.getInputStream()));
inp = new Scanner(System.in);
while (true)
{
new Thread(new Runnable(){
public void run()
{
try{
while(true){
line = in.readUTF();
System.out.println("Client : "+line);
if(socket.isClosed()||socket.isOutputShutdown()||socket.isInputShutdown())
{
System.out.println("DED");
System.exit(0);
}
}
}
catch(Exception e){
System.out.println("Exception !!!");
}
}
}).start();
iline=inp.nextLine();
out.writeUTF(iline);
if(socket.isClosed()||socket.isOutputShutdown()||socket.isInputShutdown()){
System.out.println("DED");
System.exit(0);
}
}
}
catch(IOException i)
{
System.out.println(i);
}
}
public static void main(String args[])
{
Server server = new Server(5000);
}
}
Code for Client
import java.net.*;
import java.io.*;
import java.util.Scanner;
class Client{
private Socket socket =null;
private DataInputStream inp=null;
private DataOutputStream out=null;
private Scanner in=null;
String line="";
String iline="";
Client(String address,int port)
{
try{
socket = new Socket(address,port);
in= new Scanner(System.in);
out = new DataOutputStream(socket.getOutputStream());
inp = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
while(true){
line=in.nextLine();
out.writeUTF(line);
new Thread(new Runnable(){
public void run()
{
try{
while(true){
iline=inp.readUTF();
System.out.println("Server : "+iline);
if(socket.isClosed()||socket.isOutputShutdown()||socket.isInputShutdown()){
System.out.println("DED");
System.exit(0);
}
}
}
catch(Exception e){
System.out.println("Exception !!!");
}
}
}).start();
if(socket.isClosed()||socket.isOutputShutdown()||socket.isInputShutdown()){
System.out.println("DED");
System.exit(0);
}
}
}
catch(UnknownHostException u)
{
System.out.println(u);
}
catch(Exception e){
System.out.println("EXCEPTION!!!");
}
}
}
class ClientSocket{
public static void main(String...args){
Client obj = new Client("127.0.0.1", 5000);
}
}
Just an initial run through your code what I see is in the first while(true){} , you are spawning a thread calling start method on it . The moment you start the reading thread the main thread checks fo sockets conditions and moves ahead. Since there is a true in your first while(true) a new thread is again spawned and that goes on an on until the socket is closed where the programs terminates because of system.exit call.

Java Socketing: My server class constantly takes in input but my client doesn't?

Try to do some concurrent messaging between the server and the client. When they first connect to eachother and the Server sends the test string, the client gets it perfectly fine the first time. And the client can SEND messages just fine to the Server. But my Client class cant constantly check for messages like my Server can and idk what's wrong. Any suggestions?
Server class code:
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.Random;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
String testMessage = "You are now connected and can begin chatting!";
boolean connected = false;
int port;
public Server(int port) {
this.port = port;
}
public void Open() {
//creates Threadpool for multiple instances of chatting
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
System.out.println("Opening...");
ServerSocket srvr = new ServerSocket(port);
while (true) {
Socket skt = srvr.accept();
clientProcessingPool.submit(new ClientTask(skt));
}
} catch (Exception e) {
try {
System.out.println(e);
System.out.print("You're opening too many servers in the same location, fool!\n");
ServerSocket srvr = new ServerSocket(port);
while (true) {
Socket skt = srvr.accept();
clientProcessingPool.submit(new ClientTask(skt));
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
private class ClientTask implements Runnable {
private final Socket skt;
private ClientTask(Socket skt) {
this.skt = skt;
}
#Override
public void run() {
//for sending messages
if (connected == false) {
System.out.println("======================");
System.out.println("Server has connected!");
processMessage(testMessage);
}
//for receiving messages
while (true) {
try {
// Read one line and output it
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String incomingMessage = br.readLine();
if (incomingMessage != null) {
System.out.println("Server: Received message: " + incomingMessage);
processMessage(incomingMessage);
}
//br.close();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.println("Server had error receiving message.");
System.out.println("Error: " + e);
}
}
}
//for processing a message once it is received
public void processMessage(String message) {
PrintWriter out = null;
try {
out = new PrintWriter(skt.getOutputStream(), true);
} catch (IOException ex) {
System.out.println(ex);
System.out.println("Server had error sending message.");
}
System.out.print("Server: Sending message: " + message + "\n");
out.print(message);
out.flush();
connected = true;
try {
skt.shutdownOutput();
//out.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Client class code:
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
class Client {
public String message;
Socket skt;
public int port;
public Client(int port) {
this.port = port;
}
//for receiving messages from Server
public void receiveMessage() {
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
skt = new Socket(InetAddress.getLocalHost().getHostName(), port);
while (true) {
clientProcessingPool.submit(new Client.ClientTask(skt));
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
//for sending messages to Server
public void sendMessage(String outgoingMessage) throws IOException {
try {
skt = new Socket(InetAddress.getLocalHost().getHostName(), port);
PrintWriter pw = new PrintWriter(skt.getOutputStream());
System.out.println("Client: Sending message: " + outgoingMessage);
pw.print(outgoingMessage);
pw.flush();
skt.shutdownOutput();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.println(e);
System.out.print("Client had error sending message.\n");
JOptionPane.showMessageDialog(null, "That User is not currently online.", "ERROR!!", JOptionPane.INFORMATION_MESSAGE);
}
}
private class ClientTask implements Runnable {
private final Socket skt;
private ClientTask(Socket skt) {
this.skt = skt;
}
#Override
public void run() {
while (true) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(skt.getInputStream()));
//while (!in.ready()) {}
String incomingMessage = in.readLine();
if (incomingMessage != null) {
System.out.println("Client: Received message: " + incomingMessage); // Read one line and output it
message = incomingMessage;
}
//skt.shutdownInput();
//in.close();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.print("Client had error receiving message.\n");
}
}
}
}
}
Streams cannot be re-wrapped. Once assigned to a wrapper, they must use that wrapper for the entire life-cycle of the stream. You also shouldn't close a stream until you are done using it, which in this case isn't until your client and server are done communicating.
In your current code, there are a few times where you re-initialize streams:
while (true) {
try {
//Each loop, this reader will attempt to re-wrap the input stream
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String incomingMessage = br.readLine();
if (incomingMessage != null) {
System.out.println("Server: Received message: " + incomingMessage);
processMessage(incomingMessage);
}
//don't close your stream and socket so early!
br.close();
skt.close();
} catch (Exception e) {
//...
}
You get the idea; you can use this knowledge to find the stream problems in your client code as well.
With that said, servers are the middle-man between multiple clients. If you want to be able to type in the server's console to send a message to clients, it shouldn't go to only 1 client (unless you had a system that allowed you to specify a name). You need to store every connection in some kind of collection so when you type in the server's console, it goes to every client that's connected. This also helps when a client wants to send a message to every other client (global message). The server's main thread is primarily for accepting clients; I created another thread to allow you to type in the console.
As for your streams, you should create them whenever you start the ClientTask, both server side and client side:
public class Server {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private Set<User> users = new HashSet<>();
private boolean running;
private int port;
public Server(int port) {
this.port = port;
}
public void start() {
running = true;
Runnable acceptor = () -> {
try(ServerSocket ss = new ServerSocket(port)) {
while(running) {
User client = new User(ss.accept());
users.add(client);
executor.execute(client);
}
} catch(IOException e) {
//if a server is already running on this port;
//if the port is not open;
e.printStackTrace();
}
};
Runnable userInputReader = () -> {
try(Scanner scanner = new Scanner(System.in)) {
while(running) {
String input = scanner.nextLine();
for(User user : users) {
user.send(input);
}
}
} catch(IOException e) {
//problem sending data;
e.printStackTrace();
}
};
Thread acceptorThread = new Thread(acceptor);
Thread userThread = new Thread(userInputReader);
acceptorThread.start();
userThread.start();
}
public void stop() {
running = false;
}
public static void main(String[] args) {
new Server(15180).start();
System.out.println("Server started!");
}
}
In the run() method is where the streams should be wrapped.
class User implements Runnable {
private Socket socket;
private boolean connected;
private DataOutputStream out; //so we can access from the #send(String) method
public User(Socket socket) {
this.socket = socket;
}
public void run() {
connected = true;
try(DataInputStream in = new DataInputStream(socket.getInputStream())) {
out = new DataOutputStream(socket.getOutputStream());
while(connected) {
String data = in.readUTF();
System.out.println("From client: "+data);
//send to all clients
}
} catch(IOException e) {
//if there's a problem initializing streams;
//if socket closes while attempting to read from it;
e.printStackTrace();
}
}
public void send(String message) throws IOException {
if(connected) {
out.writeUTF(message);
out.flush();
}
}
}
It's pretty much the same idea with the client:
1. Connect to Server
2. Create "communication" thread
3. Create "user input" thread (to receive input from console)
4. Start threads
public class Client {
private final String host;
private final int port;
private boolean connected;
private Socket socket;
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws IOException {
connected = true;
socket = new Socket(host, port);
Runnable serverInputReader = () -> {
try (DataInputStream in = new DataInputStream(socket.getInputStream())) {
while (connected) {
String data = in.readUTF();
System.out.println(data);
}
} catch (IOException e) {
// problem connecting to server; problem wrapping stream; problem receiving data from server;
e.printStackTrace();
}
};
Runnable userInputReader = () -> {
try (DataOutputStream out = new DataOutputStream(socket.getOutputStream());
Scanner scanner = new Scanner(System.in)) {
while (connected) {
String input = scanner.nextLine();
out.writeUTF(input);
}
} catch (IOException e) {
//problem wrapping stream; problem sending data;
e.printStackTrace();
}
};
Thread communicateThread = new Thread(serverInputReader);
Thread userThread = new Thread(userInputReader);
communicateThread.start();
userThread.start();
}
public static void main(String[] args) throws IOException {
new Client("localhost", 15180).start();
}
}
There are a few things I used in the code above that you may not be familiar with. They help simplify the syntax for your code:
Lambda Expressions - Prevents the need to create an anonymous class (or subclass) to declare a method
Try-With-Resources - Closes the resources specified automatically once the try block as ended
EDIT
When a user connects, you should store their connection by name or id. That way, you can send data to specific users. Even if your client is running on the same machine as the server, it's still the same idea: client connects to server, server sends message to client based on name or id:
while(running) {
User client = new User(ss.accept());
users.add(client); //add to set
executor.execute(client);
}
Right now, you are simply adding users to a Set. There is currently no way to grab a specific value from this set. What you need to do is give it some kind of "key". To give you an idea, here's an old algorithm I used to use. I have an array full of empty slots. When someone connects, I look for the first empty slot. Once an empty slot is found, I pass the user the index of the array it's being stored at (that will be the user's id), then store the user in the array at the specified index. When you need to send a message to someone, you can use the id to access that specific array index, grab the user you want and send a message:
class Server {
private int maxConnections = 10;
private ExecutorService executor = Executors.newFixedThreadPool(maxConnections);
private User[] users = new User[maxConnections];
//...
while(running) {
Socket socket = ss.accept();
for(int i = 0; i < users.length; i++) {
if(users[i] == null) {
users[i] = new User(socket, i);
executor.execute(users[i]);
break;
}
}
}
//...
public static void sendGlobalMessage(String message) throws IOException {
for(User user : users)
if(user != null)
user.send(message);
}
public static void sendPrivateMessage(String message, int id) {
User user = users[id];
if(user != null) {
user.send(message);
}
}
}
class User {
private Socket socket;
private int id;
private DataOutputStream out;
public User(Socket socket, int id) {
this.socket = socket;
this.id = id;
}
public void send(String message) throws IOException {
out.writeUTF(message);
out.flush();
}
public void run() {
DataInputStream in;
//wrap in and out streams
while(connected) {
String data = in.readUTF();
//Server.sendGlobalMessage(data);
//Server.sendPrivateMessage(data, ...);
sendMessage(data); //sends message back to client
}
}
}

Categories