i am making a java socket chat program and i made it compatible for multiple connections and when a user joins it doesn't send the message "[user] Joined" to all clients just to the one that connected but i have a thread for each client if anyone can tell me why it is only sending the message to the user that recently joined i would greatly appreciate it. Here is the server code
import java.io.*;
import java.net.*;
import java.util.ArrayList;
public class server {
public ObjectInputStream input;
public ServerSocket server;
public Socket s;
public ObjectOutputStream output;
public ArrayList<Socket> users = new ArrayList<Socket>();
public class Accept implements Runnable {
public void run() {
try {
server = new ServerSocket(55555, 100);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
s = server.accept();
users.add(s);
new EchoThread(s).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class EchoThread extends Thread {
private Socket sock;
public EchoThread(Socket s) throws IOException {
this.sock = s;
output = new ObjectOutputStream(sock.getOutputStream());
}
public void run() {
System.out.println(sock.getInetAddress() + " Connected");
try {
for(Socket s: users) {
output.writeObject(s.getInetAddress() + " Connected");
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
server() throws IOException {
Thread t = new Thread(new Accept());
t.start();
}
public static void main(String[] args) throws IOException {
new server();
}
}
So,
Every time someone connects to the server, u create a new EchoThread.
Each User has his own EchoThread.
Your Server role is to manage all the EchoThreads and Sockets.
output.writeObject(s.getInetAddress() + " Connected");
This only sends a message to ONE user.
Your Server should have a List of Sockets and send messages to every Sockets
public ArrayList<Socket> users = new ArrayList<Socket>();
public ArrayList<ObjectOutputStream> outputs = new ArrayList<ObjectOutputStream>();
public class Accept implements Runnable {
public void run() {
try {
server = new ServerSocket(55555, 100);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
s = server.accept();
users.add(s);
outputs.add(new ObjectOutputStream(s.getOutputStream()));
for (ObjectOutputStream o: outputs) {
o.writeObject(s.getInetAddress() + " has connected");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Related
At the moment i have a Server and a Client, and when the Client is connected to the Server, a Thread is created to handle all the resposnses from the respective Client and also to send any needed answers. My problem now is that i need to be able to send a message through every existent Thread to their respective Client.
I was thinking of doing it like this:
public class ServerThread extends Thread {
//ignore most of the constructor, just things i need
public ServerThread(Socket socket, int threadId, Manager manager) throws Exception {
try {
this.socket = socket;
this.threadId=threadId;
this.manager=manager;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
manager.addThread(); //This should add this Thread to the Collection in the Manager class
} catch (IOException ex) {
throw new Exception("Error", ex);
}
}
public void notify(String message){
// Do something
}
//In the end of the thread i would call manager.removeThread to remove the Thread from the Collection
}
public class Manager {
private //Thread Collection here
public Manager(){
//Initialize the collection;
}
public void addThread(){
//Add thread
}
public void removeThread(){
//Remove Thread
}
}
If this is a viable option to handle this, what Collection would i need to store the Threads and also, what would the notify(String message) method look like? It would need to call a method in Manager that would send a message to every Thread right?
If you want to create a multi-client server what is usually recommended is that in the main thread (or a separate thread) of the server class, the server will be accepting incoming Sockets (client) and with every socket accepted a new thread is created to service that client and it is better to have the service as a separate class that implements runnable or extends thread. Each service thread will be waiting for input from the client it is associated with and replying according to the client's request.
If you are looking to broadcast data to all the connected clients then what you need is to have an ArrayList that stores the client service objects and then loop over it, with every loop you send data to one of the connected clients but you have to make sure that you remove the clients that disconnected from the ArrayList otherwise it will start throwing exceptions.
usually, client service classes have the accepted socket, an input stream, and an output stream.
here is an example of a multiclient echo server that I have made maybe it will help.
public class TcpServer {
public TcpServer(){
ServerSocket server = null;
try{
server = new ServerSocket(9991);
while(!server.isClosed()){
Socket acceptedSocket = server.accept();
EchoService service = new EchoService(acceptedSocket);
service.start();
}
}catch (IOException e){
e.printStackTrace();
} finally {
if(server!=null) {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new TcpServer();
}}
This is the service class:
public class EchoService extends Thread {
private Socket acceptedSocket;
private DataInputStream is;
private DataOutputStream os;
public EchoService(Socket acceptedSocket) {
try {
this.acceptedSocket = acceptedSocket;
is = new DataInputStream(acceptedSocket.getInputStream());
os = new DataOutputStream(acceptedSocket.getOutputStream());
} catch (IOException e) {
try {
if (this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
#Override
public void run() {
super.run();
try {
while (!acceptedSocket.isClosed()) {
String usrMsg = is.readUTF();
String serverMsg = "server: "+usrMsg;
os.writeUTF(serverMsg);
os.flush();
}
} catch (IOException e) {
try {
if(this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}}
This is the same example but with the Broadcast feature included
Server class:
package TCP;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class TcpServer {
public static ArrayList<EchoService> connectedServices;
public TcpServer(){
ServerSocket server = null;
try{
server = new ServerSocket(9991);
System.out.println("server started");
connectedServices = new ArrayList<>();
while(!server.isClosed()){
Socket acceptedSocket = server.accept();
System.out.println("client connected: "
+acceptedSocket.getInetAddress());
EchoService service = new EchoService(acceptedSocket);
service.start();
}
}catch (IOException e){
e.printStackTrace();
} finally {
if(server!=null) {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
new TcpServer();
}
public static void removeConnectedService(EchoService client) {
boolean removed = connectedServices.remove(client);
System.out.println("client has been removed"+
client.getAcceptedSocket().getInetAddress()+", "+removed);
}
public static void broadCastMsg(long id, String usrMsg) throws IOException {
for(EchoService client: connectedServices){
if(client.getId()!=id)
{
String serverMsg = "server broadcast: " + usrMsg;
client.getOs().writeUTF(serverMsg);
client.getOs().flush();
}
}
}
}
service class:
package TCP;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoService extends Thread {
private Socket acceptedSocket;
private DataInputStream is;
private DataOutputStream os;
public EchoService(Socket acceptedSocket) {
try {
this.acceptedSocket = acceptedSocket;
is = new DataInputStream(acceptedSocket.getInputStream());
os = new DataOutputStream(acceptedSocket.getOutputStream());
} catch (IOException e) {
try {
if (this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
#Override
public void run() {
super.run();
try {
TcpServer.connectedServices.add(this);
while (!acceptedSocket.isClosed()) {
String usrMsg = is.readUTF();
if(usrMsg.contains("BROADCAST"))
TcpServer.broadCastMsg(this.getId(),usrMsg);
else {
String serverMsg = "server: " + usrMsg;
os.writeUTF(serverMsg);
os.flush();
}
}
} catch (IOException e) {
TcpServer.removeConnectedService(this);
try {
if(this.acceptedSocket != null)
acceptedSocket.close();
if(is != null)
is.close();
if(os != null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public DataInputStream getIs() {
return is;
}
public DataOutputStream getOs() {
return os;
}
public Socket getAcceptedSocket() {
return acceptedSocket;
}
}
Server output:
client 1 output:
client 2 output:
client 3 output:
I would create a static method getInstance(int threadId) in ServerThread.
Inside this, you create a syncronized and static Map (see class Collections).
In notify just navigate over the map and send your messages to your ServerThread instances.
(note: if it's a TreMap it will be sorted by the key)
Scenario:
a) Persistent connections
b) Manage each server-client communication individually
c) Protect System from propagating exceptions/errors
I tried to created two instances of server socket listeners using the following code :
SimpleSocketServers.java
public class SimpleSocketServers {
public static void main(String[] args) throws Exception {
int port1 = 9876;
SimpleSocketServer server1 = new SimpleSocketServer(port1);
server1.startAndRunServer();
System.out.println("Servers : server1 Listening on port: " + port1);
int port2 = 9875;
SimpleSocketServer server2 = new SimpleSocketServer(port2);
server2.startAndRunServer();
System.out.println("Servers : server2 Listening on port: " + port2);
}
}
and
SimpleSocketServer.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleSocketServer {
private ServerSocket serverSocket;
private int port;
public SimpleSocketServer(int port) {
this.port = port;
}
public void startAndRunServer() {
try {
System.out.println("Starting Server at port " + port + " ...");
serverSocket = new ServerSocket(port);
System.out.println("Listening for client connection ...");
Socket socket = serverSocket.accept();
RequestHandler requestHandler = new RequestHandler(socket);
requestHandler.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class RequestHandler extends Thread {
private Socket socket;
RequestHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
System.out.println("Client Request Response being processed...");
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
But, it creates only one instance as control is not returning from the constructor of first instance. Is there any possibility to get back control and run both instances of server socket listeners simultaneously? (ps: Pardon me, if it is wrong or trivial!)
Use 2 Different Threads, Listening To 2 Different Ports.
Thread ServerThread1 = new Thread(new Runnable() {
#Override
public void run() {
ServerSocket ServerSocketObject = null;
while(true)
{
try {
ServerSocketObject = new ServerSocket(Your_Port_Number1);
Socket SocketObject = ServerSocketObject.accept();
// Your Code Here
SocketObject.close();
} catch (IOException e) {
try {
ServerSocketObject.close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
});
Thread ServerThread2 = new Thread(new Runnable() {
#Override
public void run() {
ServerSocket ServerSocketObject = null;
while(true)
{
try {
ServerSocketObject = new ServerSocket(Your_Port_Number2);
Socket SocketObject = ServerSocketObject.accept();
// Your Code Here
SocketObject.close();
} catch (IOException e) {
try {
ServerSocketObject.close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
});
ServerThread1.start();
ServerThread2.start();
You need to have SimpleSocketServer implement Runnable; start a thread with itself as the Runnable in the constructor; and run an accept() loop in the run() method. At present you're blocking in the constructor waiting for a connection, and your servers will also only handle a single connection.
The more interesting question is why you want to provide the same service on two ports.
Trying to write - distributive simulation framework, where program is represented by an array with moving objects, server send command to move, client answer objects out of array
Goal - server send text message to each connected client separately
- client answer
Problem - can not find a way how to implement server listening and writing to one choosed client
Is there anyone, please, who can help me or get some idea?
private ServerSocket serverSocket;
private ArrayList<BufferedReader> clientBufReaders;
private ArrayList<BufferedWriter> clientBufWriters;
public static void main(String[] args) {
Server server = new Server();
}
public Server() {
try {
this.serverSocket = new ServerSocket(23456);
this.clientBufReaders = new ArrayList<BufferedReader>();
this.clientBufWriters = new ArrayList<BufferedWriter>();
this.clients();
} catch (IOException e) {
e.printStackTrace();
}
}
private void clients() {
Thread acceptThread = new Thread(new Runnable() {
private Scanner in;
public void run() {
while (true) {
try {
Socket clientSocket = serverSocket.accept();
clientBufReaders.add(new BufferedReader(new InputStreamReader(clientSocket.getInputStream())));
clientBufWriters.add(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())));
this.in = new Scanner(System.in);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
);
acceptThread.start();
while (true) {
synchronized (clientBufReaders) {
for (BufferedReader in : clientBufReaders) {
try {
if (in.ready()) {
System.out.println(in.readLine());
} else {
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
I wrote simple client serwer, but unfortunately, I did it so chaotic and poorly that I decided to write everything from scratch. I want to write to communicate in both directions with the ability to disconnect and connect a new client. It means the client or the server sends a message and an appropriate one reads it. At the beginning all works but when i want to close client i get two errors:
java.net.SocketException: Socket closed readSocketData()
java.net.SocketException: Socket closedwriteData(String data)
Of course I understand what those errors means , but I do not understand why they show up because i have a while loop in which i check if the client is connected. Later when i try to connect a new client everything is falling apart.
I wrote 3 classes client, server and communication. Client and server inherits from communication (methods for opening and reading data streams). It all looks like that:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends Communication{
ServerSocket serverSocket;
Socket listener;
boolean listenerLife;
public Server(int port) {
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.out.println(e);
}
}
public void startListener(){
while (true){
try {
listener = serverSocket.accept();
listenerLife = true;
} catch (IOException e) {
System.out.println(e);
}
openWriter(listener);
openReader(listener);
writeServerDataThread();
new Thread(new Runnable() {
#Override
public void run() {
readData();
}
}).start();
}
}
public void writeServerDataThread(){
openLocalReader();
new Thread(new Runnable() {
#Override
public void run() {
while (true){
String data = readLocalData();
writeData(data);
}
}
}).start();
}
public void readData(){
while (listenerLife){
String data = readSocketData();
if("exit".equals(data) || data == null){
try {
listenerLife = false;
listener.close();
} catch (IOException e) {
System.out.println(e);
}
}
else {
System.out.println(data);
}
}
}
public void writeData(String data){
try {
writer.writeBytes(data + '\n');
writer.flush();
} catch (IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Server server = new Server(8080);
server.startListener();
}
}
import java.io.IOException;
import java.net.Socket;
public class Client extends Communication{
Socket clientSocket;
boolean clientLive;
public Client(String hostName, int port) {
try {
clientSocket = new Socket(hostName, port);
clientLive = true;
} catch (IOException e) {
System.out.println(e + "Client(String hostName, int port)");
}
}
public boolean closeConnection(String data){
if("exit".equals(data) || data == null){
try {
writeData("Zamykam klienta");
clientSocket.close();
clientLive = false;
return false;
} catch (IOException e) {
System.out.println(e + "closeConnection(String data)");
}
}
return true;
}
public void readClientData(){
new Thread(new Runnable() {
#Override
public synchronized void run() {
openLocalReader();
while (!clientSocket.isClosed()){
String data = readLocalData();
if(closeConnection(data)){
writeData(data);
}
}
}
}).start();
}
public void readServerDataThread(){
new Thread(new Runnable() {
#Override
public synchronized void run() {
while (!clientSocket.isClosed()){
String data = readSocketData();
if(closeConnection(data)){
System.out.println(data);
}
}
}
}).start();
}
public void writeData(String data){
try {
writer.writeBytes(data + '\n');
writer.flush();
} catch (IOException e) {
System.out.println(e + "writeData(String data)");
}
}
public static void main(String[] args) {
final Client client = new Client("localhost", 8080);
client.openReader(client.clientSocket);
client.openWriter(client.clientSocket);
client.readServerDataThread();
client.readClientData();
}
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Communication {
BufferedReader reader;
BufferedReader localReader;
DataOutputStream writer;
public void openReader(Socket incomingSocket){
try {
reader = new BufferedReader(new InputStreamReader(incomingSocket.getInputStream()));
} catch (IOException e) {
System.out.println(e);
}
}
public void openWriter(Socket incomingSocket){
try {
writer = new DataOutputStream(incomingSocket.getOutputStream());
} catch (IOException e) {
System.out.println(e);
}
}
public void openLocalReader(){
localReader = new BufferedReader(new InputStreamReader(System.in));
}
public String readLocalData(){
String data = null;
try {
data = localReader.readLine();
} catch (IOException e) {
System.out.println(e + " readLocalData()");
}
return data;
}
public String readSocketData(){
String data = null;
try {
data = reader.readLine();
} catch (IOException e) {
System.out.println(e + " readSocketData()");
}
return data;
}
}
java.net.SocketException: Socket closed readSocketData()
java.net.SocketException: Socket closed writeData(String data)
Of course I understand what those errors means
They mean you closed the socket and continued to use it.
but I do not understand why they show up because i have a while loop in which i check if the client is connected.
No you don't. You have a while loop in which you check if the client socket is still open, which isn't the same thing at all ... but in any case that doesn't prevent you from using a closed socket inside the loop, for example after you close it in closeConnection(), whose return value being back to front from what it should be is doubtless causing confusion, and which is called by two threads as far as I can tell.
Hello Experts
can somebody please indentify the problem with this server why this is unable to connect more then one client
import java.io.*;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
public class MultithreadedServer extends Thread {
private ServerSocketChannel ssChannel;
private Thread tRunSer = new Thread(this, "ServerSelectThread");
public static void main(String argv[]) throws Exception {
new MultithreadedServer();
}
public MultithreadedServer() throws Exception {
this.start();
}
public void run() {
while (true) {
try {
ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
int port = 2345;
ssChannel.socket().bind(new InetSocketAddress(port));
} catch (Exception e) {
}
}
}
}
class Connect extends Thread {
private ServerSocketChannel ssChannel;
private SimManager SM;
private BallState BS = new BallState(10, 5);
public Connect(ServerSocketChannel ssChannel) {
this.ssChannel = ssChannel;
SM = new SimManager(BS);
SM.start();
}
public void run() {
try {
SocketChannel sChannel = ssChannel.accept();
while (true) {
ObjectOutputStream oos = new ObjectOutputStream(sChannel
.socket().getOutputStream());
oos.writeObject(BS);
System.out.println("Sending String is: '" + BS.X + "'" + BS.Y);
oos.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
my intention is to send the objects on network.
please help
new code:
import java.io.*;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
public class MultithreadedServer extends Thread {
private ServerSocketChannel ssChannel;
private SimManager SM;
private BallState BS = new BallState(10, 5);
private Thread tRunSer = new Thread(this, "ServerSelectThread");
public static void main(String argv[]) throws Exception {
new MultithreadedServer();
}
public MultithreadedServer() throws Exception {
this.start();
}
public void run() {
// create the server socket once
try {
ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.socket().bind(new InetSocketAddress(2345));
} catch (IOException e1) {
e1.printStackTrace();
}
while (true) {
// accept new connections on the socket
SocketChannel accept;
try {
accept = ssChannel.accept();
ObjectOutputStream oos;
oos = new ObjectOutputStream(accept.socket().getOutputStream());
oos.writeObject(BS);
System.out.println("Sending String is: '" + BS.X + "'" + BS.Y);
oos.flush();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
You are creating a new server socket for each loop iteration (using the same port over and over). You must create the server socket only once, and then accept new incoming connections.
Something like:
public void run() {
// create the server socket once
ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.socket().bind(new InetSocketAddress(2345));
while (true) {
// accept new connections on the socket
try {
SocketChannel accept = ssChannel.accept();
System.out.println("new client: " + accept.getRemoteAddress());
} catch (Exception e) {
System.out.println("exception: " + e.getMessage());
}
}
}
If you put something in your catch block you will probably find it yourself. (e.printStackTracer() might help for the time being).
Here is the reason for your NPE:
If this channel is in non-blocking mode then this method will immediately return null if
there are no pending connections.
This is from ServerSocketChannel.accept().
Your accept call returns null, and you then try to call a method on this null object.