Hello everyone,

Let me give some short background on my problem. I am developing a simple network cardgame, but I am first creating the building blocks.

I have a very simple server java application running (no threading yet, just sockets)
and simple client java application, created with jFrames and uses sockets and treading.

My primary goal is very simple. Request a card from the server (this is currently done by sending an instruction object through a socket, containing a card object.

Server on the first request of a card sends an int value of 0, and an string suit of spade. Value is incremented with every request (to make sure the server is running correctly, even when the client disconnects and reconnects)

This is all working fine.

The client has 3 textboxes and one button. The two smaller boxes used display the value of the card and suit respectively, and a 3rd box to display messages from the server (currently the only message is "Connection Successful"

The problem is that when I hit "Request Card" button, the textboxes are not being updated. My understanding is that the thread is not able to redraw the form. If I have the thread display to System.out, I can see the data that I expect to see in the textboxes, so I can conclude that the server is sending data, and the client is receiving it properly.

I have also tried moving the code in which I can update the textboxes into the main program, as part of the "Request Card" button, but now I run into race conditions in which the thread might not receive data in time for the data to be displayed. If I hit the button multiple times, you can see that sometimes it DOES update with this change, but not all the time.

Here is the code. textbox updates under jbtnRequestCardActionPerformed have been commented out, this was the race condition. I am leaving out the objects "card" and "instruction" since they are not actually causing a problem. They are both serializeable.

Areas to look at:
public void run() from CLIENT
jbtnRequestCardActionPerformed from CLIENT

SERVER:
package serverprovider;
 
import cardgame.*;
import java.io.*;
import java.net.*;
 
public class ServerPovider {
 
    ServerSocket providerSocket;
    Socket connection = null;
    ObjectOutputStream out;
    ObjectInputStream in;
    String message;
    instruction instr = new instruction();
    boolean listening = false;
    static int cardCount = 0;
 
    ServerPovider() {
    }
 
    void run() {
        try {
            //1. creating a server socket
            //while(listening) {
            providerSocket = new ServerSocket(2004, 5);
            //2. Wait for connection
            System.out.println("Waiting for connection");
            connection = providerSocket.accept();
            System.out.println("Connection received from " + connection.getInetAddress().getHostName());
            //3. get Input and Output streams
            out = new ObjectOutputStream(connection.getOutputStream());
            out.flush();
            in = new ObjectInputStream(connection.getInputStream());
            sendMessage("Connection successful");
            //4. The two parts communicate via the input and output streams
            do {
                try {
                    instr = (cardgame.instruction) in.readObject();
 
                    if (instr.getHeader() == 1) {
                        message = (String) instr.getObj();
                        System.out.println("client>" + message);
 
                        if (message.equals("bye")) {
                            //sendMessage("bye");
                        } else {
                            sendCard();
                        }
                    }
                } catch (ClassNotFoundException classnot) {
                    System.err.println("Data received in unknown format");
                }
            } while (!message.equals("bye"));
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } finally {
            //4: Closing connection
            try {
                in.close();
                out.close();
                providerSocket.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }
 
    void sendMessage(String msg) {
        try {
            instr.setHeader(1);
            instr.setObj(msg);
            out.writeObject(instr);
            out.flush();
            System.out.println("server>" + msg);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
 
    void sendCard() {
        card deckocards = new card();
 
        try {
            instr.setHeader(2);
 
            deckocards.setSuit("Spade");
            deckocards.setValue(cardCount);
            cardCount++;
 
            instr.setObj(deckocards);
            out.writeObject(instr);
            out.flush();
            System.out.println("server>" + "Sending deckocard");
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
 
    public static void main(String args[]) {
        ServerPovider server = new ServerPovider();
        while (true) {
            server.run();
        }
    }
}

CLIENT:
/* Client Program
 * PokerFace.java
 *
 * Created on 9-Mar-2011, 3:23:49 PM
 */
package client;
 
import java.io.*;
import java.net.*;
import cardgame.*;
import javax.swing.SwingUtilities;
 
/**
 *
 * @author Jeff
 */
public class PokerFace extends javax.swing.JFrame implements Runnable {
 
    static Socket requestSocket;
    static ObjectOutputStream out;
    static ObjectInputStream in;
    static card deckocard = new card();
 
    /** Creates new form PokerFace */
    public PokerFace() {
        initComponents();
    }
 
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {
 
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();
        jlblSuit = new javax.swing.JLabel();
        jlblValue = new javax.swing.JLabel();
        jtxtSuit = new javax.swing.JTextField();
        jtxtValue = new javax.swing.JTextField();
        jbtnRequestCard = new javax.swing.JButton();
 
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });
 
        jTextArea1.setColumns(20);
        jTextArea1.setRows(5);
        jScrollPane1.setViewportView(jTextArea1);
 
        jlblSuit.setText("Suit");
 
        jlblValue.setText("Value");
 
        jbtnRequestCard.setText("Request Card");
        jbtnRequestCard.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtnRequestCardActionPerformed(evt);
            }
        });
 
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
                        .addContainerGap())
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jlblValue)
                            .addComponent(jlblSuit))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(jtxtValue)
                            .addComponent(jtxtSuit, javax.swing.GroupLayout.DEFAULT_SIZE, 77, Short.MAX_VALUE)
                            .addComponent(jbtnRequestCard, javax.swing.GroupLayout.Alignment.LEADING))
                        .addGap(71, 71, 71))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(33, 33, 33)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jlblSuit)
                    .addComponent(jtxtSuit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jlblValue)
                    .addComponent(jtxtValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(42, 42, 42)
                .addComponent(jbtnRequestCard)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 58, Short.MAX_VALUE)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
 
        pack();
    }// </editor-fold>
 
    private void jbtnRequestCardActionPerformed(java.awt.event.ActionEvent evt) {                                        
        sendMessage("New card please!");
 
        //jtxtSuit.setText(deckocard.getSuit());
        //jtxtValue.setText(String.valueOf(deckocard.getValue()));
    }                                       
 
    private void formWindowOpened(java.awt.event.WindowEvent evt) {
 
        try {
            //1. creating a socket to connect to the server
            requestSocket = new Socket("localhost", 2004);
            System.out.println("Connected to localhost in port 2004");
            //2. get Input and Output streams
            out = new ObjectOutputStream(requestSocket.getOutputStream());
            out.flush();
            in = new ObjectInputStream(requestSocket.getInputStream());
 
            new Thread(new PokerFace()).start();
        } catch (UnknownHostException unknownHost) {
            System.err.println("You are trying to connect to an unknown host!");
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
 
    private void formWindowClosing(java.awt.event.WindowEvent evt) {
        String message;
        try {
            message = "bye";
            sendMessage(message);
            in.close();
            out.close();
            requestSocket.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
 
    public void run() {
        instruction instr = new instruction();
        String message = new String();
        //3: Communicating with the server
        do {
            try {
                instr = (instruction) in.readObject();
 
                if (instr.getHeader() == 1) {
                    message = (String) instr.getObj();
                    jTextArea1.append("server>" + message);
 
                } else if (instr.getHeader() == 2) {
                    deckocard = (card) instr.getObj();
                    jtxtSuit.setText(deckocard.getSuit());
                    jtxtValue.setText(String.valueOf(deckocard.getValue()));
 
                    System.out.println(deckocard.ToString());
 
                }
            } catch (ClassNotFoundException classNot) {
                System.err.println("data received in unknown format");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        } while (!message.equals("bye"));
    }
 
    void sendMessage(String msg) {
        instruction instr = new instruction();
        try {
            instr.setHeader(1);
            instr.setObj(msg);
            out.writeObject(instr);
            out.flush();
            System.out.println("server>" + msg);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
 
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
 
            public void run() {
                new PokerFace().setVisible(true);
            }
        });
 
 
    }
    // Variables declaration - do not modify
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JButton jbtnRequestCard;
    private javax.swing.JLabel jlblSuit;
    private javax.swing.JLabel jlblValue;
    private javax.swing.JTextField jtxtSuit;
    private javax.swing.JTextField jtxtValue;
    // End of variables declaration
}

CLIENT FORM:
<?xml version="1.1" encoding="UTF-8" ?>
 
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
  <Properties>
    <Property name="defaultCloseOperation" type="int" value="3"/>
  </Properties>
  <SyntheticProperties>
    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
  </SyntheticProperties>
  <Events>
    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
    <EventHandler event="windowOpened" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowOpened"/>
  </Events>
  <AuxValues>
    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
  </AuxValues>
 
  <Layout>
    <DimensionLayout dim="0">
      <Group type="103" groupAlignment="0" attributes="0">
          <Group type="102" attributes="0">
              <EmptySpace max="-2" attributes="0"/>
              <Group type="103" groupAlignment="0" attributes="0">
                  <Group type="102" alignment="0" attributes="0">
                      <Component id="jScrollPane1" pref="380" max="32767" attributes="0"/>
                      <EmptySpace max="-2" attributes="0"/>
                  </Group>
                  <Group type="102" alignment="1" attributes="0">
                      <Group type="103" groupAlignment="1" attributes="0">
                          <Component id="jlblValue" alignment="1" min="-2" max="-2" attributes="0"/>
                          <Component id="jlblSuit" alignment="1" min="-2" max="-2" attributes="0"/>
                      </Group>
                      <EmptySpace max="-2" attributes="0"/>
                      <Group type="103" groupAlignment="1" max="-2" attributes="0">
                          <Component id="jtxtValue" max="32767" attributes="1"/>
                          <Component id="jtxtSuit" alignment="1" pref="77" max="32767" attributes="1"/>
                          <Component id="jbtnRequestCard" alignment="0" min="-2" max="-2" attributes="0"/>
                      </Group>
                      <EmptySpace min="-2" pref="71" max="-2" attributes="0"/>
                  </Group>
              </Group>
          </Group>
      </Group>
    </DimensionLayout>
    <DimensionLayout dim="1">
      <Group type="103" groupAlignment="0" attributes="0">
          <Group type="102" alignment="1" attributes="0">
              <EmptySpace min="-2" pref="33" max="-2" attributes="0"/>
              <Group type="103" groupAlignment="3" attributes="0">
                  <Component id="jlblSuit" alignment="3" min="-2" max="-2" attributes="0"/>
                  <Component id="jtxtSuit" alignment="3" min="-2" max="-2" attributes="0"/>
              </Group>
              <EmptySpace type="unrelated" max="-2" attributes="0"/>
              <Group type="103" groupAlignment="0" attributes="0">
                  <Component id="jlblValue" min="-2" max="-2" attributes="0"/>
                  <Component id="jtxtValue" min="-2" max="-2" attributes="0"/>
              </Group>
              <EmptySpace min="-2" pref="42" max="-2" attributes="0"/>
              <Component id="jbtnRequestCard" min="-2" max="-2" attributes="0"/>
              <EmptySpace pref="58" max="32767" attributes="0"/>
              <Component id="jScrollPane1" min="-2" max="-2" attributes="0"/>
              <EmptySpace max="-2" attributes="0"/>
          </Group>
      </Group>
    </DimensionLayout>
  </Layout>
  <SubComponents>
    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
      <AuxValues>
        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
      </AuxValues>
 
      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
      <SubComponents>
        <Component class="javax.swing.JTextArea" name="jTextArea1">
          <Properties>
            <Property name="columns" type="int" value="20"/>
            <Property name="rows" type="int" value="5"/>
          </Properties>
        </Component>
      </SubComponents>
    </Container>
    <Component class="javax.swing.JLabel" name="jlblSuit">
      <Properties>
        <Property name="text" type="java.lang.String" value="Suit"/>
      </Properties>
    </Component>
    <Component class="javax.swing.JLabel" name="jlblValue">
      <Properties>
        <Property name="text" type="java.lang.String" value="Value"/>
      </Properties>
    </Component>
    <Component class="javax.swing.JTextField" name="jtxtSuit">
      <Events>
        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jtxtSuitActionPerformed"/>
      </Events>
    </Component>
    <Component class="javax.swing.JTextField" name="jtxtValue">
    </Component>
    <Component class="javax.swing.JButton" name="jbtnRequestCard">
      <Properties>
        <Property name="text" type="java.lang.String" value="Request Card"/>
      </Properties>
      <Events>
        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jbtnRequestCardActionPerformed"/>
      </Events>
    </Component>
  </SubComponents>
</Form>