I am trying to write a game server, and this is my first time I using sockets.
On both sides (client and server) I want to create two parallel threads:
1) first one is to repeatedly (by while-loop and Thread.sleep()) sending(server) and reading(client) DefaultListModel object to all connected users. I use ObjectOutputStream and ObjectInputStream for server and client respectively.
2) second one is to String exchange (for determine which method to invoke). I use BufferedReader and PrintWriter (these threads is main() threads of client and server).
My problem is: all streams are messing up. Client receive DefaultModelList when String is expected and vice versa.
And finally my questions is: is there any way to separate these two processes? Make one stream take only one class and ignore others?
My code:
// when server wakes up
//Server:
Thread listChangesChecker = new Thread(new ListUpdater());
listChangesChecker.start();
// now client starts dialog
Client:
writer.println("old");
writer.flush();
showLoginDialog();
//Server:
String userStart = reader.readLine();
if (userStart.equals("old")) { checkOldPlayer(); }
//Client:
String password = tfPassword.getText();
writer.println(login + " " + password);
writer.flush();
//Server:
loginPassword = reader.readLine();
if(userIsOk) {
// first and last time list sends inside main()
objectWriter.writeUnshared(playersLoginList);
}
//Client:
playersList = (DefaultListModel) objectReader.readObject();
// client second thread starting
Thread t = new Thread(new ListChangeListener());
t.start();
Code for server second thread:
private class ListUpdater implements Runnable {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
if(!objectWriters.isEmpty()) {
System.out.println("Sent new model");
for (int i = 0; i < objectWriters.size(); i++) {
ObjectOutputStream ous = objectWriters.get(i);
ous.writeUnshared(playersLoginList);
ous.reset();
}
Thread.sleep(5000);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Code for client second thread
private class ListChangeListener implements Runnable {
#Override
public void run() {
try {
DefaultListModel<String> newList;
while (true) {
newList = (DefaultListModel<String>) objectReader.readUnshared();
playersList = newList;
jList.setModel(playersList);
}
} catch (Exception e) {e.printStackTrace();}
}
}
Related
I am writing a Java client/server GUI application using sockets and here is the problem:
I have a button to start listening for a specified port:
button actionPerformed method
private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {
int port = Integer.parseInt(portTextfield.getText(), 10);
try {
socket.listen(port);
} catch (IOException ex) {
}
}
Here is the socket.listen method
public static void listen() throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true)
new socket(ss.accept());
}
"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.
After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?
You have two pitfalls in your design:
ss.accept() is a blocking call so your UI will freeze until there is an incoming connection
Never run while(true) loops in the EDT.
Instead do the following:
When the button is clicked create a thread that will start listening for incoming connections.
Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
as long as your
new socket(ss.accept());
returns immediately, you only need to change your
while (true)
this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.
If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List)
Create a nested class that extents SwingWorker. Just call a swingWoker.execute(); (after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt) method.
See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Never create a new thread and run it from from the Swing EDT
Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html
1) If you are writing GUI application may be in Swing never call
blocking method in Event dispatcher thread or in the event handler.
for example if you are reading a file or opening a network connection
when a button is clicked don't do that on actionPerformed() method,
instead just create another worker thread to do that job and return
from actionPerformed(). this will keep your GUI responsive, but again
it depends upon design if the operation is something which requires
user to wait than consider using invokeAndWait() for synchronous
update.
Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html
You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.
Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.
Try these...
1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.
`Socket s = new Socket();`
`s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`
2. And Secondly always keep the Non-UI work out of Your UI thread..
Here is my Example of Server - Client Communication..
Client side code:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket();
s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server side code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}
Edited my question for clarification and code:
My goal is to pass my String data from my background thread, to my main application thread. Any help is appreciated.
Here is the code that creates the main background thread. This is located in my Server.java class
public class Server {
boolean isConnected = false;
Controller controller = new Controller();
public void startHost() {
Thread host = new Thread(() -> {
Controller controller = new Controller();
ServerSocket server = null;
try {
server = new ServerSocket(GeneralConstants.applicationPort);
} catch (BindException e2) {
System.out.println("Port Already in Use!");
} catch (IOException e) {
//do nothing
}
while (true) {
if (server == null) { break; }
try {
Socket client = server.accept();
System.out.println("Client Connected: " + isConnected);
if (!isConnected) {
controller.createClientHandler(client);
isConnected = true;
System.out.println("Client Connected: " + isConnected);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
host.setDaemon(true);
host.start();
}
Here is the code that is then called when a client is connected, located in my Controller.java class.
public synchronized void createClientHandler(Socket client) {
boolean alreadyConnected = false;
if (alreadyConnected) {
//do NOT assign multiple threads for each client
} else {
ClientHandler handleClients = new ClientHandler("client", client);
}
}
The program then creates two background threads for my client, one to manage receiving messages, and sending messages.
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(this::receive);
sendThread = new Thread(this::send);
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
The thread then successfully creates the inputstream and passes the object to my controller. Which then process and grabs a string assigning it to a variable
public synchronized void handleReceivedPacket(String name, BufferedReader in) {
try {
data = in.readLine();
System.out.println("Successfully assigned data to: " + data);
} catch (IOException e) {
System.out.println("Unable to read result data");
}
}
How do I access my String data from the main thread without getting null?
Aka I can call (or something similar)
controller.returnData();
from my main application. From which it'll either return null (no data yet), or actually return my data. Right now, it's always null.
Edit, this is what's actually calling controller.returnData() {
I don't want to paste a massive amount of code for fear of reaching StackOverflow's code limit, so here's my application structure.
My JavaFX creates the scene, and creates a root gridpane, it then calls a method that creates sub gridpanes based the specified input. Aka, a user can press "Main Menu" that calls my method setScene() which removes the current "sub-root" gridpane and creates a "new" scene. Right now, I have a GameBoard.java class which on button press, calls controller.returnData()
PassOption.setOnAction(event -> {
System.out.println(controller.returnData());
});
There is no functional purpose for this besides testing. If I can receive the data, then I can expand on this using the data.
Start thinking about design. In network applications you typically have to manage the following responsibilites:
Connected clients and their state (connection state, heartbeats, ...)
Received messages from the clients
Messages to transmit to the clients
It makes sense to separate those responsibilities in order to keep the code clean, readable and maintainable.
Separation can mean both, thread-wise and class-wise.
For example, you could implement it as follows:
The class ClientAcceptor is responsible for opening the socket and accepting clients. As soon as a client has connected, it delegates the further work to a controller and then waits for other clients:
public class ClientAcceptor implements Runnable {
#Override
public void run() {
while (true) {
ServerSocket server;
try {
server = new ServerSocket(1992);
Socket client = server.accept();
if (client.isConnected()) {
controller.createClientHandler(client);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The controller could then create a handler (if the controller decides to do so, e.g. it could also decline the client). The ClientHandler class could look as follows:
public class ClientHandler {
private Thread receiveThread;
private Thread sendThread;
private boolean connected;
private Socket clientSocket;
private String clientName;
private LinkedBlockingDeque<byte[]> sendQueue;
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(() -> receive());
sendThread = new Thread(() -> send());
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
private void receive() {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(clientSocket.getInputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
try {
byte[] bytes = in.readAllBytes();
if (bytes != null && bytes.length > 0) {
controller.handleReceivedPacket(clientName, bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void send() {
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(clientSocket.getOutputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
byte[] toSend = sendQueue.getFirst();
if (toSend != null && toSend.length > 0) {
try {
out.write(toSend);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void send(byte[] packet) {
sendQueue.add(packet);
}
public void close() {
connected = false;
}
}
The ClientHandler is responsible for receiving and transmitting data. If a packet arrives it informes the controller, which parses the packet. The ClientHandler also provides a public API to send data (which is stored in a queue and handled by a thread) and close the connection.
The above code examples are neither tested, nor complete. Take it as a starting point.
I am writing a Java client/server GUI application using sockets and here is the problem:
I have a button to start listening for a specified port:
button actionPerformed method
private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {
int port = Integer.parseInt(portTextfield.getText(), 10);
try {
socket.listen(port);
} catch (IOException ex) {
}
}
Here is the socket.listen method
public static void listen() throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true)
new socket(ss.accept());
}
"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.
After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?
You have two pitfalls in your design:
ss.accept() is a blocking call so your UI will freeze until there is an incoming connection
Never run while(true) loops in the EDT.
Instead do the following:
When the button is clicked create a thread that will start listening for incoming connections.
Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
as long as your
new socket(ss.accept());
returns immediately, you only need to change your
while (true)
this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.
If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List)
Create a nested class that extents SwingWorker. Just call a swingWoker.execute(); (after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt) method.
See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Never create a new thread and run it from from the Swing EDT
Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html
1) If you are writing GUI application may be in Swing never call
blocking method in Event dispatcher thread or in the event handler.
for example if you are reading a file or opening a network connection
when a button is clicked don't do that on actionPerformed() method,
instead just create another worker thread to do that job and return
from actionPerformed(). this will keep your GUI responsive, but again
it depends upon design if the operation is something which requires
user to wait than consider using invokeAndWait() for synchronous
update.
Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html
You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.
Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.
Try these...
1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.
`Socket s = new Socket();`
`s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`
2. And Secondly always keep the Non-UI work out of Your UI thread..
Here is my Example of Server - Client Communication..
Client side code:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket();
s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server side code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}
I made my one-on-one socket chat work between the server (myself) and the client (a friend in a different network). Now I'm trying to do the same but I'm trying to create multiple connections, placing them in an Executors.newFixedThreadPool(poolSize), where part of the code is taken from the ExecutorService documentation.
The server works, and accepts connections, however, the problem occurs when I try to make a second connection and send messages to it. Although each client can send messages to the server, the server can only send messages to the first client.
Here is the full code:
public class MultipleServer implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool;
Scanner console;
public MultipleServer(int port, int poolSize, Scanner mainconsole)
throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
console = mainconsole;
}
public void run() {
try {
for(;;) {
pool.execute(new Handler(serverSocket.accept(), console));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private Socket socket;
private Scanner console;
private String name = "undefined";
Handler(Socket socket, Scanner console)
{
this.socket = socket;
this.console = console;
}
public void run()
{
if (socket.isConnected())
{
System.out.println("connection from " + socket.getLocalAddress().getHostAddress());
Thread inputthread = new Thread(new Runnable()
{
#Override
public void run()
{
PrintWriter out;
try
{
out = new PrintWriter(socket.getOutputStream(), true);
out.println("Welcome to my server. Input your name");
out.flush();
String line;
while ((line = console.nextLine()) != null)
{
if (line.contains("/"))
{
if (line.equals("/q " + name))
{
out.println("Connection closing");
System.out.println("Connection to " + name + "closing");
out.close();
socket.close();
} else if (line.substring(0, name.length() + 3).equals("/m " + name))
{
out.println(line.substring(name.length() + 4));
out.flush();
}
} else
{
System.out.println("Incorrect command");
}
}
if (socket.isClosed())
{
out.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
});
Thread outputthread = new Thread(new Runnable()
{
int msgno = 0;
#Override
public void run()
{
BufferedReader in;
try
{
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!socket.isClosed())
{
while (!in.ready())
{
Thread.sleep(100);
}
String msg = in.readLine();
if (msgno == 0)
{
name = msg;
msgno++;
} else
{
System.out.println(name + ": " + msg);
}
synchronized (this)
{
this.wait(100);
}
}
if (socket.isClosed())
{
in.close();
}
} catch (IOException e)
{
e.printStackTrace();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
});
inputthread.start();
outputthread.start();
}
}
public static void main(String[] args) throws IOException
{
int connections = 10;
int port = 80;
Scanner scanner = new Scanner(System.in);
MultipleServer server = new MultipleServer(port, connections, scanner);
server.run();
}
}
More specifically, the exception thrown:
Exception in thread "Thread-2" java.lang.IndexOutOfBoundsException: end
at java.util.regex.Matcher.region(Unknown Source)
at java.util.Scanner.findPatternInBuffer(Unknown Source)
at java.util.Scanner.findWithinHorizon(Unknown Source)
at java.util.Scanner.nextLine(Unknown Source)
at Handler$1.run(MultipleServer.java:61)
at java.lang.Thread.run(Unknown Source)
Where the line in question is:
while((line=console.nextLine())!=null){
To clarify: this exception happens when the second user joins the server. When I type /m user1 message the first user gets the intended message, when I type /m user2 message, there are no errors, but the user2 doesn't get the message. Moreover, there is no "Incorrect command" message at the server console, meaning that the output to the second user isnt working
The main problem - you have too complicated threads management: several threads tries to read from console input simultaneously: user 1 reader thread and user 2 read thread.
You should introduce a single router thread, responsible for communication with administrator and manage all messages between spawned threads via shared concurrent structure(s).
For such tasks it would be better to use any existent frameworks, e.g. netty or nirvana messaging.
I wanted to create a simple game with a server and more than one clients. Server will have several Hashmaps and Arraylists. Server will broadcast these to clients, then one by one a client may modify these and send back to server and then server will broadcast updated values to all clients.
To get started, I have created Server - Client chat app. When a client sends String message to server, Server will add that String message to it's Arraylist and will broadcast that arraylist to all clients. I have used threads so that multiple clients can send messages concurrently, but I haven't applied thread-safety yet.
Lets come to the problem. for the first time when a client sends String to server, server prints it well, add to it's arraylist, then broadcasts it to all clients and all clients can see that too. But next time when client sends String message, server accepts it, adds to arraylist and broadcasts it, but this time all clients gets old arraylist ( list with only one String which was added first ). I have printed arraylist before broadcasting and it shows modified values, but at client side it shows list with one entry only.
Part of Server code
public class ServerGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
private ServerSocket ss;
ArrayList<String> al;
ArrayList<ClientHandler> clients;
public ServerGUI() {
initComponents();
setVisible(true);
al = new ArrayList<>();
clients = new ArrayList<>();
initNet();
}
private void initNet() {
Socket ds = null;
try {
ss = new ServerSocket(SERVER_PORT, 1);
while (true) {
ds = ss.accept();
clients.add(new ClientHandler(ds));
}
} catch (Exception e) {
System.out.println("shutting down server......");
}
}
class ClientHandler extends Thread {
private Socket ds;
private ObjectOutputStream out;
private ObjectInputStream in;
public ClientHandler(Socket ds) throws Exception {
this.ds = ds;
out = new ObjectOutputStream(ds.getOutputStream());
in = new ObjectInputStream(ds.getInputStream());
start();
}
public ObjectOutputStream getOut() {
return out;
}
public void run() {
try {
while (true) {
acceptData(in);
broadcastData();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Finally called. socket closed");
if (ds != null) {
try {
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private void acceptData(ObjectInputStream in) throws Exception {
System.out.println("acceptData called by " + Thread.currentThread().getName());
String s = (String) in.readObject();
al.add(s);
jta.setText(al.toString());
}
private void broadcastData() throws Exception {
System.out.println("broadcast called by " + Thread.currentThread().getName());
System.out.println("al is : \n" + al);
for (ClientHandler clnt : clients) {
clnt.getOut().writeObject(al);
clnt.getOut().flush();
}
}
Part of Client code
public class ClientGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
public static final String SERVER_IP = "127.0.0.1";
private Socket s1;
private ObjectOutputStream out;
private ObjectInputStream in;
private ArrayList<String> al;
public ClientGUI() {
initComponents();
setVisible(true);
initNet();
}
private void initNet() {
try {
s1 = new Socket(SERVER_IP, SERVER_PORT);
out = new ObjectOutputStream(s1.getOutputStream());
in = new ObjectInputStream(s1.getInputStream());
System.out.println("connected to server");
new ReadData();
} catch (Exception e) {
e.printStackTrace();
}
}
class ReadData extends Thread {
public ReadData() {
start();
}
public void run() {
System.out.println("client thread started");
try {
while (true) {
al = (ArrayList<String>) in.readObject();
System.out.println("client read completed, al is "+al);
jta.setText(al.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void textFieldActionPerformed(java.awt.event.ActionEvent evt) {
try {
out.writeObject(jtf.getText());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
This is normal behavior. If you send the same object (your ArrayList) several times to a given ObjectOutputStream, the stream will send the full object the first time, and will only send a reference to this object the next times. This is what allows sending a graph of objects without consuming too much bandwidth, and without going into infinite loops because a references b which also references a.
To make sure the ArrayList is sent a second time, you need to call reset() on the ObjectOutputStream.