I want to read and write(randomly from server to client) on same server socket (java application). My client to server write and read work fine in a loop. At server with response write properly.
But if i am trying to write at server randomly some command. i do not have solution, first of all my question is :
is it possible at server side to write command to client ramdonly on same socket?
if possible, any suggestion or pointer how to do it?
please give me some pointer where I can read the material about this scenario ?
thanks in advance.
public class ContentServerSocket extends ServerSocket {
private final static int PORT = 4444;
protected static boolean XYZGONE = false;
public static Content content;
public ContentServerSocket(xyzService service) throws IOException {
super(PORT);
while (true) {
Log.d(TAG, "Waiting for new request from client(content) ....");
new HandleRequest(accept(), service).start();
}
}
public static void xyzRunAway() {
Log.d(TAG," Content Serv er 1 ");
XYZGONE = true;
}
}
class HandleRequest extends Thread {
private final static String TAG = "ContentServerSocket:Thread for a request:";
private Socket client;
private xyzService service;
private static Context context;
HandleRequest(Socket client, SuggestionService service) {
this.client = client;
this.service = service;
context = xyzService.serviceContext();
}
public void run() {
while (true) {
try {
Log.d(TAG, " Step 1: client: Received request MSG for Check... ");
PrintWriter out = new PrintWriter(client.getOutputStream(),
true);
BufferedReader in = new BufferedReader(new InputStreamReader(
client.getInputStream(), "utf-8"));
String request = "";
String tmpLine = null;
Log.d(TAG, " Step Xyz waiting data from the client ... ");
while ((tmpLine = in.readLine()) != null) {
if (tmpLine.length() > 0) {
request += tmpLine;
//if (tmpLine.toLowerCase().contains("</contentInfo>")) {
if (tmpLine.contains("</contentInfo>")) {
Log.d(TAG, " Server : broke because of </contentInfo>");
break;
}
} else {
Log.d(TAG, " Step NULL : ");
request = "";
}
}
Log.d("Robin", " Step 2: Actual request received from the client : : " + request);
if (request.length() == 0) {
Log.d("Robin",
" client got 0 length request, thread stop!");
throw new Exception();
}
//XMLParser xmlParser = new XMLParser(new ByteArrayInputStream(
// request.getBytes("UTF-8")));
Log.d(TAG, " Step 3 : ");
RequestParser readxmlrequest = new RequestParser(request);
String requestType = readxmlrequest.parsingXmlRequestFromContent();
Log.d(TAG, " Step 4 requestType : " + requestType);
//TODO : need to get the result and pas to the out.println..
//String result = processXML(xmlParser);
String result = responseToContentRequest(readxmlrequest,requestType);//null; //TODO need to complete.
Log.d(TAG, " Step 5 result : "+result);
(((((((((())))))))))";
if (result != null && result.length() > 0) {
//oos.writeObject(result);
Log.d("Robin", " Writing response to socket ... ");
out.println(result + "\n");
out.flush();
Log.d("Robin", " Writing flush completed ");
}
if(ContentServerSocket.XYZGONE) {
Log.d(TAG," XYZGONE >>>>>>>> ");
ContentServerSocket.XYZGONE = false;
String tmp = "<ssr> OK Done .......</ssr>";
out.println(tmp + "\n");
Log.d("Content Server Socket ", "xyz:" + tmp);
out.flush();
}
} catch (IOException ioException) {
Log.d("Robin", " IOException on socket listen: " + ioException);
}
catch (Exception e) {
Log.d("Robin", " outer exception: " + e.toString());
break;
}
finally {
if (client == null || client.isClosed()
|| !client.isConnected()) {
Log.d(" Robin ", " client is null");
break;
}
}
//break;
}
Log.d("Robin", " thread stop... ");
}
So , I fixed it . I just need to maintain two different thread.
1) read.
2)write.
In the above code i just started one more thread for write .
insert the code in Run function of above code.
====================================================
Runnable r1 = new Runnable() {
public void run() {
try {
while (true) {
System.out.println("Hello, world!");
if(ContentServerSocket.XYZGONE) {
Log.d(TAG," XYZGONEY >>>>>>>> ");
ContentServerSocket.XYZGONE = false;
String tmp = "<ssr> OK Done .......</ssr>";
out.println(tmp + "\n");
Log.d("Content Server Socket ", "XYZGONE :" + tmp);
out.flush();
}
Thread.sleep(1000L);
}
} catch (InterruptedException iex) {}
}
};
Thread thr1 = new Thread(r1);
==================================
Then Start the thread in the wile loop of read.
with the following code with a check.
====================================
if(!thr1.isAlive())thr1.start();
Thanks everyone, who respond my question..
Yes it is possible to write data from multiple threads on a server or on a client to an existing socket. However you have to make sure the requests do not overlap, and the receiving side actually knows what is written from who.
If you use a line based protocol you can define each message is a single line. In that case you should synchronize multiple threads in a way that only one is writing parts of that line at any given moment.
Your code is a bit too big to understand where your problem is, sorry.
Maybe this tutorial helps? There are quite many out there:
http://www.javaworld.com/javaworld/jw-12-1996/jw-12-sockets.html
Related
Explanation
I'm currently trying to create a Multiplayer Game with Java where up to five Players can play together.
The problem is that when I'm trying to connect multiple Clients to my Server I get an Exception and the Server doesn't work anymore.
With one Client at a time, everything works fine.
So what I need is a Server that can handle up to five players at a time and the clients should always get some new game data from the Server
every few seconds (Connected Players, etc.).
The "Game data" in the code below is the String I'm sending through the Object Stream.
Normally I would send an Object which has all the game data, but with the String, I get the same problem.
I'm struggling with the problem that only one Client can connect without any errors occurring for some days now and I didn't find a solution to my problem.
I saw that there are things like java.nio or the ExecutorService, but I didn't really understand those that much, so I don't know if they can help.
I have made a smaller program that simulates the same problem I get with my bigger program.
To Start the Server, you need to Start the GameMultiPlayerCreate.java Class, and for the Client, the Client.java class.
I'm new to Sockets so if something is unnecessary or if something can be made better please let me know.
So the Error I'm getting when I connect two or more Clients is:
java.io.StreamCorruptedException: invalid stream header: 00050131
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
at Server.waitForData(Server.java:89) //I highlighted that in the code with a comment
at Server.loopWaitForData(Server.java:49)
at Server.run(Server.java:34)
at java.lang.Thread.run(Unknown Source)
Code
GameMultiPlayerCreate.java: Should start the Server threads if a Client connects
public class GameMultiPlayerCreate {
ServerSocket socketServer = null;
static String settingIp = "localhost";
static String settingPort = "22222";
static byte settingPlayers = 5;
public static int connectedPlayers = 0;
public static void main(String[] args) {
try {
GameMultiPlayerCreate objGameMultiPlayerCreate = new GameMultiPlayerCreate();
objGameMultiPlayerCreate.createServer();
} catch (NumberFormatException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
public void createServer() throws NumberFormatException, UnknownHostException, IOException, InterruptedException {
while (connectedPlayers < settingPlayers) {
socketServer = new ServerSocket(Integer.parseInt(settingPort), 8, InetAddress.getByName(settingIp));
System.out.println("Server is waiting for connection...");
Socket socket = socketServer.accept();
new Thread(new Server(socket)).start();
Thread.sleep(5000);
socketServer.close();
}
}
}
Server.java: This is the Class of which a new Thread should be created for each connected Client (Client Handler)
public class Server implements Runnable {
protected static Socket socket = null;
private int loops;
private int maxLoops = 10;
private int timeout = 10000;
protected static boolean killThread = false;
private boolean authenticated = true; //true for testing
protected static String ip;
protected static int port;
public Server(Socket socket) throws IOException {
Server.socket = socket;
}
public void run() {
try {
socket.setSoTimeout(timeout);
} catch (SocketException e) {
System.out.println("Error while trying to set Socket timeout. ");
System.out.println("Closing Thread..." + Thread.currentThread());
disconnectClient();
}
if (!killThread) {
GameMultiPlayerCreate.connectedPlayers = GameMultiPlayerCreate.connectedPlayers + 1;
loopWaitForData();
}
}
private void disconnectClient() {
System.out.println("Kicking Client... " + Thread.currentThread());
killThread = true;
GameMultiPlayerCreate.connectedPlayers = GameMultiPlayerCreate.connectedPlayers - 1;
}
public void loopWaitForData() {
while (!killThread) {
System.out.println(maxLoops + ", " + loops);
if (maxLoops - loops > 0) {
try {
waitForData();
} catch (SocketTimeoutException e) {
System.out.println("Error occurred while waiting for Data. Thread disconnected? Sending reminder. " + Thread.currentThread());
if (!authenticated) {
System.out.println("Kicking Client: Not authenticated");
disconnectClient();
} else {
commandReminder();
}
} catch (ClassNotFoundException | IOException e) {
loops = loops + 1;
System.out.println("Error occurred while waiting for Data. Waiting for more Data. " + Thread.currentThread());
e.printStackTrace();
loopWaitForData();
}
} else if (maxLoops - loops == 0) {
System.out.println("Error occurred while waiting for Data. Maximum trys reached. Disbanding connection. " + Thread.currentThread());
disconnectClient();
loops = loops + 1;
} else {
System.out.println("Closing Thread..." + Thread.currentThread());
disconnectClient();
}
}
}
private void commandReminder() {
System.out.println("Reminder");
try {
String code = new String("0");
ObjectOutputStream outputObject = new ObjectOutputStream(Server.socket.getOutputStream());
outputObject.writeObject(code);
} catch (IOException e) {
System.out.println("Error occurred while trying to authenticate Client: " + e + " in " + Thread.currentThread());
}
}
public void waitForData() throws IOException, ClassNotFoundException {
String code;
System.out.println("Waiting for Data...");
//Next line is where the error occurres
ObjectInputStream inputObject = new ObjectInputStream(socket.getInputStream());
while ((code = (String) inputObject.readObject()) != null) {
System.out.println("Received Data...");
System.out.println("Input received: " + code);
return;
}
}
}
Client.java: This is the Client
public class Client {
public static Socket socket = new Socket();
private int loops = 0;
private int maxLoops = 10;
private static boolean killThread = false;
private String ip;
private int port;
public Client(String receivedIp, String receivedPort) {
ip = receivedIp;
port = Integer.parseInt(receivedPort);
try {
System.out.println("Trying to connect to Server...");
socket.connect(new InetSocketAddress(ip, port));
System.out.println("Connected!");
} catch (IOException e) {
System.out.println("Error occurred while trying to connect to Server.");
}
loopWaitForData();
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Client objClient = new Client("localhost", "22222");
}
public void loopWaitForData() {
while (!killThread) {
System.out.println(maxLoops + ", " + loops);
if (maxLoops - loops > 0) {
try {
waitForData();
} catch (IOException | ClassNotFoundException e) {
loops = loops + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
}
System.out.println("Error occurred while waiting for Data. Waiting for more Data. " + Thread.currentThread());
e.printStackTrace();
loopWaitForData();
}
} else if (maxLoops - loops == 0){
System.out.println("Error occurred while waiting for Data. Maximum trys reached. Disbanding connection. " + Thread.currentThread());
try {
socket.close();
} catch (IOException e) {
System.out.println("Failed to close Socket " + Thread.currentThread());
}
loops = loops + 1;
} else {
System.out.println("Closing Thread..." + Thread.currentThread());
killThread = true;
}
}
}
public void waitForData() throws IOException, ClassNotFoundException {
InputStream input = socket.getInputStream();
ObjectInputStream inputObject = new ObjectInputStream(input);
String code;
System.out.println("Waiting for Data...");
while ((code = (String) inputObject.readObject()) != null) {
System.out.println("Received Data...");
System.out.println("Input received: " + code);
answer();
return;
}
}
private void answer() {
try {
String code = new String("1");
ObjectOutputStream outputObject = new ObjectOutputStream(socket.getOutputStream());
outputObject.writeObject(code);
} catch (IOException e) {
System.out.println("Error occurred while trying to answer: " + e + " in " + Thread.currentThread());
}
}
}
I have a device that replies to commands using UDP datagrams. I'm trying to come up with a way to guarantee the response is from a particular request. When I run the following code I get the first two, and sometimes third request, then it just hangs and times out the receive. I've tried a few different methods to resolve it (hence the synchronize and iQueuePointer receive timeout). Here is an example of a run:
Listening for X-Air responses
Sending X-Air requests
Servicing request 6
Send loop - bWait=true request.size=6 iQueuePointer=6
/info,ssssV0.04XR12-24-00-6EXR121.10 from 6
Removed 6
Servicing request 5
Send loop - bWait=true request.size=5 iQueuePointer=5
/ch/01/config/name,sPreach Mic from 5
Removed 5
Here's the code:
public static final Object socketLock = new Object();
public static DatagramSocket socket;
public static ArrayList<String> request = new ArrayList<>();
public static int iQueuePointer;
public static boolean bWait;
public static void main(String[] args) {
new Main();
}
private Main() {
try {
socket = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
new Thread(receiveRunnable).start();
new Thread(sendRunnable).start();
iQueuePointer++;
request.add("/info");
iQueuePointer++;
request.add("/ch/01/config/name");
iQueuePointer++;
request.add("/ch/02/config/name");
iQueuePointer++;
request.add("/ch/03/config/name");
iQueuePointer++;
request.add("/ch/04/config/name");
iQueuePointer++;
request.add("/ch/05/config/name");
iQueuePointer++;
}
private Runnable sendRunnable = new Runnable() {
#Override
public void run() {
System.out.println("Sending requests");
while(socket != null) {
if(!bWait && request.size() > 0 && request.size() < iQueuePointer) {
iQueuePointer--;
bWait = true;
System.out.println("Servicing request " + iQueuePointer);
//synchronized (socketLock) {
try {
socket.send(new DatagramPacket(request.get(0).getBytes(),
request.get(0).getBytes().length,
InetAddress.getByName("192.168.0.180"), 10024));
} catch (IOException e) {
e.printStackTrace();
}
//}
}
}
System.out.println("sendRunnable ended");
}
};
private Runnable receiveRunnable = new Runnable() {
#Override
public void run() {
System.out.println("Listening for responses");
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
while(socket != null) {
//synchronized (socketLock) {
try {
//socket.setSoTimeout(5000);
socket.receive(packet);
if (packet.getLength() > 0 && socket != null) {
System.out.println(new String(Arrays.copyOf(packet.getData(), packet.getLength()))
+ " from " + iQueuePointer);
request.remove(0);
System.out.println("Removed " + iQueuePointer);
bWait = false;
}
} catch (Exception e) {
if (!e.toString().contains("Receive timed out")) {
e.printStackTrace();
} else {
System.out.println("Receive loop - bWait=" + bWait + " request.size=" + request.size()
+ " iQueuePointer=" + iQueuePointer);
}
}
//}
}
System.out.println("receiveRunnable ended");
}
};
In UDP you can't assume that the responses arrive in the same order as the requests were sent, or indeed at all, and you also can't assume they only arrive once.
You will have to use sequence numbers in both, to match them up, or else not have any pending requests, and keep issuing a request until you get its response, and then you still have to deal with duplicates somehow.
NB You need to either recreate the DatagramPacket or at least reset its length every time around the read loop: otherwise it can keep shrinking to the size of the smallest datagram received so far.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
well, what i want to do is basically, to make a client server chat program that works over internet, ive done a basic one that works flawlessly over lan, but cant get it right over the internet..
Server :
public class Server extends javax.swing.JFrame {
HashMap<String,PrintWriter> map = new HashMap<String,PrintWriter>();
ArrayList clientOutputStreams = new ArrayList();
ArrayList<String> onlineUsers = new ArrayList();
int port = 5080;
Socket clientSock = null;
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket sock;
PrintWriter client;
public ClientHandler(Socket clientSocket, PrintWriter user) {
// new inputStreamReader and then add it to a BufferedReader
client = user;
try {
sock = clientSocket;
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
System.out.println("first");
} // end try
catch (Exception ex) {
System.out.println("error beginning StreamReader");
} // end catch
} // end ClientHandler()
#Override
public void run() {
System.out.println("run method is running");
String message;
String[] data;
String connect = "Connect";
String disconnect = "Disconnect";
String chat = "Chat";
try {
while ((message = reader.readLine()) != null) {
ta1.append(message + "\n");
ta1.repaint();
System.out.println("Received: " + message);
data = message.split("#");
for (String token : data) {
System.out.println(token);
}
System.out.println(data[data.length - 1] + " datalast");
if (data[2].equals(connect)) {
tellEveryone((data[0] + "#" + data[1] + "#" + chat));
userAdd(data[0]);
map.put(data[0], client);
} else if (data[2].equals(disconnect)) {
System.out.println("barpppppppppp");
tellEveryone((data[0] + "#has disconnected." + "#" + chat));
userRemove(data[0]);
map.remove(data[0]);
} else if (data[2].equals(chat)) {
tellEveryone(message);
} else {
System.out.println("No Conditions were met.");
}
} // end while
} // end try
catch (Exception ex) {
System.out.println("lost a connection");
System.out.println(ex.getMessage());
clientOutputStreams.remove(client);
} // end catch
} // end run()
}
public void go() {
// clientOutputStreams = new ArrayList();
try {
ServerSocket serverSock = new ServerSocket(port);
System.out.println("ServerSocket Created !");
System.out.println("Started listening to port " + port);
while (true) {
// set up the server writer function and then begin at the same
// the listener using the Runnable and Thread
clientSock = serverSock.accept();
PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
ta1.append(writer + " ");
ta1.repaint();
System.out.println(writer);
clientOutputStreams.add(writer);
//data_of_names_and_output_streams.add(writer.toString());
// use a Runnable to start a 'second main method that will run
// the listener
Thread listener = new Thread(new Server.ClientHandler(clientSock, writer));
listener.start();
System.out.println("Server Thread for 'new player' was started");
System.out.println("got a connection");
} // end while
} // end try
catch (Exception ex) {
System.out.println("error making a connection");
} // end catch
} // end go()
public void userAdd(String data) {
String message;
String add = "# #Connect", done = "Server# #Done";
onlineUsers.add(data);
String[] tempList = new String[(onlineUsers.size())];
onlineUsers.toArray(tempList);
for (String token : tempList) {
message = (token + add);
tellEveryone(message);
System.out.println(message);
}
tellEveryone(done);
}
public void userRemove(String data) {
System.out.println(onlineUsers.size() + " is size of online users");
System.out.println(clientOutputStreams.size() + " is size of ous");
String message;
String add = "# #Connect", done = "Server# #Done";
onlineUsers.remove(data);
String[] tempList = new String[(onlineUsers.size())];
onlineUsers.toArray(tempList);
for (String token : tempList) {
message = (token + add);
tellEveryone(message);
}
tellEveryone(done);
}
public void tellEveryone(String message) {
System.out.println(onlineUsers.size() + " is size of online users");
System.out.println(clientOutputStreams.size() + " is size of ous");
// jButton1.doClick();
// sends message to everyone connected to server
Iterator it = clientOutputStreams.iterator();
if (message.length() < 250) {
System.out.println("inside it");
while (it.hasNext()) {
try {
PrintWriter writer = (PrintWriter) it.next();
writer.println(message);
// l1.setText(message);
System.out.println("Sending " + message);
writer.flush();
} // end try
catch (Exception ex) {
System.out.println("error telling everyone");
} // end catch
}
} else {
try {
clientSock.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* Creates new form Server
*/
public Server() {
initComponents();
ta1.repaint();
}
public static void main(String args[]) throws Exception {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Server().setVisible(true);
}
});
new Server().go();
}
} //end form
Client : jbutton1 is setting up connection,jbutton2 sends the message.
public class Client extends javax.swing.JFrame {
boolean sent, receive;
SimpleDateFormat sdf;
String ip;
String username;
Socket sock;
BufferedReader reader;
PrintWriter writer;
ArrayList<String> userList = new ArrayList();
Boolean isConnected = false;
DefaultListModel dlm;
public Client() {
initComponents();
dlm = (DefaultListModel) l1.getModel();
ip = JOptionPane.showInputDialog("Enter the IP of the server to connect");
}
public class IncomingReader implements Runnable {
public void run() {
String stream;
String[] data;
String done = "Done", connect = "Connect", disconnect = "Disconnect", chat = "Chat", battlerequest = "battlerequest";
try {
while ((stream = reader.readLine()) != null) {
data = stream.split("#");
System.out.println(stream + " ------------------------ data");
if (data[2].equals(chat)) {
sdf = new SimpleDateFormat("HH:mm:ss");
t.append("(" + sdf.format(new Date()) + ") " + data[0] + ": " + data[1] + "\n");
//t.setText("<html><b>hi" + 3 + 3 + "</b></html>");
} else if (data[2].equals(connect)) {
t.removeAll();
userAdd(data[0]);
} else if (data[2].equals(disconnect)) {
userRemove(data[0]);
} else if (data[2].equals(done)) {
dlm.removeAllElements();
writeUsers();
userList.clear();
} else {
System.out.println("no condition met - " + stream);
}
}
} catch (Exception ex) {
System.out.println(ex.getMessage() + " hi");
}
}
}
public void ListenThread() {
Thread IncomingReader = new Thread(new Client.IncomingReader());
IncomingReader.start();
}
public void userAdd(String data) {
userList.add(data);
}
public void userRemove(String data) {
t.setText(t1.getText() + data + " has disconnected.\n");
}
public void writeUsers() {
String[] tempList = new String[(userList.size())];
userList.toArray(tempList);
for (String token : tempList) {
//ul.append( token + "\n");
dlm.addElement(token);
// ul.setText(ul.getText() + token + '\n');
}
}
public void sendDisconnect() {
String bye = (username + "# #Disconnect");
try {
writer.println(bye); // Sends server the disconnect signal.
writer.flush(); // flushes the buffer
} catch (Exception e) {
t.append("Could not send Disconnect message.\n");
}
}
public void Disconnect() {
try {
t.append("Disconnected.\n");
sock.close();
} catch (Exception ex) {
t.append("Failed to disconnect. \n");
}
isConnected = false;
n.setEditable(true);
dlm.removeAllElements();
// ul.setText("");
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected == false && !n.getText().equals("")) {
username = n.getText();
n.setEditable(false);
try {
sock = new Socket(ip, 5080);
InputStreamReader streamreader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(streamreader);
writer = new PrintWriter(sock.getOutputStream());
writer.println(username + "#has connected.#Connect"); // Displays to everyone that user connected.
writer.flush(); // flushes the buffer
isConnected = true;
jLabel4.setText(n.getText());
//t.append( "<html><font color = \"black\"><b>Server : Welcome,</b></font></html>"+username);
//t1.setText("<html><font color=\"red\">yo</font></html>");
// Used to see if the client is connected.
} catch (Exception ex) {
t.append("Cannot Connect! Try Again. \n");
n.setEditable(true);
}
ListenThread();
} else if (isConnected == true) {
t.append("You are already connected. \n");
} else if (n.getText().equals("")) {
t.append("Enter a valid name \n");
}
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
String nothing = "";
if ((t1.getText()).equals(nothing)) {
t1.setText("");
t1.requestFocus();
} else {
try {
writer.println(username + "#" + t1.getText() + "#" + "Chat");
writer.flush(); // flushes the buffer
} catch (Exception ex) {
t.append("Message was not sent. \n");
}
t1.setText("");
t1.requestFocus();
}
t1.setText("");
t1.requestFocus(); // TODO add your handling code here:
}
private void dicsActionPerformed(java.awt.event.ActionEvent evt) {
sendDisconnect();
Disconnect(); // TODO add your handling code here:
}
i have also port forwarded the ports i am going to use - ie. 5080
now when my friend opens the client program from his computer from his home, i tell him to enter the ip as 192.168.1.2 coz thats what is saved when i open cmd and type ipconfig....
sometimes i think that the ip address i gave him is wrong coz 192.168.1.2 is i guess lan or internal ip address, so then, so do i do ? where do i get the correct ip address ? or is something else wrong in my code ?
192.168.1.2 is a non-routable IP. Click here to get your current external IP (unless your IP address is static, it may change periodically).
If you were to sign up for a dynamic dns service (here for example), then you could give your friend a "domain name" (e.g. something.dnsdynamic.com) and the service would update when your IP address changes.
I've got a little network game I'm making to learn networking in Java, and I'm in need of a little insight into what my program is having issues with. My server program maxes out the heap and burns 100% of the CPU. I'm sure I've got major newbie gotchas in the code, and I'm wondering if anyone would be so kind as to point them out to me, and perhaps detail why it is such a horrible practice.
Basically, the Server class's job is to wait in socket.accept() to deal with new clients. Each client from there gets its own ConnectionThread (which deals with input) and an attached OutputStream (which handles output). I know this may be wasteful for large applications, but with the server running along with just three clients (which are set to skip rendering and only send data through the socket every ~20ms for both input and output) it cooks the CPU and the server overflows the stack.
I've got a Packet class which converts the data into a string for sending, and the receiver decodes it back into a Packet. I suspect I have some Packets laying around too long, but I don't see where. If it isn't the packets, I'm fairly certain I have SOME sort of uncontrolled exponential object growth.
Here are some snippets of relevant code. I'm happy to provide more if the problem is elsewhere.
Just for reference, here is the full code: https://github.com/taylorrobert/ProjectM2O
Server:
public Server() {
network = new NetworkManager(this);
network.setConnectionCounter(0);
entityManager = new EntityManager(this);
setListenState(true);
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
System.out.println("Error in server constructor.");
System.exit(1);
}
}
public void listen() {
System.out.println("Current connectionCounter: " + network.getConnectionCounter());
while (shouldListen) {
ConnectionThread conn = null;
try {
conn = new ConnectionThread(serverSocket, this);
}
catch (Exception e) {
System.out.println("____Error constructing ConnectionThread. Could there be another instance of the server running?");
e.printStackTrace();
System.exit(1);
}
(new Thread(conn)).start();
System.out.println("Connection count: " + network.getConnectionCounter());
}
}
ConnectionThread:
public ConnectionThread(ServerSocket s, Server ser) {
resetTimer();
setActiveState(false);
server = ser;
//This UUID becomes the client's controllable player ID
//and the ID of this ConnectionThread.
connectionID = String.valueOf(UUID.randomUUID());
try {
socket = s.accept();
System.out.println("Socket ID " + connectionID + " established on: " + socket);
} catch (IOException e) {
System.out.println("Error in ConnectionThread. Is there a server already running on this port?");
}
init();
}
public void init() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch (IOException e) {
System.out.println("Error in intializing I/O streams.");
System.exit(1);
}
//Create the output thread
OutputStream outputHandler = new OutputStream(this);
new Thread(outputHandler).start();
//Get the client up to date on all relevant data
server.getEntityManager().addPlayerEntity(getConnectionID());
server.getNetwork().pushClientInitState(getConnectionID(), this);
server.getNetwork().addConnection(this);
server.getNetwork().notifyClientsAboutNewPlayer(getConnectionID());
int s = server.getNetwork().getConnections().size();
server.getNetwork().sendConsoleMessage("Players online: " + s, this);
}
public void run() {
setActiveState(true);
System.out.println("Running ConnectionThread...");
while (isActive()) {
//System.out.println("Entity size: " + server.getEntityManager().getEntities().size());
String op = readInputStream();
if (op.equals("")) continue;
Packet packet = Packet.populateNewPacketFromString(op);
try {
incomingOpQueue.put(packet);
} catch (InterruptedException e) {
System.out.println("Server failed to add packet to outgoing queue!");
}
//Take all packets off the incoming queue and execute them in order
while (incomingOpQueue.size() > 0) {
Packet p = incomingOpQueue.poll();
PacketExecutor.executePacket(server, p, this);
}
}
}
public String readInputStream() {
String msg = "";
try {
msg = in.readLine();
msg = msg.replace("\n", "");
msg = msg.trim();
} catch (IOException e) {
return "";
}
return msg;
}
OutputStream:
public void output() {
while (parentCT.isActive()) {
UnitTester.updateAllEntityLocationsToAllClients(parentCT, parentCT.server.getEntityManager().getEntities());
while (parentCT.getOutgoingOpQueue().size() > 0) {
String packet = (parentCT.getOutgoingOpQueue().poll().getString());
if (packet.equals("")) continue;
//System.out.println("Sending " + packet + " to " + parentCT.getConnectionID());
parentCT.getOutput().println(packet);
}
}
}
You probably need to make shouldListen volatile. Otherwise, there's every chance that its value will be cached, and setting it to false in some other thread will make no difference. You are setting it to false right, so that the main loop just doesn't make lots and lots of threads until it maxes out the heap and burns up the CPU?
I'm just getting started with RMI and I'm trying to write a simple program that simulates a train booking system. I have the basics set up - Server, Client, and a Remote object exported. It works fine with one Client connection. However when more than 1 Client connects, the Clients seem to be executing in the same thread. This is the case when I run multiple Clients on the same machine or when I connect a Client from another laptop.
I was under the impression that RMI handled threading on the server side? If not, how do I go about handling multiple Client connections given the code below?
Here are the classes of interest.
Server.....
public class Server {
public Server() {
try {
Booking stub = (Booking) UnicastRemoteObject.exportObject(new BookingProcess(), 0);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Booking", stub);
System.err.println("Server Ready");
} catch (RemoteException e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
}
}
BookingProcess.....(I've left out the private methods that processInput(String input) uses)
public class BookingProcess implements Booking {
private static Journey dublinGalway = new Journey("Dublin to Galway");
private static Journey dublinLimerick = new Journey("Dublin to Limerick");
private static Journey dublinCork = new Journey("Dublin to Cork");
private Journey currentJourney;
private enum State {
INITIAL, JOURNEYS_DISPLAYED, JOURNEY_CHOSEN, ANOTHER_BOOKING_OFFERED, SOLD_OUT;
}
private State currentState = State.INITIAL;
public synchronized String processInput(String input) {
String output = "";
if(currentState == State.INITIAL) {
if(bookedOut()) {
output = "Sorry, there are no seats remaining on any route. Get the bus.";
currentState = State.SOLD_OUT;
}
else {
output = "Please choose a journey to book: " + "1: " + dublinGalway.getDescription() + ", 2: " + dublinLimerick.getDescription() + ", 3: " + dublinCork.getDescription();
currentState = State.JOURNEYS_DISPLAYED;
}
}
else if(currentState == State.JOURNEYS_DISPLAYED) {
output = this.processJourneyChoice(input);
}
else if(currentState == State.JOURNEY_CHOSEN) {
output = "Do you wish to confirm this booking? (y/n)";
if(input.equalsIgnoreCase("y")) {
if(bookingConfirmed()) {
output = "Thank you. Your journey from " + currentJourney.getDescription() + " is confirmed. Hit return to continue.";
//currentState = State.ANOTHER_BOOKING_OFFERED;
}
else {
output = "Sorry, but the last seat on the " + currentJourney.getDescription() + " route has just been booked by another user.";
//currentState = State.ANOTHER_BOOKING_OFFERED;
}
currentState = State.ANOTHER_BOOKING_OFFERED;
}
else if(input.equalsIgnoreCase("n")) {
output = "You have cancelled this booking. Hit return to continue.";
currentState = State.ANOTHER_BOOKING_OFFERED;
}
}
else if(currentState == State.ANOTHER_BOOKING_OFFERED) {
output = "Would you like to make another booking? (y/n)";
if(input.equalsIgnoreCase("y")) {
output = "Hit Return to continue.";
currentState = State.INITIAL;
}
else if(input.equalsIgnoreCase("n")){
output = "Goodbye.";
try {
Thread.currentThread().join(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
currentState = State.INITIAL;
}
}
else if(currentState == State.SOLD_OUT) {
output = "Goodbye.";
}
return output;
}
And finally Client......
public class Client {
public static void main(String[] args) {
Client client = new Client();
client.runClient();
}
public void runClient() {
try {
BufferedReader consoleInput = new BufferedReader(new InputStreamReader(System.in));
Registry registry = LocateRegistry.getRegistry("localhost");
Booking stub = (Booking) registry.lookup("Booking");
String serverResponse = stub.processInput("begin");
System.out.println("Server: " + serverResponse);
while((serverResponse = stub.processInput(consoleInput.readLine())) != null) {
System.out.println(serverResponse);
if(serverResponse.equals("Goodbye.")) {
break;
}
}
} catch (Exception e) {
System.err.println("Client exception " + e.toString());
e.printStackTrace();
}
}
}
As for as RMI server threads, the answer is that it may or may not run in a separate thread. See the documentation here:
http://docs.oracle.com/javase/6/docs/platform/rmi/spec/rmi-arch3.html
3.2 Thread Usage in Remote Method Invocations
A method dispatched by the RMI runtime to a remote object implementation may or may not execute in a separate thread. The RMI runtime makes no guarantees with respect to mapping remote object invocations to threads. Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe.
You can take server side thread dumps and you would see that the RMI TCP Connection threads IDs keep changing, however as #jtahlborn noticed the server side method is synchronized so it would execute serially, not necessarily in a single thread though.
Your server side processInput() method is synchronized, so, yes, the calls will be handled serially. what does that have to do with RMI?
UPDATE:
if you want to have separate currentState and currentJourney values for each client session, then you need to use the RMI remote session pattern, see this answer for details.