So I have seen a lot of different questions like this but no definitive help, at least to my understanding or my personal application. I am making a socket "chat room" program that allows the user to send images to selected users through a central server. I can establish the clients to connect but when sending an image this error occurs. Here is my code:
Client:
Thread thread = new Thread() {
#Override
public void run() {
try {
s = new Socket("localhost", 4000);
while (s.isConnected()) {
oos = new ObjectOutputStream(s.getOutputStream());
if (!initialized) {
oos.writeObject(identity);
oos.flush();
oos.reset();
initialized = true;
}
baos = new ByteArrayOutputStream(1000);
// Take screenshot
BufferedImage img = new Robot()
.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
// Write img to baos
ImageIO.write(img, "jpg", baos);
// Send image over socket
oos.writeObject(baos.toByteArray());
oos.flush();
oos.reset();
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
Central Server Home:
public Home() {
initComponents();
textView = new Terminal(terminal);
users = new CopyOnWriteArrayList<>();
Thread startServer = new Thread(new ServerStart());
startServer.start();
}
public class ServerStart implements Runnable {
#Override
public void run() {
try {
serverSock = new ServerSocket(4000);
terminal.append("Server started...\n");
while (true) {
// Detect client connection
Socket clientSock = serverSock.accept();
Thread thread = new Thread(new ClientHandler(clientSock));
thread.start();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public class ClientHandler implements Runnable {
Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
User user = new User(socket);
terminal.append(user.getName() + " connected as " + user.getType() + "...\n");
if (user.getType().equals(User.TYPE_01)) {
users.add(user);
} else {
User client = findUser(user);
while(true){
user.sendScreen(client.receiveScreen());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private User findUser(User user) {
for (User client : users) {
if (client.getCompany().equals(user.getCompany())) {
if (client.getName().equals(user.getName())) {
return client;
}
}
}
return null;
}
}
Central Server User:
public static final String TYPE_00 = "VIEWER";
public static final String TYPE_01 = "CLIENT";
private byte[] bytes;
private ObjectInputStream in;
private ObjectOutputStream out;
private String company, name, type;
public User(Socket socket) throws IOException {
this.out = new ObjectOutputStream(socket.getOutputStream());
this.in = new ObjectInputStream(socket.getInputStream());
setUserType();
}
public void sendScreen(byte[] bytes) {
try {
out.writeObject(bytes);
out.flush();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public byte[] receiveScreen() {
byte[] bytes = null;
try {
bytes = (byte[]) in.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
public String getCompany() {
return company;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public void setUserType()
{
String[] strings = null;
try{
strings = (String[])in.readObject();
type = strings[0];
company = strings[1];
name = strings[2];
} catch(Exception e){
e.printStackTrace();
}
}
Client Viewer:
Thread thread = new Thread() {
#Override
public void run() {
try {
Socket s = new Socket("localhost",4000);
String[] strings = { TYPE, "Vision", "cadams" };
while (s.isConnected()) {
if(!initialized){
System.out.println("initialized");
oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(strings);
oos.flush();
oos.reset();
initialized = true;
}
ois = new ObjectInputStream(s.getInputStream());
byte[] bytes = (byte[]) ois.readObject();
BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
ImageIcon ico = new ImageIcon(
img.getScaledInstance(viewer.getWidth(), viewer.getHeight(), Image.SCALE_SMOOTH));
viewer.setIcon(ico);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
I have done some extensive research and know that this could be from my streams looking like a bowl of ramen noodles but I haven't seen any sort of proposal on how to fix it in terms of source. I thank those who can contribute and please let me know if there is anything I can do to further understanding.
Don't keep creating new ObjectInput/OutputStreams. Use the same ones for the life of the socket.
NB while (s.isConnected() isn't valid. It doesn't magically become false when the peer disconnects. You need to handle end of stream and the various socket termination exceptions.
Related
I'm trying to send Message object from Server module to Client module. Unfortunately it throw java.io.StreamCorruptedException: invalid type code: 64 error. Does anyone know what is the problem with code below?
Client class from Server module
private boolean needToRun;
public final Socket socket;
private OutputStream outputStream;
private InputStream inputStream;
private ObjectOutputStream objOut;
private ObjectInputStream objIn;
public Client(Socket socket) {
this.needToRun = true;
this.socket = socket;
try {
this.outputStream = socket.getOutputStream();
this.inputStream = socket.getInputStream();
this.objOut = new ObjectOutputStream(outputStream);
this.objIn = new ObjectInputStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
run();
}
public void send(Message msg) {
try {
objOut.writeObject(msg);
objOut.flush();
objOut.reset();
} catch (Exception ex){
ex.printStackTrace();
}
}
public void close() {
needToRun = false;
}
public void run() {
new Thread(() -> {
while(needToRun) {
try {
int amount = inputStream.available();
if (amount != 0) {
Message msg = (Message) objIn.readObject();
receivedContent(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public void receivedContent(Message msg) {
for (Client connection : Server.clients) {
connection.send(msg);
}
}
the Client class from Client module looks the same but receivedContent looks like this:
public void receivedContent(Message msg) {
String errorName = msg.content().trim();
MainPane.addLabel(errorName);
}
and last one Server class, which accepts socket connections:
while (true) {
System.out.println("running");
try {
System.out.println("Waiting for client...");
Socket socket = serverSocket.accept();
clients.add(new Client(socket));
} catch (Exception e) {
if (!serverSocket.isClosed()) {
stopServer();
}
break;
}
}
I create program chat box, client will send code to server after that server will return object to client;
I use JFrame to create login.java. This frame will create new client and send this client to JFrame chatbox.java. chatbox will get data from server and server will get data from database.
database<--->server <---> client <---> JFrame.
But when I pass client from login.java to chatbox.java the server will create new socket. Then will make 2 socket run for 1 Jframe(wasted thread). How can I solve this problem or can you give me some ways to make this program! Thanks all
Code demo:
Server
public class Server {
public static void main(String[] args) {
int i = 1;
ExecutorService excutor = Executors.newFixedThreadPool(10);
UserDAO dao = new UserDAO();
try {
ServerSocket server = new ServerSocket(3333);
System.out.println("Server success");
while (true) {
Socket socket = server.accept();
System.out.println("connect success");
ThreadHandler thread = new ThreadHandler(socket);
excutor.execute(thread);
System.out.println("============");
}
} catch (Exception e) {
System.out.println(e);
}
}
}
class ThreadHandler extends Thread {
UserDAO dao = new UserDAO();
private Socket socket;
private DataOutputStream dataOut;
private DataInputStream dataIn;
private ObjectInputStream objIn;
private ObjectOutputStream objOut;
private volatile boolean stop = false;
UserDAO userDAO;
User userSave ;
public ThreadHandler(Socket sockets) {
this.socket = sockets;
try {
dataOut = new DataOutputStream(socket.getOutputStream());
dataIn = new DataInputStream(socket.getInputStream());
objOut = new ObjectOutputStream(socket.getOutputStream());
objIn = new ObjectInputStream(socket.getInputStream());
userDAO = new UserDAO();
userSave = new User();
} catch (IOException e) {
System.out.println("error in constructor");
}
}
#Override
public void run() {
while (!stop) {
try {
String code = dataIn.readUTF();
switch (code) {
case "login":
try {
User user = (User) objIn.readObject();
this.userSave = user;
User userLogin = userDAO.loginUser(user);
objOut.writeObject(userLogin);
} catch (ClassNotFoundException e) {
System.out.println(e);
}
break;
} catch (IOException e) {
try {
userDAO.setStatusUser(false, userSave); //set account offline in db
dataIn.close();
objIn.close();
objOut.close();
} catch (IOException x) {
System.out.println(x);
}
break;
}
}
}
}
Client
public class Client {
DataOutputStream dataOut;
DataInputStream dataIn;
ObjectInputStream objIn;
ObjectOutputStream objOut;
Socket socket;
public Client() {
try {
socket = new Socket("localhost", 3333);
socket.setKeepAlive(true);
dataOut = new DataOutputStream(socket.getOutputStream());
objOut = new ObjectOutputStream(socket.getOutputStream());
objIn = new ObjectInputStream(socket.getInputStream());
dataIn = new DataInputStream(socket.getInputStream());
} catch (Exception e) {
System.out.println(e);
}
}
public User loginUser(User user) {
User fullUser = null;
try {
dataOut.writeUTF("login");
objOut.writeObject(user);
fullUser = (User) objIn.readObject();
} catch (IOException e) {
System.out.println(e);
} catch (ClassNotFoundException x) {
System.out.println(x);
}
return fullUser;
}
JFrame
public class Login extends javax.swing.JFrame {
Client client;
public Login() {
initComponents();
client = new Client();
this.setTitle("Login to TCS");
}
//bt login
private void btLoginActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String login = tfLogin.getText();
String password = String.copyValueOf(tfPassword.getPassword());
if(login.isEmpty()||password.isEmpty()){
JOptionPane.showMessageDialog(null,"Plz enter account!");
return;
}else{
User user = new User(login, password);
User userLogin = client.loginUser(user);
if(userLogin == null){
JOptionPane.showMessageDialog(null, "Your login or password is invalid!");
}else{
ListOfUser listOfUser = new ListOfUser(userLogin, client);//pass client to chatbox
listOfUser.setVisible(true);
this.dispose();
}
}
}
I want to send some objects using network. My network I made it using DatagramSocket, DatagramPacket, ByteArrayInputStream, ObjectInputStream, ByteArrayOutputStream and ObjectOutputStream.
When I was trying to send an object using network I got java.io.EOFException and when I handled this exception using try and catch I lost my object.
Server Side
public class GameServer extends Thread {
private DatagramSocket socket;
private DatagramPacket packet;
private byte[] data;
private ByteArrayInputStream bais;
private ObjectInputStream ois;
private ByteArrayOutputStream baos;
private ObjectOutputStream oos;
private Game game;
public GameServer() {
try {
this.socket = new DatagramSocket(1331);
}
catch (SocketException e) {
e.printStackTrace();
}
start();
}
#Override
public void run() {
while (true) {
data = new byte[6400];
packet = new DatagramPacket(data, data.length);
Object object = receive();
if (object instanceof String) {
String message = (String) object;
System.out.println("CLIENT [ " + packet.getAddress().getHostAddress() + " : " + packet.getPort() + " ] >> " + message.trim());
if (message.equalsIgnoreCase("start")) {
game = new Game("Tankies", 1200, 700);
sendObject(game);
}
}
else if (object instanceof State) {
System.out.println("got state");
}
else if (object instanceof Player)
System.out.println("hi player");
}
}
private Object receive() {
bais = new ByteArrayInputStream(data);
try {
socket.receive(packet);
ois = new ObjectInputStream(new BufferedInputStream(bais));
return ois.readObject();
} catch (EOFException e) {
System.out.println("SERVER Got EOFException");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
private void sendData(byte[] data, InetAddress ipAddress, int port) {
DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, port);
try {
this.socket.send(packet);
}
catch (IOException e) {
e.printStackTrace();
}
}
private void sendObject(Object object) {
baos = new ByteArrayOutputStream(6400);
oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
}
catch (IOException e) {
e.printStackTrace();
}
sendData(baos.toByteArray(), packet.getAddress(), packet.getPort());
}
}
Client Side
public class GameClient extends Thread implements Serializable {
private InetAddress ipAddress;
private transient DatagramSocket socket;
private transient DatagramPacket packet;
private byte[] data;
private transient ByteArrayInputStream bais;
private transient ObjectInputStream ois;
private transient ByteArrayOutputStream baos;
private transient ObjectOutputStream oos;
private Game game;
public GameClient(String ipAddress) {
try {
this.socket = new DatagramSocket();
}
catch (SocketException e) {
e.printStackTrace();
}
try {
this.ipAddress = Inet4Address.getByName(ipAddress);
}
catch (UnknownHostException e) {
e.printStackTrace();
}
start();
}
#Override
public void run() {
while (true) {
data = new byte[6400];
packet = new DatagramPacket(data, data.length);
Object object = receive();
if (object instanceof String) {
System.out.println("SERVER >> " + object);
}
else if (object instanceof Game) {
this.game = (Game) object;
this.game.setClient(this);
this.game.start();
}
}
}
private Object receive() {
bais = new ByteArrayInputStream(data);
try {
socket.receive(packet);
ois = new ObjectInputStream(new BufferedInputStream(bais));
return ois.readObject();
}
catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
private void sendData(byte[] data) {
DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, 1331);
try {
this.socket.send(packet);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void sendObject(Object object) {
baos = new ByteArrayOutputStream(6400);
oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
}
catch (IOException e) {
e.printStackTrace();
}
sendData(baos.toByteArray());
}
}
Code to send the object to server
public class MultiplayerState extends State{
private World world;
private Tank myTank, playerTank;
public MultiplayerState(Handler handler) {
super(handler);
}
#Override
public void startState() {
world = new World(handler,"res/worlds/world1.txt");
handler.setWorld(world);
myTank = new Tank(handler, world.getSpawnX(), world.getSpawnY());
handler.getGame().getRender().addObject(world);
handler.getGame().getRender().addObject(myTank);
world.start();
myTank.start();
handler.getGame().getClient().sendObject(handler.getGame().getPlayer());
}
}
handler.getGame().getClient().sendObject(handler.getGame().getPlayer());
This line to send player to server .. some explanation about code .. this is a game using multithreading in java and i want to create simple network to make two different laptops playing this game online because of that i made this network. I created class Handler this is a class to manage all the game, using object instance of Handler class I can get anything in the game and I want to get object instance of Player class to send it to server because I want to do something to make the game online.
I solved this exception by made GameClient object in Game class transient because I don't want to serialize it. What I want is to use this object to send something to server from Game object internally.
I have a small primitive server for studying, and client side.
Here I have piece of my server code:
public class Connector implements Runnable, SocketListener {
private Socket socket;
private ServerSocket serverSocket;
private List<ServerSideClient> clients = new LinkedList<>();
private boolean triger;
public Connector(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
#Override
public void run() {
while (true) {
try {
System.out.println("Waiting for clients..");
triger = true;
socket = serverSocket.accept();
System.out.println("Client connected");
ServerSideClient client = createClient();
client.setConnection(true);
client.startListeningClient();
clients.add(client);
new Thread(() -> {
socketIsClosed(client);
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private ServerSideClient createClient() {
return new ServerSideClient(socket);
}
#Override
public synchronized void socketIsClosed(ServerSideClient client) {
while (triger == true) {
if (client.isConnected() == false) {
triger = false;
clients.remove(client);
System.out.println("Client was removed " + clients.size());
}
}
}
}
Here we wait for new Client, then create client instance and add it to LinkedList. In instance on server side we waiting information from client and sending answer on separated thread. But when client closes connection with server, socketIsClosed() method should to delete current client reference from collection. But when client is disconnected I haven't even Logout System.out.println("Client was removed " + clients.size()); from socketIsClosed(ServerSideClient client) method.
Client Code:
public class Client {
private final String HOST = "localhost";
private final int PORT = 1022;
private InputStream inputStream;
private OutputStream outputStream;
private BufferedReader bufferedReader;
private Socket socket;
private boolean connection;
public Client() throws IOException {
socket = new Socket();
socket.connect(new InetSocketAddress(HOST, PORT));
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
}
public static void main(String[] args) {
Client client = null;
try {
client = new Client();
client.work();
} catch (IOException e) {
e.printStackTrace();
}
}
private void work() {
connection = true;
listenForConsoleInput();
receiveAnswerFromServer();
}
private void listenForConsoleInput() {
new Thread(() -> {
while (connection == true) {
String requset = null;
try {
requset = bufferedReader.readLine();
if (requset.equals(".")) {
closeConnection();
return;
} else {
sendRequest(requset);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private void sendRequest(String request) {
try {
outputStream.write(request.getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void receiveAnswerFromServer() {
new Thread(() -> {
while (connection == true) {
byte[] data = new byte[32 * 1024];
try {
int numberOfBytes = inputStream.read(data);
System.out.println("Server>> " + new String(data, 0, numberOfBytes));
} catch (IOException e) {
closeConnection();
}
}
}).start();
}
private void closeConnection() {
try {
connection = false;
socket.close();
inputStream.close();
outputStream.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
socketIsClosed(ServerSideClient client) method works in separated thread.
public class ServerSideClient {
private Socket socket;
private InputStream in;
private OutputStream out;
private boolean connection;
private int numOfBytes;
public boolean isConnected() {
return connection;
}
public void setConnection(boolean connection) {
this.connection = connection;
}
public ServerSideClient(Socket socket) {
this.socket = socket;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startListeningClient() {
new Thread(() -> {
listenUsers();
}).start();
}
private void listenUsers() {
while (connection == true) {
byte[] data = new byte[32 * 1024];
readInputFromClient(data);
if (numOfBytes == -1) {
try {
connection = false;
socket.close();
in.close();
out.close();
isConnected();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Client disconected..");
return;
}
String requestFromClient = new String(data, 0, numOfBytes);
System.out.println("Client sended>> " + requestFromClient);
sendResponce(requestFromClient);
}
}
private void readInputFromClient(byte[] data) {
try {
numOfBytes = in.read(data);
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendResponce(String resp) {
try {
out.write(resp.getBytes());
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I trying to resolve this problem since 2 week, Helllllllp.....
I was able to replicate your problem, and as a easy solution to fix is creating a class SocketClosedListener:
class SocketClosedListener implements Runnable {
private final ServerSideClient client;
private List<ServerSideClient> clients;
public SocketClosedListener(ServerSideClient client, List<ServerSideClient> clients) {
this.client = client;
this.clients = clients;
}
#Override
public void run() {
while (true) {
if (!client.isConnected()) {
clients.remove(client);
System.out.println("Client was removed " + clients.size());
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And inside your run() method in the Connector class, we have this call:
#Override
public void run() {
while (true) {
try {
System.out.println("Waiting for clients..");
triger = true;
socket = serverSocket.accept();
System.out.println("Client connected");
ServerSideClient client = createClient();
client.setConnection(true);
client.startListeningClient();
clients.add(client);
new Thread(new SocketClosedListener(client, clients)).start();//added
} catch (IOException e) {
e.printStackTrace();
}
}
}
The line added:
new Thread(new SocketClosedListener(client, clients)).start();
It is responsible to be looking for client when disconnected in a separated thread. Also a delay of 100ms to avoid checking each ms that can cause issues when multiple threads running.
With this code I was able to have this in the console:
Waiting for clients..
Client sended>> hi
Client disconected..
Client was removed 1
Client disconected..
Client was removed 0
Okay, I decided this problem with javaRX library. I just used event that send to observer server state. In Observable class I've created:
private PublishSubject<Boolean> subject = PublishSubject.create();
public Observable<Boolean> observable = subject.asObservable();
public void setConnection(boolean connection) {
this.connection = connection;
subject.onNext(this.connection);
}
Method setConnection() set true if client has been connected and false if client initialized disconnect.
In Observer class I initialized an instance of Observable class, and initialized subscription:
client = createClient();
client.observable.subscribe(state -> removeClient(state));
public void removeClient(Boolean state) {
System.out.println("Server state " + state);
if (state == false) {
clients.remove(client);
System.out.println("Client remowed. List size: " + clients.size());
}
}
Now, I always know about server state, and make client removing if last has initialized disconnection.
I'm trying to create a proxy application, but I'm facing problems in server socket. The Server Socket is not accepting the connection and returning a socket. Hence, I cannot test the proxy application. What is wrong?
The problem line is indicated in WebServe.java:
public class WebServe implements Runnable {
Socket soc;
OutputStream os;
BufferedReader is;
String resource;
WebServe(Socket s) throws IOException {
soc = s;
os = soc.getOutputStream();
is = new BufferedReader(new InputStreamReader(soc.getInputStream()));
}
public void run() {
System.err.println("Running");
getRequest();
returnResponse();
close();
}
public static void main(String args[]) {
try {
System.out.println("Proxy Thread");
ServerSocket s = new ServerSocket(8080);
for (;;) {
s.setSoTimeout(10000);
WebServe w = new WebServe(s.accept()); // Problem is here
Thread thr = new Thread(w);
thr.start();
w.getRequest();
w.returnResponse();
w.close();
}
} catch (IOException i) {
System.err.println("IOException in Server");
}
}
void getRequest() {
System.out.println("Getting Request");
try {
String message;
while ((message = is.readLine()) != null) {
if (message.equals("")) {
break;
}
System.err.println(message);
StringTokenizer t = new StringTokenizer(message);
String token = t.nextToken();
if (token.equals("GET")) {
resource = t.nextToken();
}
}
} catch (IOException e) {
System.err.println("Error receiving Web request");
}
}
void returnResponse() {
int c;
try {
FileInputStream f = new FileInputStream("." + resource);
while ((c = f.read()) != -1) {
os.write(c);
}
f.close();
} catch (IOException e) {
System.err.println("IOException is reading in web");
}
}
public void close() {
try {
is.close();
os.close();
soc.close();
} catch (IOException e) {
System.err.println("IOException in closing connection");
}
}
}
public static void main(String args[]){
try {
System.out.println("Proxy Thread");
ServerSocket s = new ServerSocket (8080);
for (;;){
s.setSoTimeout(10000);
Move that ahead of the loop. You don't need to keep setting it. You don't really need it at all actually.
WebServe w = new WebServe (s.accept()); //Problem is here
The problem is here only because you set a socket timeout you don't actually need.
Thread thr = new Thread (w);
thr.start();
So far so good.
w.getRequest();
w.returnResponse();
w.close();
Remove. The next problem is here. The run() method of WebServ already does this.
As to the rest, you aren't writing an HTTP header in the response.