I have a socket communication between clients and a server. I design the server side in order to create a new thread every time a client connects to the server. The problem is that, sometimes, ObjectInputStream throws StreamCorruptedException when I try to read and object.
The involved classes implement serializable, and have correct serialVersionUIDs. Also, I used synchronized to avoid problems of synchronization. I tried to flush the objectOutputStream every time I write and object. The problem persist, so it is possible to send objects via a socket communication without use ObjectOutputStream? Send a byte array directly or something like this?
I let some code in case someone sees something I'm doing wrong.
server side
public class ClientHandler implements Runnable {
public static ArrayList<ClientHandler> clientsHandlers = new ArrayList<>();
private Socket socket;
private Server server;
private Usuario usuario;
private ObjectInputStream objectInputStream;
private ObjectOutputStream objectOutputStream;
public ClientHandler(Socket socket, Server server) {
try {
this.socket = socket;
this.server = server;
objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
clientsHandlers.add(this);
} catch (Exception e) {
// TODO: handle exception
disconnect();
}
}
#Override
public void run() {
// TODO Auto-generated method stub
while (!socket.isClosed() && socket.isConnected()) {
try {
synchronized (objectInputStream) {
Object object = objectInputStream.readObject(); // <---PROBLEM
if (object instanceof AccionOnline) {
switch (((AccionOnline) object).getTipoAccionOnline()) {
case DESCONECTAR:
disconnect();
if (server.numConnection == 0) {
server.closeServerSocket();
} else {
sendObject(object);
}
break;
case INICIARPARTIDA:
case DODECAEDRO:
case SIGUIENTE:
case DADO:
case ITEMDADO:
case RULETA:
case TEST:
case DRAWSTART:
case DRAW:
case DRAWUP:
sendObject(object);
break;
}
}
if (object instanceof Usuario) {
this.usuario = (Usuario) object;
for (ClientHandler clientHandler : clientsHandlers) {
if (!clientHandler.equals(this)) {
this.objectOutputStream.writeObject(clientHandler.usuario);
this.objectOutputStream.flush();
}
}
sendObject(object);
}
}
} catch (Exception e) { // TODO: handle exception closeAll(socket, bufferedReader,
disconnect();
}
}
}
public <T> void sendObject(T object) {
for (ClientHandler clientHandler : clientsHandlers) {
try {
clientHandler.objectOutputStream.writeObject(object);
clientHandler.objectOutputStream.flush();
} catch (Exception e) {
// TODO: handle exception
disconnect();
}
}
}
public void disconnect() {
System.out.println("cerrar conexion");
clientsHandlers.remove(this);
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (objectOutputStream != null) {
objectOutputStream.close();
}
if (socket != null) {
socket.close();
}
server.numConnection--;
} catch (Exception e) {
// TODO: handle exception
}
}
}
client side
public class Client {
private Socket socket;
private ObjectOutputStream objectOutputStream;
private ObjectInputStream objectInputStream;
private ArrayList<GetObject> listeners = new ArrayList<>();
public Client(Socket socket, GetObject listener) {
listeners.add(listener);
try {
this.socket = socket;
this.objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
this.objectInputStream = new ObjectInputStream(socket.getInputStream());
} catch (Exception e) {
// TODO: handle exception
closeAll();
}
}
public void addListener(GetObject listener) {
listeners.add(listener);
}
public void removeListener(GetObject listener) {
listeners.remove(listener);
}
public <T> void sendObject(T object) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
objectOutputStream.writeObject(object);
} catch (Exception e) {
closeAll();
}
}
});
thread.start();
}
public void listenServer() {
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (socket.isConnected()) {
try {
Object o = objectInputStream.readObject();
for (GetObject listener : listeners) {
listener.getObject(o);
}
} catch (Exception e) {
// TODO: handle exception
closeAll();
}
}
}
}).start();
}
public void closeAll() {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (objectOutputStream != null) {
objectOutputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
Related
i know there is alot of post that ask how to comunicate between client and server ,but in the majority those are generally people using the localhost, I have for project to use a vps and several client computer, unfortunately all the solutions given in the other post does not work, indeed the client does not seem to be able to connect to my vps
there is my client code
public IRCClient() throws IOException {
socket = new Socket(InetAddress.getByAddress(new byte[]{(byte) 185, (byte) 242, (byte) 180,97}), 2406);
messages = new LinkedBlockingQueue<Object>();
server = new ConnectionToServer(socket);
Thread messageHandling = new Thread() {
public void run() {
while (true) {
try {
Object message = messages.take();
parse(message);
System.out.println("Message Received: " + message);
} catch (InterruptedException e) {
}
}
}
};
messageHandling.setDaemon(true);
messageHandling.start();
}
private void parse(Object message) {
String msg = String.valueOf(message);
if (msg.contains("-")) {
if (msg.contains("key")) {
key = msg.split("-")[1];
} else if (msg.contains("name")) {
name = msg.split("-")[1];
} else if (msg.contains("world")) {
world = msg.split("-")[1];
} else if (msg.contains("server")) {
serverName = msg.split("-")[1];
} else if (msg.contains("x")) {
x = Integer.parseInt(msg.split("-")[1]);
} else if (msg.contains("y")) {
y = Integer.parseInt(msg.split("-")[1]);
} else if (msg.contains("z")) {
z = Integer.parseInt(msg.split("-")[1]);
} else if (msg.contains("isEntity")) {
entity = msg.split("-")[1].equalsIgnoreCase("true");
} else if (msg.contains("ticks")) {
lTicks = Integer.parseInt(msg.split("-")[1]);
} else if (msg.contains("end")) {
if (key.equalsIgnoreCase(MultiPingMod.getKey()) && !name.equalsIgnoreCase(Minecraft.getMinecraft().thePlayer.getName())) {
MultiPing m = new MultiPing(name, world, serverName, x, y, z, entity);
MultiPingMod.setTime(lTicks);
m.render = true;
if (MultiPingMod.render.getToRender().containsKey(name)) {
MultiPingMod.render.getToRender().get(name).render = false;
MultiPingMod.render.getToRender().remove(name);
}
MultiPingMod.render.addToRender(m);
}
}
}
}
public void send(Object obj) {
server.write(obj);
}
private class ConnectionToServer {
ObjectInputStream in;
ObjectOutputStream out;
Socket socket;
ConnectionToServer(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread() {
public void run() {
while (true) {
try {
Object obj = in.readObject();
messages.put(obj);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
};
read.setDaemon(true);
read.start();
}
private void write(Object obj) {
try {
out.writeObject(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
i got this code from somewhere in this forum because after lot of attempt nothing was working
same for the server code here is :
public ServerListener() {
debug("Creating the server");
clientList = new ArrayList<ConnectionToClient>();
messages = new LinkedBlockingQueue<Object>();
debug("Client list is created");
try {
serverSocket = new ServerSocket(2406);
debug("opening the port 2406");
} catch (IOException e) {
e.printStackTrace();
debug(e.getMessage());
}
debug("creating the accept thread");
Thread accept = new Thread() {
public void run() {
debug("thread created");
while (true) {
try {
Socket s = serverSocket.accept();
if(s!=null) {
debug("new client joined");
clientList.add(new ConnectionToClient(s));
debug("new client was accepted ["+ s.getInetAddress() + "/" + s.getPort()+"]");
}
} catch (IOException e) {
e.printStackTrace();
debug(e.getMessage());
}
}
}
};
accept.setDaemon(true);
accept.start();
Thread messageHandling = new Thread() {
public void run() {
while (true) {
try {
Object message = messages.take();
debug("we parse the ping");
parse(message);
System.out.println("Message Received: " + message);
} catch (InterruptedException e) {
}
}
}
};
messageHandling.setDaemon(true);
messageHandling.start();
}
private void parse(Object message) {
String msg = String.valueOf(message);
if(msg.contains("-")) {
if(msg.contains("key")) {
debug("key detected");
key = msg.split("-")[1];
} else if(msg.contains("name")) {
debug("name detected");
name = msg.split("-")[1];
} else if(msg.contains("world")) {
debug("worldname detected");
world = msg.split("-")[1];
} else if(msg.contains("server")) {
debug("servername detected");
server = msg.split("-")[1];
} else if(msg.contains("x")) {
debug("x detected");
x = Integer.parseInt(msg.split("-")[1]);
} else if(msg.contains("y")) {
debug("y detected");
y = Integer.parseInt(msg.split("-")[1]);
} else if(msg.contains("z")) {
debug("z detected");
z = Integer.parseInt(msg.split("-")[1]);
} else if(msg.contains("isEntity")) {
debug("entity detected");
entity = msg.split("-")[1].equalsIgnoreCase("true");
} else if(msg.contains("ticks")) {
debug("ticks detected");
lTicks = Integer.parseInt(msg.split("-")[1]);
} else if(msg.contains("end")) {
debug("we got everything detected");
toSend = new IrcMPING(key, name, world, server, x, y, z, entity, lTicks);
for(String str : toSend.getArgs()) {
sendToAll(str);
}
toSend=null;
}
}
}
public void sendToOne(int index, Object message) throws IndexOutOfBoundsException {
clientList.get(index).write(message);
}
public void sendToAll(Object message) {
for (ConnectionToClient client : clientList) {
debug("sending the ping to " + client.socket.getInetAddress());
client.write(message);
}
}
public void debug(String str) {
System.out.println("SOROS DEBUG [MULTIPING] : " + str) ;
}
private class ConnectionToClient {
ObjectInputStream in;
ObjectOutputStream out;
Socket socket;
ConnectionToClient(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread() {
public void run() {
while (true) {
try {
Object obj = in.readObject();
messages.put(obj);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
};
read.setDaemon(true); // terminate when main ends
read.start();
}
public void write(Object obj) {
try {
out.writeObject(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
i run the jar from the vps (who is based on debian) using the java jar command , but nothing to do i only get this on the terminal
https://cdn.discordapp.com/attachments/832578338567487497/833752196017029170/unknown.png //link to the image
How can i do to make this work ? there is any other way than socket to make two jar communicate from distant computer/server ? thank you for reading me and thank you if you try to help me
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)
I have class that extends asynchronous task and another class which extends thread.
Client.java
public class Client extends AsyncTask<String, Void, Void>
{
Socket socket;
private SocketClient socketClient;
DataOutputStream out;
#Override
protected Void doInBackground(String... params)
{
// TODO Auto-generated method stub
Log.d("home","Client");
connect();
return null;
}
protected void connect()
{
// TODO Auto-generated method stub
Log.d("home","Connect");
if(socket!=null)
{
disconnect();
return;
}
try
{
String host = "111.111.1.111";
InetAddress in=InetAddress.getByName(host);
socket = new Socket(in,21);
socketClient=SocketClient.handle(this,socket);
Log.d("home","Connection established");
}
catch(Exception e)
{
e.printStackTrace();
Log.d("home","Not Connection established");
}
}
void disconnect()
{
// TODO Auto-generated method stub
try
{
socketClient.setDesonnected(true);
socket.close();
}
catch (Exception e)
{
System.err.println("Error closing client : "+e);
}
socket=null;
}
protected void sendmessage(byte[] commandchannel1)
{
// TODO Auto-generated method stub
byte[] commandchannel=commandchannel1;
try
{
if(out==null)
{
out=new DataOutputStream(socket.getOutputStream());
}
// out.writeInt(commandchannel.length);
out.write(commandchannel);
out.flush();
}
catch(Exception e)
{
e.printStackTrace();
disconnect();
}
}
public void setreceived(String got)
{
// TODO Auto-generated method stub
System.out.println(got);
}
}
SocketClient.java
public class SocketClient extends Thread
{
private boolean desonnected=false;
private static SocketClient socketClient=null;
private Socket socket=null;
private static Client parent;
private DataInputStream in;
customadapter customadapter;
public synchronized void setDesonnected(boolean cr)
{
desonnected=cr;
}
private SocketClient(Client parent, Socket s)
{
super("Client");
this.parent = parent;
socket=s;
setDesonnected(false);
start();
System.out.println(this.parent);
}
public static SocketClient handle(Client client, Socket socket)
{
// TODO Auto-generated method stub
if(socketClient==null)
socketClient=new SocketClient(parent, socket);
else {
if(socketClient.socket!=null) {
try {
socketClient.socket.close();
} catch (Exception e) {
}
}
socketClient.socket=null;
socketClient=new SocketClient(parent,socket);
}
return socketClient;
}
public void run() {
InputStream is = null;
try {
is = socket.getInputStream();
System.out.println(is);
in = new DataInputStream(is);
} catch(IOException e) {
try {
socket.close();
} catch(IOException e2) {
System.err.println("Socket not closed :"+e2);
}
System.out.println("Could not open socket : "+e.getMessage());
parent.disconnect();
return;
}
while(!desonnected) {
try {
String got = readInputStream(in); //in.readLine();
if(got==null) {
//parent.error("Connection closed by client");
parent.disconnect();
break;
}
**parent.setreceived(got);**
} catch(IOException e)
{
if(!desonnected)
{
System.out.println(e.getMessage());
parent.disconnect();
}
break;
}
}//end of while
try {
is.close();
in.close();
//socket.close();
} catch (Exception err) {}
socket=null;
}//end of run
private static String readInputStream(DataInputStream _in) throws IOException
{
StringBuilder sb=new StringBuilder();
String data = "";
int s = _in.read();
if(s==-1)
return null;
data += ""+String.format("%X", s)+ " ";
int len = _in.available();
System.out.println("Len got : "+len);
if(len > 0)
{
byte[] byteData = new byte[len];
_in.read(byteData);
for(byte b:byteData)
{
System.out.println(byteData);
sb.append(String.format("%02X",b));
sb.append(" ");
}
}
data += sb.toString();
System.out.println(data);
return data;
}
}
I am getting exception as Attempt to invoke virtual method on null pointer exception when setreceived(got) is called. How will i overcome this exception.
I am calling the asynchronous task from another Activity as
client=new Client();
client.execute();
I want to return the received value to an activity finally. How can i do this.
Please help.Thanks in Advance
You will have to change handle method. As for initializing SocketClient you have passed parameter parent, which is not initialized yet. So pass 'client' instead of it.
public static SocketClient handle(Client client, Socket socket)
{
// Verify that the socket is open
if(socketClient==null)
socketClient=new SocketClient(client, socket);
else {
if(socketClient.socket!=null) {
try {
socketClient.socket.close();
} catch (Exception e) {
}
}
socketClient.socket=null;
socketClient=new SocketClient(client,socket);
}
return socketClient;
}
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...
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.