(UPDATED CODE)
I'm trying to make clients communicate with server (I've made simple client-server apps, like a chatroom). The communication is created, but there is a huge delay (I send coordinates from the client to the server). It's over 10 seconds (sometimes even more). What could be the problem?
The client:
public class GameComponent extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private static final int WIDTH = 320;
private static final int HEIGHT = 240;
private static final int SCALE = 2;
private boolean running;
private JFrame frame;
Thread thread;
public static final int GRID_W = 16;
public static final int GRID_H = 16;
private Socket socket;
private DataInputStream reader;
private DataOutputStream writer;
private HashMap<Integer, OtherPlayer> oPlayers;
private ArrayList<OtherPlayer> opList;
private int maxID = 1;
private int ID;
Player player;
public GameComponent() {
//GUI code..
oPlayers = new HashMap<Integer, OtherPlayer>(); //Hash map to be able to get players by their ID's
opList = new ArrayList<OtherPlayer>(); //And an array list for easier drawing
setUpNetworking();
start();
}
public void start() {
if (running)
return;
running = true;
thread = new Thread(this);
player = new Player(GRID_W * 2, GRID_H * 2);
thread.start();
}
public void stop() {
if (!running)
return;
running = false;
}
public void run() { //The main loop, ticks 60 times every second
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while (delta >= 1) {
ticks++;
tick(delta);
delta -= 1;
shouldRender = true;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender) {
frames++;
render();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
frames = 0;
ticks = 0;
}
}
}
private void tick(double delta) { //main logic
player.move();
try {
writer.writeInt(ID); //I send the player data here (id, x, y)
writer.writeInt(player.getX());
writer.writeInt(player.getY());
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void render(Graphics2D g2d) {
//rendering the stuff
for (OtherPlayer i : opList) { //drawing a black rectangle for every other player
g2d.fillRect(i.getX(), i.getY(), GRID_W, GRID_H);
}
}
private void render() {
//more rendering...
}
public static void main(String[] args) {
new GameComponent();
}
class TKeyListener implements KeyListener {
//movement methods...
}
private void setUpNetworking() { //This is where I make my message reader and data IO
try {
socket = new Socket("127.0.0.1", 5099);
reader = new DataInputStream(socket.getInputStream());
writer = new DataOutputStream(socket.getOutputStream());
Thread rT = new Thread(new msgReader());
rT.start();
} catch (Exception e) {
e.printStackTrace();
}
}
class msgReader implements Runnable { //where I read messages
public void run() {
try {
ID = reader.readInt(); //when I connect, I get an id from the server
while(true) { //my main loop
int oid = reader.readInt(); //get the read data id
int ox, oy;
ox = reader.readInt(); //get the read player's x and y
oy = reader.readInt();
if (oid != ID){ //If not reading myself
if (oPlayers.containsKey(oid)) { //If a player with this id exists
OtherPlayer op = (OtherPlayer) oPlayers.get(oid);
op.setX(ox); //set it's x, y
op.setY(oy);
} else { //if it doesn't exist, create him
OtherPlayer op = new OtherPlayer(ox, oy);
opList.add(op);
oPlayers.put(oid, op);
}
}
maxID = reader.readInt(); //Allways read the highest current id from server
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
}
And the server:
public class ServerBase {
ServerSocket serverSocket;
ArrayList<DataOutputStream> clients;
private int id = 1;
SyncSend ss = new SyncSend();
class ClientHandler implements Runnable {
private Socket soc;
private DataInputStream reader;
private int x;
private int y;
private int id;
private boolean run = true;
public ClientHandler(Socket s) {
soc = s;
try {
reader = new DataInputStream(soc.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try {
while (run) {
id = reader.readInt();
x = reader.readInt();
y = reader.readInt();
if (id == 2)
System.out.println("x: " + x + " y: " + y);
int[] tmb = {id, x, y};
ss.sendEveryone(tmb);
}
} catch (Exception e) {
run = false;
clients.remove(this);
}
}
}
class SyncSend {
public synchronized void sendEveryone(int[] a) throws SocketException {
ArrayList<DataOutputStream> cl = (ArrayList<DataOutputStream>) clients.clone();
Iterator<DataOutputStream> it = cl.iterator();
while(it.hasNext()){
try {
DataOutputStream writer = (DataOutputStream) it.next();
writer.writeInt(a[0]);
writer.writeInt(a[1]);
writer.writeInt(a[2]);
writer.writeInt(id-1);
writer.flush();
} catch (Exception ex) {
throw new SocketException();
}
}
}
}
public void init() {
clients = new ArrayList<DataOutputStream>();
try {
serverSocket = new ServerSocket(5099);
while(true) {
Socket clientSocket = serverSocket.accept();
DataOutputStream clientWriter = new DataOutputStream(clientSocket.getOutputStream());
clients.add(clientWriter);
clientWriter.writeInt(id);
id++;
Thread t = new Thread(new ClientHandler(clientSocket));
t.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ServerBase().init();
}
}
What causes the delay? I've been searching for the reason for hours now, but with no success.
You most likely need to call flush() on the client-side. Even if this is not your current problem, it is probably a good idea.
Streams may buffer their content, meaning they may not send the data to its destination (whether that be a disk or over the wire to a server) the instant you call write (or writeInt in this case). Instead, they may wait until they get a sufficient amount of data to make the transfer "worth it". If they did not behave in this way, they would end up making lots of inefficient, smaller transfers. The downside to all of this is that you may need to call flush to tell the stream that you are done sending data for a while and that the stream should go ahead and initiate the transfer.
try to put your codes into several threads everywhere you can and then call threads, I mean you don't need to wait for every Socket and simply run all of them at same time...or something like this :)
for example in Port Scanners, you should use many threads to speed up searching...
Be aware that your call to ss.sendEveryone(tmb) is synchronized on the ss object. I am assuming this is a static variable somewhere that holds a reference to all of the clients. This means that if there are several clients sending data at the same time, a lot of calls to sendEveryone will happen all at once and they will all line up in a queue waiting for the others to finish, before those threads can go back and read more data from the client again.
As a diagnostic exercise, you may want to remove this call and see if you still have your problem.
Related
I am trying to do checkers using java sockets. However, when I run a client, it gets stuck in a loop and stops responding.
So far my app has methods to draw a board, move checkers and create connection between a server and clients.
The connection is created correctly.
The problem is with play() which is responsible for handle server messages.
Pls help me to modify play() to have it working.
Client App
public class CheckersApp extends Application {
public static final int TILE_SIZE = 100;
public static final int WIDTH = 8;
public static final int HEIGHT = 8;
private Tile[][] board = new Tile[WIDTH][HEIGHT];
private Group tileGroup = new Group();
private Group pieceGroup = new Group();
private Label text = new Label();
private static int PORT = 8901;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
// method to draw a board with checkers
private Parent createContent() {
...
}
// method to check if moving checkers is possbile
private MoveResult tryMove(Piece piece, int newX, int newY) {
...
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createContent());
primaryStage.setTitle("CheckersApp");
primaryStage.setScene(scene);
primaryStage.show();
// Setup networking
socket = new Socket("LAP00132", PORT);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
play();
}
// method to move checkers
private Piece makePiece(PieceType type, int x, int y) {
...
}
// method to get responses from Server
public void play() throws Exception {
String response;
try {
response = in.readLine();
if (response.startsWith("WELCOME")) {
// char mark = response.charAt(8);
}
while (true) {
response = in.readLine();
if (response.startsWith("VALID_MOVE")) {
text.setText("Valid move, please wait");
} else if (response.startsWith("OPPONENT_MOVED")) {
text.setText("Opponent moved, your turn");
} else if (response.startsWith("VICTORY")) {
text.setText("You win");
break;
} else if (response.startsWith("DEFEAT")) {
text.setText("You lose");
break;
} else if (response.startsWith("TIE")) {
text.setText("You tied");
break;
} else if (response.startsWith("MESSAGE")) {
text.setText(response.substring(8));
}
}
out.println("QUIT");
}
finally {
socket.close();
}
}
public static void main(String[] args) {
launch(args);}
Server App
public class Server {
/**
* Runs the application. Pairs up clients that connect.
*/
public static void main(String[] args) throws Exception {
ServerSocket listener = new ServerSocket(8901);
System.out.println("Server is Running");
try {
while (true) {
Game game = new Game();
Game.Player playerX = game.new Player(listener.accept(), 'X');
System.out.println("Połączony X");
Game.Player playerO = game.new Player(listener.accept(), 'O');
System.out.println("Połączony O");
playerX.setOpponent(playerO);
playerO.setOpponent(playerX);
game.currentPlayer = playerX;
playerX.start();
playerO.start();
}
} finally {
listener.close();}}}
class Game {
public static final int WIDTH = 8;
public static final int HEIGHT = 8;
//private Tile[][] board = new Tile[WIDTH][HEIGHT];
Player currentPlayer;
/**
* Called by the player threads when a player tries to make a
* move. This method checks to see if the move is legal: that
* is, the player requesting the move must be the current player
*/
public synchronized boolean legalMove(Player player) {
if (player == currentPlayer) {
currentPlayer = currentPlayer.opponent;
currentPlayer.otherPlayerMoved();
return true;
}
return false;
}
class Player extends Thread {
char mark;
Player opponent;
Socket socket;
BufferedReader input;
PrintWriter output;
/**
* Constructs a handler thread for a given socket and mark
* initializes the stream fields, displays the first two
* welcoming messages.
*/
public Player(Socket socket, char mark) {
this.socket = socket;
this.mark = mark;
try {
input = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(socket.getOutputStream(), true);
output.println("WELCOME " + mark);
System.out.println("Welcome ");
output.println("MESSAGE Waiting for opponent to connect");
} catch (IOException e) {
System.out.println("Player died: " + e);
}
}
/**
* Accepts notification of who the opponent is.
*/
public void setOpponent(Player opponent) {
this.opponent = opponent;
}
/**
* Handles the otherPlayerMoved message.
*/
public void otherPlayerMoved() {
output.println("OPPONENT_MOVED ");
System.out.println("OPPONENT_MOVED");
}
/**
* The run method of this thread.
*/
public void run() {
try {
// The thread is only started after everyone connects.
output.println("MESSAGE All players connected");
// Tell the first player that it is her turn.
if (mark == 'X') {
output.println("MESSAGE Your move");
}
// Repeatedly get commands from the client and process them.
while (true) {
String command = input.readLine();
if (command.startsWith("MOVE")) {
if (legalMove(this)) {
output.println("VALID_MOVE");
System.out.println("VALID MOVE");
} else {
output.println("MESSAGE ?");
}
} else if (command.startsWith("QUIT")) {
return;
}
}
} catch (IOException e) {
System.out.println("Player died: " + e);
} finally {
try {socket.close();} catch (IOException e) {}
}
}
}}
Your while(true) loop just waits for a line. It blocks the ability to perform any actions on the UI.
Spawn a separate thread to handle server communications. Obviously you need to be aware of the dangers of multi-threading and multi-thread access of model and UI data.
I created a thread to play an mp3 file in Java by converting it to an array of bytes.
I'm wondering if I can keep track of the current play position as the mp3 is being played.
First, I set up my music stream like so:
try {
AudioInputStream in = AudioSystem.getAudioInputStream(file);
musicInputStream = AudioSystem.getAudioInputStream(MUSIC_FORMAT, in);
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, MUSIC_FORMAT);
musicDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
musicDataLine.open(MUSIC_FORMAT);
musicDataLine.start();
startMusicThread();
} catch(Exception e) {
e.printStackTrace();
}
Next, my music thread looks like this:
private class MusicThread extends Thread {
byte musicBuffer[] = new byte[BUFFER_SIZE];
public void run() {
try {
int musicCount = 0;
while(writeOutput){
if(writeMusic && (musicCount = musicInputStream.read(musicBuffer, 0, musicBuffer.length)) > 0){
musicDataLine.write(musicBuffer, 0, musicCount);
}
}
} catch (Exception e) {
System.out.println("AudioStream Exception - Music Thread"+e);
e.printStackTrace();
}
}
}
I thought of one possibility, to create another thread with a timer that slowly ticks down, second by second, to show the remaining amount of time for the mp3 song. But that doesn't seem like a good solution at all.
Your int musicCount (the return value from AudioInputStream.read(...)) tells you the number of bytes read, so with that you can do a small computation to figure out your place in the stream always. (DataLine has some methods to do some of the math for you but they can't always be used...see below.)
int musicCount = 0;
int totalBytes = 0;
while ( loop stuff ) {
// accumulate it
// and do whatever you need with it
totalBytes += musicCount;
musicDataLine.write(...);
}
To get the number of seconds elapsed, you can do the following things:
AudioFormat fmt = musicInputStream.getFormat();
long framesRead = totalBytes / fmt.getFrameSize();
long totalFrames = musicInputStream.getFrameLength();
double totalSeconds = (double) totalFrames / fmt.getSampleRate();
double elapsedSeconds =
((double) framesRead / (double) totalFrames) * totalSeconds;
So you'd just get the elapsed time each loop and put it wherever you need it to go. Note that the accuracy of this kind of depends on the size of your buffer. The smaller the buffer, the more accurate.
Also, Clip has some methods to query this for you (but you'd probably have to change what you're doing a lot).
These methods (get(Long)FramePosition/getMicrosecondPosition) are inherited from DataLine, so you can also call them on the SourceDataLine as well if you don't want to do the math yourself. However, you basically need to make a new line for every file you play, so it depends on how you're using the line. (Personally I'd rather just do the division myself since asking the line is kind of opaque.)
BTW:
musicDataLine.open(MUSIC_FORMAT);
You should open the line with your own buffer size specified, using the (AudioFormat, int) overload. SourceDataLine.write(...) only blocks when its internal buffer is full, so if it's a different size from your byte array, sometimes your loop is blocking, other times it's just spinning.
MCVE for good measure:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.sound.sampled.*;
public class SimplePlaybackProgress
extends WindowAdapter implements Runnable, ActionListener {
class AudioPlayer extends Thread {
volatile boolean shouldPlay = true;
final int bufferSize;
final AudioFormat fmt;
final AudioInputStream audioIn;
final SourceDataLine audioOut;
final long frameSize;
final long totalFrames;
final double sampleRate;
AudioPlayer(File file)
throws UnsupportedAudioFileException,
IOException,
LineUnavailableException {
audioIn = AudioSystem.getAudioInputStream(file);
fmt = audioIn.getFormat();
bufferSize = fmt.getFrameSize() * 8192;
frameSize = fmt.getFrameSize();
totalFrames = audioIn.getFrameLength();
sampleRate = fmt.getSampleRate();
try {
audioOut = AudioSystem.getSourceDataLine(audioIn.getFormat());
audioOut.open(fmt, bufferSize);
} catch (LineUnavailableException x) {
try {
audioIn.close();
} catch(IOException suppressed) {
// Java 7+
// x.addSuppressed(suppressed);
}
throw x;
}
}
#Override
public void run() {
final byte[] buffer = new byte[bufferSize];
long framePosition = 0;
try {
audioOut.start();
while (shouldPlay) {
int bytesRead = audioIn.read(buffer);
if (bytesRead < 0) {
break;
}
int bytesWritten = audioOut.write(buffer, 0, bytesRead);
if (bytesWritten != bytesRead) {
// shouldn't happen
throw new RuntimeException(String.format(
"read: %d, wrote: %d", bytesWritten, bytesRead));
}
framePosition += bytesRead / frameSize;
// or
// framePosition = audioOut.getLongFramePosition();
updateProgressBar(framePosition);
}
audioOut.drain();
audioOut.stop();
} catch (Throwable x) {
showErrorMessage(x);
} finally {
updateProgressBar(0);
try {
audioIn.close();
} catch (IOException x) {
showErrorMessage(x);
}
audioOut.close();
}
}
void updateProgressBar(
final long framePosition) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
double fractionalProgress =
(double) framePosition / (double) totalFrames;
int progressValue = (int) Math.round(
fractionalProgress * theProgressBar.getMaximum());
theProgressBar.setValue(progressValue);
int secondsElapsed = (int) Math.round(
(double) framePosition / sampleRate);
int minutes = secondsElapsed / 60;
int seconds = secondsElapsed % 60;
theProgressBar.setString(String.format(
"%d:%02d", minutes, seconds));
}
});
}
void stopPlaybackAndDrain() throws InterruptedException {
shouldPlay = false;
this.join();
}
}
/* * */
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimplePlaybackProgress());
}
JFrame theFrame;
JButton theButton;
JProgressBar theProgressBar;
// this should only ever have 1 thing in it...
// multithreaded code with poor behavior just bugs me,
// even for improbable cases, so the queue makes it more robust
final Queue<AudioPlayer> thePlayerQueue = new ArrayDeque<AudioPlayer>();
#Override
public void run() {
theFrame = new JFrame("Playback Progress");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theButton = new JButton("Open");
theProgressBar = new JProgressBar(
SwingConstants.HORIZONTAL, 0, 1000);
theProgressBar.setStringPainted(true);
theProgressBar.setString("0:00");
Container contentPane = theFrame.getContentPane();
((JPanel) contentPane).setBorder(
BorderFactory.createEmptyBorder(8, 8, 8, 8));
contentPane.add(theButton, BorderLayout.WEST);
contentPane.add(theProgressBar, BorderLayout.CENTER);
theFrame.pack();
theFrame.setResizable(false);
theFrame.setLocationRelativeTo(null);
theFrame.setVisible(true);
theButton.addActionListener(this);
theFrame.addWindowListener(this);
}
#Override
public void actionPerformed(ActionEvent ae) {
JFileChooser dialog = new JFileChooser();
int option = dialog.showOpenDialog(theFrame);
if (option == JFileChooser.APPROVE_OPTION) {
File file = dialog.getSelectedFile();
try {
enqueueNewPlayer(new AudioPlayer(file));
} catch (UnsupportedAudioFileException x) { // ew, Java 6
showErrorMessage(x); //
} catch (IOException x) { //
showErrorMessage(x); //
} catch (LineUnavailableException x) { //
showErrorMessage(x); //
} //
}
}
#Override
public void windowClosing(WindowEvent we) {
stopEverything();
}
void enqueueNewPlayer(final AudioPlayer newPlayer) {
// stopPlaybackAndDrain calls join
// so we want to do it off the EDT
new Thread() {
#Override
public void run() {
synchronized (thePlayerQueue) {
stopEverything();
newPlayer.start();
thePlayerQueue.add(newPlayer);
}
}
}.start();
}
void stopEverything() {
synchronized (thePlayerQueue) {
while (!thePlayerQueue.isEmpty()) {
try {
thePlayerQueue.remove().stopPlaybackAndDrain();
} catch (InterruptedException x) {
// shouldn't happen
showErrorMessage(x);
}
}
}
}
void showErrorMessage(Throwable x) {
x.printStackTrace(System.out);
String errorMsg = String.format(
"%s:%n\"%s\"", x.getClass().getSimpleName(), x.getMessage());
JOptionPane.showMessageDialog(theFrame, errorMsg);
}
}
For Clip, you'd just have something like a Swing timer (or other side-thread) and query it however often:
new javax.swing.Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
long usPosition = theClip.getMicrosecondPosition();
// put it somewhere
}
}).start();
Related:
How to calculate the level/amplitude/db of audio signal in java?
How to make waveform rendering more interesting?
I'm writing a program that constantly pings a server. I wrote the code to check it once and put the ping in a JLabel and put it in a method called setPing().
Here is my code
private void formWindowOpened(java.awt.event.WindowEvent evt) {
setPing();
}
That worked but only did it once, so I did:
private void formWindowOpened(java.awt.event.WindowEvent evt) {
for(;;){
setPing();
}
}
But this doesn't even work for the first time.
I didnt put the setPing method because it was too long so here it is:
public String setPing(){
Runtime runtime = Runtime.getRuntime();
try{
Process process = runtime.exec("ping lol.garena.com");
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
int i = 0;
i = line.indexOf("Average");
if(i > 0){
String finalPing = "";
line.toCharArray();
try
{
finalPing = "";
for(int x = i; x < i + 17; x++)
{
finalPing = finalPing + (line.charAt(x));
}
}catch(IndexOutOfBoundsException e)
{
try
{
finalPing = "";
for(int x = i; x < i + 16; x++)
{
finalPing = finalPing + (line.charAt(x));
}
}catch(IndexOutOfBoundsException f)
{
try
{
finalPing = "";
for(int x = i; x < i + 15; x++)
{
finalPing = finalPing + (line.charAt(x));
}
}catch(IndexOutOfBoundsException g){}
}
}
String final1Ping = finalPing.replaceAll("[^0-9]", "");
return final1Ping;
}
}
}catch(IOException e){
}
return "";
}
UPDATE
Just in case this is important, Im using netbeans. I created a form and put this code in the formWindowOpened evt instead of calling it in main:
private void formWindowOpened(java.awt.event.WindowEvent evt) {
ActionListener timerListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new PingWorker().execute();
}
};
Timer timer = new Timer(1000, timerListener);
timer.start();
jLabel1.setText(label.getText());
timer.stop();
// TODO add your handling code here:
}
class PingWorker extends SwingWorker {
int time;
#Override
protected Object doInBackground() throws Exception {
time = pingTime("lol.garena.com");
return new Integer(time);
}
#Override
protected void done() {
label.setText("" + time);
}
};
public JComponent getUI() {
return label;
}
public static int pingTime(String hostnameOrIP) {
Socket socket = null;
long start = System.currentTimeMillis();
try {
socket = new Socket(hostnameOrIP, 80);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
long end = System.currentTimeMillis();
return (int) (end - start);
}
Use a Swing Timer for repeating tasks & a SwingWorker for long running tasks. E.G. of both below - it uses a Timer to repeatedly perform a 'long running' task (a ping) in a SwingWorker.
See Concurrency in Swing for more details on the Event Dispatch Thread and doing long running or repeating tasks in a GUI.
This code combines a long running task ('pinging' a server) using SwingWorker invoked from a repeating task (updating the JLabel repeatedly with the times) using a Swing based Timer.
import java.awt.event.*;
import javax.swing.*;
import java.net.Socket;
public class LabelUpdateUsingTimer {
static String hostnameOrIP = "stackoverflow.com";
int delay = 5000;
JLabel label = new JLabel("0000");
LabelUpdateUsingTimer() {
label.setFont(label.getFont().deriveFont(120f));
ActionListener timerListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new PingWorker().execute();
}
};
Timer timer = new Timer(delay, timerListener);
timer.start();
JOptionPane.showMessageDialog(
null, label, hostnameOrIP, JOptionPane.INFORMATION_MESSAGE);
timer.stop();
}
class PingWorker extends SwingWorker {
int time;
#Override
protected Object doInBackground() throws Exception {
time = pingTime();
return new Integer(time);
}
#Override
protected void done() {
label.setText("" + time);
}
};
public static int pingTime() {
Socket socket = null;
long start = System.currentTimeMillis();
try {
socket = new Socket(hostnameOrIP, 80);
} catch (Exception weTried) {
} finally {
if (socket != null) {
try {
socket.close();
} catch (Exception weTried) {}
}
}
long end = System.currentTimeMillis();
return (int) (end - start);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new LabelUpdateUsingTimer();
}
};
SwingUtilities.invokeLater(r);
}
}
You could use a Thread. The problem is you are blocking the main thread, thereby blocking your program. To get around this, start a background Thread to update components repeatedly.
(Note: you need to update GUI components on the EDT, so use SwingUtilities.invokeLater)
(new Thread((new Runnable(){
#Override
public void run(){
while(true){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
refToJLabel.setText(Math.random());
}
});
}
}
}))).start();
There is a problem, the following code does not work
code:
Server
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
static ServerSocket serverSocket;
static Socket socket;
static DataOutputStream out;
static DataInputStream in;
static Users[] user = new Users[10];
public static void main(String[] args) {
try {
System.out.println("Server Started...");
serverSocket = new ServerSocket(7778);
System.out.println("Server Start.");
while (true) {
socket = serverSocket.accept();
for (int i = 0; i < 10; i++) {
if (user[i] == null) {
System.out.println("Conection from"
+ socket.getInetAddress());
out = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
user[i] = new Users(out, in, user, i);
Thread thread = new Thread(user[i]);
thread.start();
break;
}
}
}
} catch (IOException e) {
}
}
}
class Users implements Runnable {
DataOutputStream out;
DataInputStream in;
Users[] user = new Users[10];
String name;
int playerid;
int playeridln;
int xin;
int yin;
public Users(DataOutputStream out, DataInputStream in, Users[] user, int pid) {
this.out = out;
this.in = in;
this.user = user;
this.playerid = pid;
}
public void run() {
try {
out.writeInt(playerid);
} catch (IOException e1) {
System.out.println("Failed to send PlayerID");
}
while (true) {
try {
playeridln = in.readInt();
xin = in.readInt();
yin = in.readInt();
for (int i = 0; i < 10; i++) {
if (user[i] != null) {
user[i].out.writeInt(playeridln);
user[i].out.writeInt(xin);
user[i].out.writeInt(yin);
}
}
} catch (IOException e) {
user[playerid] = null;
break;
}
}
}
}
Client
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Client extends JPanel implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
static Socket socket;
static DataInputStream in;
static DataOutputStream out;
int playerid;
int[] x = new int[10];
int[] y = new int[10];
boolean left, up, right, down;
int playerx;
int playery;
public Client() {
init();
}
public void init() {
try {
System.out.println("Conecting to serever...");
socket = new Socket("localhost", 7778);
System.out.println("Connection successful");
in = new DataInputStream(socket.getInputStream());
playerid = in.readInt();
out = new DataOutputStream(socket.getOutputStream());
Input input = new Input(in, this);
Thread thread = new Thread(input);
thread.start();
Thread thread2 = new Thread(this);
thread2.start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void updateCoordinates(int pid, int x2, int y2) {
this.x[pid] = x2;
this.y[pid] = y2;
}
public void paint(Graphics g) {
repaint();
for (int i = 0; i < 10; i++) {
g.drawOval(x[i], y[i], 5, 5);
}
}
public void run() {
while (true) {
if (right) {
playerx += 10;
}
if (left) {
playerx -= 10;
}
if (down) {
playery += 10;
}
if (up) {
playery -= 10;
}
if (right || left || up || down) {
try {
out.writeInt(playerid);
out.writeInt(playerx);
out.writeInt(playery);
} catch (Exception e) {
System.out.println("Erro Coordinates");
}
}
repaint();
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 37) {
left = true;
}
if (e.getKeyCode() == 38) {
up = true;
}
if (e.getKeyCode() == 39) {
right = true;
}
if (e.getKeyCode() == 40) {
down = true;
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 37) {
left = false;
}
if (e.getKeyCode() == 38) {
up = false;
}
if (e.getKeyCode() == 39) {
right = false;
}
if (e.getKeyCode() == 40) {
down = false;
}
}
public void keyTyped(KeyEvent e) {
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(300, 300);
f.getContentPane().add(new Client());
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class Input implements Runnable {
DataInputStream in;
Client client;
public Input(DataInputStream in, Client c) {
this.in = in;
this.client = c;
}
public void run() {
while (true) {
try {
int playerd = in.readInt();
int x = in.readInt();
int y = in.readInt();
client.updateCoordinates(playerd, x, y);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
When I run the code (run multiple windows to check) It does not work, even though the circle should move ..
Help to solve it, please)
Thank you in advance!
This is rather complicated stuff. There's two problems I can see.
Minor problem (I think): Swing classes and methods, with very few exceptions (such as the repaint() method in Component/JComponent) must run on the event queue. In your Client the main() method, which runs on the startup thread, creates a JFrame and calls several methods. Everybody does this, and I think everybody gets away with it, but it's dangerous. Use EventQueue.InvokeLater to put the code onto the UI thread. I checked your run() methods, but they don't seem to touch Swing, (other than a legit call to repaint()) but keep an eye on them. Call a Swing method from there and you'll have a bigger problem.
Major problem: You have a bunch of fields referenced in the Client run method and in some button code (running on the UI thread). (playerx, playery, left, right, up, down) Synchronization is not really a problem here. However, the JVM is under no obligation (though it can if it wants) to inform a thread of changes made by other threads. Having done this myself, I've found that sometimes the threads see changes immediately, sometimes after a noticable lag (leading to annoying, jumpy graphics), and sometimes never.
The language spec requires that data be transferred between threads when a thread starts, when it finishes with a join, when a thread enters a synch block after another thread has left a block synched on the same object, when a volatile field is written and read, and after calls to Atomic methods.
So what you want to do is go through, manually, all the fields in your Client class and for each one make sure it is marked as final, volatile, or referenced only in synchronized blocks or only referenced on one thread (like Swing methods). The quickest thing for you to do would be make those fields volatile. Synch blocks might be more efficient. I believe that they cost more to get into and out of than reads and writes to volatiles, but once in you can modify a bunch of fields at little extra cost.
I made a simple GUI that has 5 tables and forks and tried to visualize this famous problem, but I cannot achieve to fully implement. I didn't get the stuck point for my code, if anyone have suggestion for me to solve this problem, any help would be appreciated and thanks in advance!
Extra Note: There is also an error that i guess it is about my array creation ideas, i have an error as java.lang.ArrayIndexOutOfBoundsException: 5.
public class Philosopher implements Runnable {
private static Table table;
private int ID;
private int N = 5;
private static Semaphore s1 = new Semaphore(1) ;
private static Semaphore[] sarray = new Semaphore[5];
private int[] array = new int[5];
private int thinking = 0;
private int hungry = 1;
private int eating = 2;
private int left = (ID + N - 1) % N;
private int right = (ID + 1) % N;
void test(int i)
{
if((array[i] == hungry) && (array[left] != eating) && (array[right] != eating))
{
table.ForkTake_GUI(i);
array[i] = eating;
sarray[i].release();
}
}
void take_forks(int i)
{
try {
s1.acquire();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
array[i] = hungry;
table.Hungry_GUI(i);
test(i);
s1.release();
table.Eating_GUI(i);
sarray[i].release();
}
void put_forks(int i)
{
table.StopEating_GUI(i);
try {
s1.acquire();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
array[i] = thinking;
test(left);
test(right);
table.ForkPut_GUI(i);
s1.release();
}
public Philosopher(int i)
{
setID(i);
}
public void run()
{
while(true)
{
Random RandomGenerator = new Random();
int randomNum = RandomGenerator.nextInt(10);
try {
Thread.sleep((randomNum * 1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
take_forks(ID);
//table.Eating_GUI();
put_forks(ID);
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
table = new Table();
table.frame.setVisible(true);
}
catch(Exception e){
e.printStackTrace();
}
}
});
Philosopher p1 = new Philosopher(1);
Philosopher p2 = new Philosopher(2);
Philosopher p3 = new Philosopher(3);
Philosopher p4 = new Philosopher(4);
Philosopher p5 = new Philosopher(5);
Thread pt1 = new Thread(p1);
Thread pt2 = new Thread(p2);
Thread pt3 = new Thread(p3);
Thread pt4 = new Thread(p4);
Thread pt5 = new Thread(p5);
sarray[0] = new Semaphore(1);
sarray[1] = new Semaphore(1);
sarray[2] = new Semaphore(1);
sarray[3] = new Semaphore(1);
sarray[4] = new Semaphore(1);
pt1.start();
pt2.start();
pt3.start();
pt4.start();
pt5.start();
}
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
}
Take a look at where you acquire a mutex from sarray - point is that you don't, so at least there's redundant code in there.
Further notes:
You define N but use the magic number 5 all over.
You seem to have one "central" mutex and one for each fork. Using a central mutex would already solve the original problem.
Consider putting each mutex and the data it protects into an aggregate. That would make it clear that the five mutexes are for the five forks and not for the five philosophers, or?
Your out-of-bounds is obviously caused by a shift between 1-base and 0-based indices. Could that be caused by changing ID after computing left and right? In general, I wouldn't store these as members. Also, be aware that the values you have there are for the philosophers, not for the forks! Draw a picture, that will help you get those right!