This question already has answers here:
Official reasons for "Software caused connection abort: socket write error"
(14 answers)
Closed 9 years ago.
There are two computers, A and B, each one of them is waiting for the other one to tell him that is ready, when they receive the message they'll start doing something.
public class SyncClientImpl implements SyncClient, Runnable {
private Socket s;
private String ipAddress;
private int port;
private boolean otherIsReady;
private Thread thread;
private OutputStream os;
private ObjectOutputStream oos;
public Thread getThread() {
return thread;
}
public void setThread(Thread thread) {
this.thread = thread;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public boolean isOtherIsReady() {
return otherIsReady;
}
public void setOtherIsReady(boolean otherIsReady) {
this.otherIsReady = otherIsReady;
}
public Socket getS() {
if (s == null) {
try {
s = new Socket(ipAddress, port);
} catch (UnknownHostException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
return s;
}
public void setS(Socket s) {
this.s = s;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
#Override
public void send(Object o, int port, String ipAdrress) {
try {
os = this.getS().getOutputStream();
oos = new ObjectOutputStream(os);
oos.flush();
oos.writeObject(o);
oos.flush();
} catch (IOException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void update() {
otherIsReady = true;
}
#Override
public void run() {
try {
while (!otherIsReady) {
try {
this.send("ready", port, ipAddress);
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
oos.close();
os.close();
s.close();
} catch (IOException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
This first class sends the message "ready" to a server, it will stop doing it until someone else notify it.
The class that will notify it is this one:
public class SyncServerImpl implements SyncServer, Runnable {
private ServerSocket ss;
private Socket s;
private String ipAddress;
private int port;
private InputStream is;
private ObjectInputStream ois;
private boolean confirmReceived;
private Thread thread;
private transient List<Observer> list = new ArrayList<Observer>();
private Object lock;
public boolean isConfirmReceived() {
return confirmReceived;
}
public void setConfirmReceived(boolean confirmReceived) {
this.confirmReceived = confirmReceived;
}
#Override
public void setLock(Object lock) {
this.lock = lock;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public Socket getS() {
if (s == null) {
try {
s = this.getSS().accept();
} catch (UnknownHostException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
return s;
}
public void setS(Socket s) {
this.s = s;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public ServerSocket getSS() {
if (ss == null) {
try {
ss = new ServerSocket(port);
} catch (IOException ex) {
Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
return ss;
}
public void setSS(ServerSocket ss) {
this.ss = ss;
}
#Override
public void addObserver(Observer observer) {
list.add(observer);
}
#Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
#Override
public void notifyObservers() {
for (Observer observer : list) {
observer.update();
}
}
public void receive() {
try {
is = this.getS().getInputStream();
ois = new ObjectInputStream(is);
String to = (String) ois.readObject();
if (to.equalsIgnoreCase("ready")) {
synchronized (lock) {
confirmReceived = true;
this.notifyObservers();
lock.notifyAll();
}
System.out.println("packet received");
}
} catch (IOException ex) {
Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
try {
while (!confirmReceived) {
this.receive();
}
ois.close();
is.close();
s.close();
ss.close();
} catch (Exception ex) {
Logger.getLogger(SyncServerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String args[]) {
final Object lock = new Object();
SyncServerImpl ss = new SyncServerImpl();
SyncClientImpl sc = new SyncClientImpl();
ss.setLock(lock);
ss.addObserver(sc);
ss.setPort(2002);
ss.start();
sc.setIpAddress("192.168.1.101");
sc.setPort(2002);
sc.start();
synchronized (lock) {
while (!ss.isConfirmReceived()) {
try {
lock.wait();
} catch (InterruptedException ex) {
}
}
}
System.out.println("Ok");
}
}
This Server is waiting for the message "ready" to arrive, when it comes it will notify the other class which will stop sending packets, and will notify the main thread waiting on the lock.
It works fine on the localhost but not on my LAN.
I have a mac and a pc, if I start the main method first from the pc and then from the mac, I get this error (from the mac, which will iterate endlessly).
sync.SyncClientImpl send
GRAVE: null
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1864)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1773)
at java.io.ObjectOutputStream.<init>(ObjectOutputStream.java:229)
at tetris.logic.online.sync.SyncClientImpl.send(SyncClientImpl.java:87)
at tetris.logic.online.sync.SyncClientImpl.run(SyncClientImpl.java:106)
at java.lang.Thread.run(Thread.java:695)
while of the pc it reports me that the connection is refused (but it's ok because it starts first)
If I start first on the mac and the on the pc, I get this error (from the pc) which will iterate endlessly too:
sync.SyncClientImpl send
GRAVE: null
java.net.SocketException: Software caused connection abort: socket write error
...
at tetris.logic.online.sync.SyncClientImpl.send(SyncClientImpl.java:87)
at tetris.logic.online.sync.SyncClientImpl.run(SyncClientImpl.java:106)
at java.lang.Thread.run(Thread.java:695)
This error looks like to be the same of one above but described in a different manner.
Does any one knows what is causing this error?
Try to simplify your solution, and take a look at the following article on socket programming: Writing the Server Side of a Socket.
Try to make it work one way first before attempting to do it in both directions (although the need for that feature isn't quite clear to me). Right now the client & server threads within the same applications are interfering with the client/server pair you're trying to set up over the network.
If you only want to send text over the socket just use BufferedReader and PrintWriter instead of ObjectStreams (latter could get you into memory issues if not managed properly).
#Override
public void send(String line, int port, String ipAdrress) {
try {
Socket clientSocket = new Socket(ipAddress, port);
os = clientSocket.getOutputStream();
PrintWriter out= new PrintWriter(os, true);
out.println(line);
out.close();
clientSocket.close();
} catch (IOException ex) {
Logger.getLogger(SyncClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
If you only want to use the connection for checking if the other is ready than closing the Socket is ok, but if you'd want to keep the connection open you need to keep the OutputStream (not the Socket itself) for further processing in the Thread. Again, take a look at the article above and work from there.
Related
I have a multithreaded tcp server, that handles multiple clients.
Each client has its thread on the serverside that keeps the socket connection.
Everything theoretically works fine for many minutes, but at rare occasions, while having multiple clients connected, the following happens:
One of the clients sends a tcp packet to the server and the serverside read times out. I have found many questions, that tackle read timeouts on the clientside, but in my case, this never happens. In my case, the server times out on a read when receiving a packet from a client.
My question is, why and how can this happen and what can I do to handle this problem?
here is my server listener:
public class GameServerTCP extends Thread {
//TCP
private ServerSocket serverSocket;
public Server server;
public int amountOfTCPConnections = 0;
ClassLoader classLoader = getClass().getClassLoader();
File myFile = new File(classLoader.getResource("Sprites/sprite_sheet.png").getFile());
public GameServerTCP(Server game) {
this.server = game;
//TCP
try {
serverSocket = new ServerSocket(6336);
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(true) {
//TCP
Socket socket = null;
try {
socket = serverSocket.accept();
Toolkit.getDefaultToolkit().beep();
System.out.println(socket.getRemoteSocketAddress() + " has connected to server.");
}
catch (Exception e) {
e.printStackTrace();
}
new TCPConnection(socket, this);
amountOfTCPConnections++;
if (amountOfTCPConnections > 500) {
System.err.println("Too many clients error! (unsolved)");
server.frame.dispatchEvent(new WindowEvent(server.frame, WindowEvent.WINDOW_CLOSING));
}
}
}
}
here is my server thread that hold each single connection:
public class TCPConnection implements Runnable {
Socket socket;
private Thread thread;
private boolean isRunning = false;
public GameServerTCP serverTCP;
private String gamename = "-1";
public String username;
/**
* This is the future!
* Contains an exact imprint of the player of client side.
* Cheats can be detected here.
*/
private PlayerMP playerMP;
String clientSentence;
TCPConnection(Socket socket, GameServerTCP serverTCP) {
this.socket = socket;
this.serverTCP = serverTCP;
isRunning = true;
thread = new Thread(this);
thread.start();
}
public synchronized void closeConnection() {
if (MasterConnections.connectionsTCP.containsKey(getUniqueConnectionIdentifier())) MasterConnections.connectionsTCP.remove(getUniqueConnectionIdentifier());
if (this.username != null && MasterConnections.currentlyLoggedOnAccounts.contains(this.username)) MasterConnections.currentlyLoggedOnAccounts.remove(this.username);
if (this.gamename != null && serverTCP.server.games.containsKey(this.gamename)) {
Level game = serverTCP.server.games.get(this.gamename);
for (String p : game.playersInLevel) {
if (p.equals(getUniqueConnectionIdentifier())) {
game.playersInLevel.remove(p);
System.out.println(this.username + " has been been removed from game " + this.gamename + ".");
}
}
PacketTCP02LeaveGame tellOthersPacket = new PacketTCP02LeaveGame(this.gamename, this.username);
game.writeDataTCPToAllPlayersInThisLevel(tellOthersPacket);
}
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(socket.getRemoteSocketAddress() + " has been disconnected from server.");
this.serverTCP.amountOfTCPConnections--;
this.stop();
}
public String getUniqueConnectionIdentifier() {
return socket.getInetAddress() + ":" + socket.getPort();
}
public String generateUniqueUDPConnectionIdentifier(InetAddress inetAddess, int udpPort) {
System.out.println("uuc created: ");
System.out.println(inetAddess + "/" + udpPort);
return inetAddess + ":" + udpPort;
}
public void run() {
//version check first
PacketTCP00VersionCheck packetVersionCheck = new PacketTCP00VersionCheck(serverTCP.server.getVersion());
if (MasterConnections.connectionsTCP.containsKey(getUniqueConnectionIdentifier())) {
this.closeConnection();
}
else {
MasterConnections.connectionsTCP.put(getUniqueConnectionIdentifier(), this);
packetVersionCheck.writeData(this);
}
BufferedReader inFromClient;
try {
inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e1) {
e1.printStackTrace();
closeConnection();
return;
}
while(isRunning) {
try {
clientSentence = inFromClient.readLine();
if (clientSentence == null) {
inFromClient.close();
closeConnection();
}
else {
System.out.println("tcprec -> " + (new Date(System.currentTimeMillis())) + " -> " + this.username + " -> " + clientSentence);
this.parsePacket(clientSentence.getBytes());
}
}
catch (SocketTimeoutException ste) {
/**
* TODO:
*/
ste.printStackTrace();
System.err.println("YOU CAN DO SOMETHING HERE!!!!!!!");
closeConnection();
}
catch (Exception e) {
e.printStackTrace();
closeConnection();
}
}
}
public void stop() {
isRunning = false;
try {
thread.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And here is my client:
public class GameClientTCP extends Thread {
public String gamestate = "logged out";
private Game game;
public Socket tcpSocket;
public boolean isRunning = false;
private String serverSentence;
public boolean hasBeenStarted = false;
public int boundUDPPort = -1;
public static String[] characters = new String[5];
public static boolean charactersAreLoaded = false;
private PrintWriter toServer;
public GameClientTCP(Game game, String ipAddress) {
this.game = game;
}
public boolean tryConnect() {
try {
tcpSocket = new Socket();
tcpSocket.connect(new InetSocketAddress(Settings.SERVER_ADDRESS, 6336), 1000);
System.out.println("Just connected to " + tcpSocket.getRemoteSocketAddress());
game.getSocketClientUDP().prepareBeforeStart();
game.getSocketClientUDP().start();
return true;
} catch (UnknownHostException e1) {
try {
tcpSocket.close();
} catch (IOException e) {
GameError.appendToErrorLog(e);
return false;
}
return false;
} catch (IOException e1) {
try {
tcpSocket.close();
} catch (IOException e) {
GameError.appendToErrorLog(e);
return false;
}
GameError.appendToErrorLog(e1);
return false;
}
}
public void run() {
BufferedReader fromServer;
try {
fromServer = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
toServer = new PrintWriter(tcpSocket.getOutputStream(),true);
} catch (IOException e1) {
GameError.appendToErrorLog(e1);
return;
}
while(isRunning) {
try {
serverSentence = fromServer.readLine();
//System.out.println("Received: " + serverSentence);
if (serverSentence != null) this.parsePacket(serverSentence.getBytes());
}
catch(UnknownHostException ex) {
GameError.appendToErrorLog(ex);
}
catch(IOException e){
GameError.appendToErrorLog(e);
}
catch(Exception e) {
GameError.appendToErrorLog(e);
}
}
}
public void sendMessageToServer(String message) {
try {
toServer.println(message);
toServer.flush();
}
catch (Exception e) {
GameError.appendToErrorLog(e);
System.exit(-1);
}
}
}
I hope to find out more about this issue, please help! :)
EDIT: It may be important to say, that while my program is running, it can occur, that there are no tcp packets sent over a longer period of time. The timeout always happens, when i dont send any packets for at least 20 or 30 minutes and then when i send one again, another client times out.
As it turned out, tcp sockets, that are not used longer than a certain amount of time will be kind of destroyed by peers and therefore lose their connection.
I solved my issue, by sending a nearly empty tcp packet every minute to make it clear to all programs and services, that these sockets are alive!
I've been trying to make the code below to have multiple clients communicate with the same server.
Currently, it works one client at a time with the server but it seems to be that when the second client opens, code stops at new ObjectInputStream(connection.getInputStream()); in the Class 3 (client) - see below.
I've tried making the inputstream object transient to be shared in different threads but it didn't work, nor with making runClient method synchronized.
If I were to implement Serializable in the client class using serialVersionUID, how can I make multithreading work with the same server or is there any better way..?
Class 1 - server main
public class EchoServer {
private ServerSocket server;
private int portNum;
public static final int DEFAULT_PORT = 8081;
public EchoServer(int portNum) {
this.portNum = portNum;
}
public void runServer() {
System.out.println("Echo Server started...");
try {
server = new ServerSocket(portNum);
Socket connection = server.accept();
new Thread(new ClientHandler(connection)).run();
} catch(IOException ex) {
System.err.println("Error encountered! Port is likely already in use! Exiting program...");
ex.printStackTrace();
}
}
public static void main(String[] args) {
if (args.length > 0) {
(new EchoServer(Integer.parseInt(args[0]))).runServer();
} else {
(new EchoServer(DEFAULT_PORT)).runServer();
}
}
}
Class 2
public class ClientHandler implements Runnable {
private ObjectOutputStream output;
private ObjectInputStream input;
private String message;
/** Integer to hold the message number. */
private int messagenum;
private Socket connection;
public ClientHandler(Socket connection) {
this.connection = connection;
}
#Override
public void run() {
do{
handleRequest();
} while (true);
}
public void handleRequest() {
try {
output = new ObjectOutputStream(this.connection.getOutputStream());
input = new ObjectInputStream(this.connection.getInputStream());
do {
try {
message = (String) input.readObject();
System.out.println(messagenum +" Output> " +message);
} catch (EOFException | SocketException e) {
message = null;
}
if (message != null) {
output.writeObject(messagenum +" FromServer> " +message);
output.flush();
++messagenum;
}
} while (message != null);
input.close();
output.close();
this.connection.close();
} catch (IOException | ClassNotFoundException ex) {
System.err.println("Error encountered! Exiting program...");
ex.printStackTrace();
}
}
}
Class 3 - client main
public class EchoClient implements Serializable {
private static final long serialVersionUID = 1L;
private Socket connection;
private ObjectOutputStream output;
private transient ObjectInputStream input;
private String message = "";
private static String serverName;
public static final String DEFAULT_SERVER_NAME = "localhost";
private static int portNum;
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
public EchoClient(String serverName, int portNum) {
this.serverName = serverName;
this.portNum = portNum;
}
public synchronized void runClient() {
try {
connection = new Socket(InetAddress.getByName(serverName), portNum);
output = new ObjectOutputStream(connection.getOutputStream());
input = new ObjectInputStream(connection.getInputStream());
do {
System.out.print("Input> ");
message = keyboard.readLine();
if (message != null){
output.writeObject(message);
output.flush();
message = (String) input.readObject();
System.out.println(message);
}
} while (message != null);
input.close();
output.close();
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (ClassNotFoundException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
switch (args.length) {
case 2:
(new EchoClient(args[0], Integer.parseInt(args[1]))).runClient();
break;
case 1:
(new EchoClient(DEFAULT_SERVER_NAME, Integer.parseInt(args[0]))).runClient();
break;
default:
(new EchoClient(DEFAULT_SERVER_NAME, server.EchoServer.DEFAULT_PORT)).runClient();
}
}
}
Call server.accept() in the loop to accept multiple client connections as mentioned in the other answers. Start a new thread with the Thread.start method instead of Thread.run- What's the difference between Thread start() and Runnable run().
volatile boolean isRunning = true;
public void runServer() {
System.out.println("Echo Server started...");
try {
server = new ServerSocket(portNum);
while(isRunning) {
Socket connection = server.accept();
new Thread(new ClientHandler(connection)).start();
}
} catch(IOException ex) {
System.err.println("Error encountered! Port is likely already in use! Exiting program...");
ex.printStackTrace();
}
}
run server needs to wait for connections in a loop otherwise it will connect once and that is it. It needs to close its connections too. Clean up its threads. that's just in server main. I'm pretty sure this is a duplicate. So keep on researching
As said by efekctive, you need your server.accept() in a loop, else it will accept the first client and exit the program. So put these two lines in runServer() in a loop like this:
boolean isRunning = true;
while(isRunning){
Socket connection = server.accept();
new Thread(new ClientHandler(connection)).run();
}
i have this Class (my Server start Class), here i create with every new Client a new Thread for him. After the Thread was createt, i add him to the Vector (list) to keep Track of active users and connections, so that i can send messages to a specific user. But i cant Access the Vector-List from my Thread (its the class below). Can you explain me, how i can do this? I have a private list and public setter and getter methods but i always get the size 1 from the Vector. But i testet it, if i connect with more then one client there are multiple Threads with different socket creates. I can add Entrys to the vector if i do it manuel in my server start class.
package securemessageserver;
public class SecureMessageServer {
private Vector<SecureMessageServerClientThread> userList = new Vector();
private SSLServerSocket sslserversocket;
int port = 9999;
private Boolean isRunning=true;
SSLSocket sslsocket;
private synchronized void loadCertificat(){
try {
URL url = this.getClass().getResource("/securemessageserver/keystore.jks");
File file = new File(url.toURI());
System.setProperty("javax.net.ssl.keyStore", "C:/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "Schelkan1994");
//System.setProperty("javax.net.debug","all");
System.out.println("Certifikat geladen");
} catch (URISyntaxException ex) {
Logger.getLogger(SecureMessageServer.class.getName()).log(Level.SEVERE, null, ex);;
stopServer();
}
}
private synchronized void createSocket(){
try {
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port);
System.out.println("Socket erstellt mit "+port);
} catch (IOException ex) {
Logger.getLogger(SecureMessageServer.class.getName()).log(Level.SEVERE, null, ex);
stopServer();
}
}
private synchronized void startServer(SSLServerSocket sslserversocket){
while(isRunning){
try {
System.out.println("Akzeptiere Verbindungen");
sslsocket = (SSLSocket) sslserversocket.accept();
SecureMessageServerClientThread client = new SecureMessageServerClientThread(sslsocket);
startNewClient(client);
userList.add(client);
} catch (IOException ex) {
Logger.getLogger(SecureMessageServer.class.getName()).log(Level.SEVERE, null, ex);
stopServer();
}
}
}
public synchronized void startNewClient(SecureMessageServerClientThread th){
new Thread(th).start();
}
public synchronized void stopServer(){
isRunning=false;
}
public synchronized SSLServerSocket getServerSocket(){
if(sslserversocket!=null){
return this.sslserversocket;
}
return null;
}
public synchronized void addThreadToList(SecureMessageServerClientThread thread){
userList.add(thread);
}
public synchronized void getAllThreadFromList(){
System.out.println("Size: "+userList.size());
}
public synchronized String getUserName(){
return userList.get(0).getUserOfThread();
}
public synchronized void deleteThreadFromList(SecureMessageServerClientThread thread){
userList.remove(thread);
}
public synchronized void getUserNameOfAllThreads(){
for(int i=0;userList.size()>i;i++){
System.out.println(userList.get(i).getUserOfThread());
}
}
public static void main(String[] args){
SecureMessageServer server = new SecureMessageServer();
server.loadCertificat();
server.createSocket();
server.startServer(server.sslserversocket);
}
}
And hier ist the other class (My Thread Class) instanze of this class if always createt if new client connect to keep track of the connection and to perform input and output operations. But i dont get the right value from the Vector in the other class ... Do you see my error? Thanks for help
public class SecureMessageServerClientThread implements Runnable{
private SSLSocket socket;
private String userName;
boolean isRunning=true;
SecureMessageServer server = new SecureMessageServer();
public SecureMessageServerClientThread(SSLSocket socket){
this.socket=socket;
}
private ObjectInputStream sInput;
private ObjectOutputStream sOutput;
#Override
public void run() {
System.out.println("Client mit Socket is Running: "+socket);
while(isRunning){
try {
sInput = new ObjectInputStream(socket.getInputStream());
SecureMessageServerClientMessage msg = (SecureMessageServerClientMessage) sInput.readObject();
if(msg.getType()==0){
System.out.println("All Threads:");
server.getAllThreadFromList();
}else if(msg.getType()==1){
System.out.println(msg.getMessage());
}else if(msg.getType()==2){
Thread.sleep(1000);
socket.close();
this.stopThread();
}else{
System.out.println("Unbekannter Nachrichtentyp");
}
} catch (IOException ex) {
Logger.getLogger(SecureMessageServerClientThread.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(SecureMessageServerClientThread.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(SecureMessageServerClientThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void stopThread(){
isRunning=false;
// sOutput = new ObjectOutputStream(socket.getOutputStream());
}
public String getUserOfThread(){
return this.userName;
}
public void getUserList(){
server.getAllThreadFromList();
}
}
In SecureMessageServerClientThread, you create a new Server instance with SecureMessageServer server = new SecureMessageServer();.
This means that when you call server.getAllThreadFromList() in getUserList, you're getting the list from the server you just created which has no clients.
The Client thread should instead take the server instance as a parameter:
SecureMessageServer server;
public SecureMessageServerClientThread(SSLSocket socket, SecureMessageServer server){
this.socket=socket;
this.server=server;
}
And in the Server, you should pass this to the new client instance:
SecureMessageServerClientThread client = new SecureMessageServerClientThread(sslsocket, this);
Well, if it is private you obviously can't access from another class. Make it protected and make both classes be in same package.
A few days ago i tried to create a server - client or client Server as an experiment to learn about socket using a thread but then someone told me that i should use swingWorker. I did some research how to use and have implemented it in as practice but it still doesn't work. the swingWorker thread doesn't look like it is running even tho i get a connection and have used .excute(). If you guys can help spot where i am doing wrong that will be great. SwingWorker class is in the startSever() and startClient() method.
private void startServer() {
SwingWorker <Void, String> runningServer = new SwingWorker<Void, String>(){
protected Void doInBackground() {
try {
listeningSocket = new ServerSocket(port);
System.out.println("waiting for connection");
connection = listeningSocket.accept();
connected = true;
System.out.println("Connected");
String incomeMessage =null;
while(connected){
inStream = connection.getInputStream();
inDataStream = new DataInputStream(inStream);
if (myMessage !=null){
outStream = connection.getOutputStream();
outDataStream = new DataOutputStream(outStream);
outDataStream.writeUTF(myMessage);
}
if((incomeMessage = inDataStream.readUTF())!=null){
clientMessage = incomeMessage;
publish(clientMessage);
incomeMessage =null;
}
}
} catch (IOException e) {
clientMessage = "Connection Lost";
}
return null;
}
runningServer.execute();
}
Here's a VERY basic example.
Basically, because you program requires asynchronous communications (that is, you need to be able to read from the socket AND write to it at the same time), you need to offload each stream to a separate thread.
The management process of this example is, well, no existent. Realistically, you should have some kind of "connection" manager that would be able to cleanly close the output and input threads so that, for example, when the user types "bye", the output thread would be able to tell the connection manager that the connection should be terminated. It would then tell the input thread to stop reading any new message and terminate...
Client
public class Client {
public static void main(String[] args) {
try {
Socket master = new Socket("localhost", 8900);
new Thread(new InputHandler(master)).start();
new Thread(new OuputHandler(master)).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static class InputHandler implements Runnable {
private Socket socket;
public InputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (commune) {
String text = reader.readLine();
System.out.println("\n<server> " + text);
if (text.toLowerCase().equals("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
public static class OuputHandler implements Runnable {
private Socket socket;
public OuputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
while (commune) {
System.out.print("> ");
String text = scanner.nextLine();
writer.write(text);
writer.newLine();
writer.flush();
if (text.equalsIgnoreCase("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
writer.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
Server
public class Server {
public static void main(String[] args) {
try {
ServerSocket master = new ServerSocket(8900);
Socket socket = master.accept();
new Thread(new InputHandler(socket)).start();
new Thread(new OuputHandler(socket)).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static class InputHandler implements Runnable {
private Socket socket;
public InputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (commune) {
String text = reader.readLine();
System.out.println("\n<client> " + text);
if (text.toLowerCase().equals("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
public static class OuputHandler implements Runnable {
private Socket socket;
public OuputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
while (commune) {
System.out.print("> ");
String text = scanner.next();
writer.write(text);
writer.newLine();
writer.flush();
if (text.equalsIgnoreCase("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
writer.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
Update (whine)
While I have your source code in front of me...
There should very, very, rarely be a need to do textMessage.addKeyListener(this)
Because you are using a JTextField, you should be using a ActionListener instead. There are a a number of important reasons for this, but for you, the main one would be the fact that a "accept" action is Look and Feel dependent. While most systems do use Enter as there "accept" action, is not a guarantee.
Have a look at How to Write a Action Listener for more information
Given the general complexity of what you are trying to do, +1 for a overall good attempt!
Using this example, the following changes work with a single telnet client.
private PrintWriter out;
...
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
myMessage = friendLabel + textMessage.getText();
if (out != null) {
out.println(myMessage);
}
...
}
...
protected Void doInBackground() {
try {
listeningSocket = new ServerSocket(port);
System.out.println("Waiting for connection");
connection = listeningSocket.accept();
connected = true;
System.out.println("Connected");
Scanner in = new Scanner(connection.getInputStream());
out = new PrintWriter(connection.getOutputStream(), true);
publish("Connected");
while (true) {
publish(in.nextLine());
}
} catch (IOException e) {
clientMessage = "Connection Lost";
try {
connection.close();
System.out.println("Closed");
} catch (IOException e1) {
e1.printStackTrace();
connected = false;
}
}
return null;
}
I see your server port is 8900 and your client port is 8900 too. I am not sure if it matters if the server and client are running on the same machine...
I'm having issues sending objects to a server. Right now, I have a server setup and listening for clients. The client connects, sends a test object (just a String) and outputs it to the command line. It works for the first string sent but none after that.
Server (Hivemind.java):
// Open server socket for listening
ServerSocket ss = null;
boolean listening = true;
try {
ss = new ServerSocket(PORT_NUMBER);
} catch (IOException e) {
System.err.println("Cannot start listening on port " + PORT_NUMBER);
e.printStackTrace();
}
// While listening is true, listen for new clients
while (listening) {
Socket socket = ss.accept();
ServerDispatcher dispatcher = new ServerDispatcher(socket);
dispatcher.start();
}
// Close the socket after we are done listening
ss.close();
Server Thread (ServerDispatcher):
public ServerDispatcher(Socket socket) {
super("ServerDispatcher");
this.socket = socket;
}
public void run() {
System.out.println("Client connected");
try {
input = socket.getInputStream();
objInput = new ObjectInputStream(input);
Object obj = null;
try {
obj = (String)objInput.readObject();
} catch (ClassNotFoundException ex) {
Logger.getLogger(ServerDispatcher.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(obj);
} catch (IOException ex) {
Logger.getLogger(ServerDispatcher.class.getName()).log(Level.SEVERE, null, ex);
}
Connection Class (HivemindConnect.java):
public HivemindConnect(int port) {
this.port = port;
url = "localhost";
}
public HivemindConnect(int port, String url) {
this.port = port;
this.url = url;
}
public void connect() {
try {
socket = new Socket(url, port);
output = socket.getOutputStream();
objOutput = new ObjectOutputStream(output);
} catch (IOException e) {
e.printStackTrace();
}
}
public void close() {
try {
objOutput.close();
output.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(Object obj) {
try {
objOutput.writeObject(obj);
objOutput.flush();
} catch (IOException ex) {
Logger.getLogger(HivemindConnect.class.getName()).log(Level.SEVERE, null, ex);
}
}
CustomerTopComponent:
// When the TC is opened connect to the server
#Override
public void componentOpened() {
hivemind = new HivemindConnect(9001);
hivemind.connect();
}
private void btnSendActionPerformed(java.awt.event.ActionEvent evt) {
hivemind.send(txtText.getText());
}
// When the TC is closed close the connection to the server
#Override
public void componentClosed() {
hivemind.close();
}
You need a loop like this:
while(objInput.available()>0){
Object obj = null;
obj = (String)objInput.readObject();
System.out.println(obj);}
Or something similar.