Java TCP sockets, sending and receiving objects in a thread - java

I'm a a beginner programmer, currently stuck on a java project. I have a fully working singleplayer minesweeper game, object-oriented, and I'm trying to implement a TCP multiplayer function. The game has a control class, which handles the view, game field, timer, labels, has the action listeners, etc.
For multiplayer, I'm trying to make a separate thread, which has the Socker and the ServerSocket, and depending on the parameters passed on by the constructor, acts as a host or client. While running, it should be trying to read my custom Packet class from the input stream, and another method can send packets. Here is the code:
public class MultiThread extends Thread {
GameControl gc;
ServerSocket servSocket;
Socket socket;
Packet data;
ObjectInputStream incoming;
ObjectOutputStream outgoing;
Boolean isHost;
Boolean commEnd;
public MultiThread(GameControl gc, Boolean isHost) {
this.gc = gc;
this.isHost = isHost;
this.commEnd = false;
gc.chatDialog.setVisible(true);
}
public void run() {
try {
if (isHost) {
servSocket = new ServerSocket(1234);
gc.chatDialog.status.setText("Awaiting connection...");
socket = servSocket.accept();
gc.chatDialog.status.setText("Connected.");
incoming = new ObjectInputStream(socket.getInputStream());
outgoing = new ObjectOutputStream(socket.getOutputStream());
}
else if (!isHost){
socket = new Socket("localhost", 1234);
if (socket.isConnected()) {
gc.chatDialog.status.setText("Connected.");
incoming = new ObjectInputStream(socket.getInputStream());
outgoing = new ObjectOutputStream(socket.getOutputStream());
}
else {
gc.chatDialog.status.setText("No connection.");
}
}
while (!commEnd) {
try {
Thread.sleep(100);
data = (Packet)incoming.readObject();
System.out.println(data.msg);
gc.chatDialog.chatArea.append(data.getMsg());
}
catch (IOException e) {e.printStackTrace();}
}
System.out.println("asd");
gc.chatDialog.status.setText("No connection");
incoming.close();
outgoing.close();
socket.close();
servSocket.close();
}
catch (Exception e) {e.printStackTrace();}
}
public void sendPacket(Packet p) {
try {
outgoing.writeObject(p);
}
catch (IOException e) {e.printStackTrace();}
}
}
The connection gets established on localhost, but I'm getting an exception thrown when trying to initialize the incoming and outgoing fields.
Sorry if the code is a mess, I get the feeling I'm in some serious misunderstanding, so any help is appreciated.

Related

Java Server producing inconsistent output

I want to integrate a server with multiple clients for a blackjack game I created, and thus I began practicing with servers in java. I create a thread, that when ran, forces the server to listen for input and produce an output. Then I added a feature to stop the server. However, the server randomly produces the correct output, and sometimes fails to connect. Here is the code for when the user hosts a server:
st = new ServerThread(); //this is a field of type ServerThread
st.start(); //this runs the server concurrently as a new thread
Here is the code for when they close a server:
st.stopThread();
Finally, here is the source for the serverThread:
public class ServerThread extends Thread {
private volatile boolean isRunning = true;
private Socket socket;
private static final int PORTNUM = 1342;
#Override
public void run() {
while (isRunning) { //should run only when the
try {
ServerSocket serverSocket = new ServerSocket(PORTNUM); //uses the same port number, which I made a constant
//Reading the an object of type Information from the client
socket = serverSocket.accept();
ObjectInputStream serverInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream serverOutputStream = new ObjectOutputStream(socket.getOutputStream());
Information i = (Information) serverInputStream.readObject();
//arbitrarily changes the data stored in the information object to verify connection with server
i.setI(100);
i.setS("new string");
i.setD(4.4);
//sends the modified object back to the client
serverOutputStream.writeObject(i);
serverInputStream.close();
serverOutputStream.close();
socket.close();
} catch (IOException e) {
//System.out.println("IOException");
//e.printStackTrace();
} catch (ClassNotFoundException e) {
//System.out.println("ClassNotFoundException");
//e.printStackTrace();
} finally {
try {
if (socket != null) { //avoid null pointer if no connections have been established
socket.close();
}
} catch (IOException ex) {
//Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public void stopThread() {
isRunning = false;
}
}
Any suggestions on edits to make my code perform correctly and consistently would be welcome. Thanks.
I would move the socket definition away from being an instance variable i.e,
while (isRunning) {
Socket socket = null;
try {
...

how can i send data to the selected client from server?

i'm building a multithread example using sockets and threads in java. the sever will get multiple Socket at same time, and when i send a message from server, i want the socket from client to go back in order to what i give.
my understanding so far is to make ArrayList but i have no idea how to use it for my purpose.
can anyone help or give me any clue to solve this problem?
following is the code:
//server socket to wait before accepting from client.
public class ServerSocketEntry {
ServerSocket ssoc;
Socket soc;
ArrayList<Socket> arrSocket = new ArrayList<Socket>();
private static final int port=4853;
public ServerSocketEntry(ServerManagement sm){
try {
ssoc = new ServerSocket(port);
System.out.println("Waiting");
while(true){
soc=ssoc.accept();
arrSocket.add(soc);
System.out.println("Accepted: "+soc);
ServerSocketThread sth = new ServerSocketThread(soc,sm);
sth.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ServerManagement sm = new ServerManagement();
new ServerSocketEntry(sm);
}
}
//threadClass using readObject(), writeObject() method.
public class ServerSocketThread extends Thread {
Socket soc;
ObjectOutputStream oos;
ObjectInputStream ois;
ServerManagement sm;
Food food;
public ServerSocketThread(Socket soc,ServerManagement sm) {
this.soc=soc;
this.sm=sm;
try {
ois= new ObjectInputStream(soc.getInputStream());
oos= new ObjectOutputStream(soc.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run(){
Command com;
while(true){
try {
com = (Command) ois.readObject();
if(com.getCommand()==Command.Member_Check){
Member member = (Member) com.getObj();
System.out.println("thread: "+member);
if(sm.checkMember(member)){
com.setCommand(Command.Command_OK);
}else{
com.setCommand(Command.Command_Fail);
}
}else if(com.getCommand()==Command.LogIn_Check){
Member member = (Member) com.getObj();
if(sm.checkLogIn(member)){
com.setCommand(Command.Command_OK);
}else{
com.setCommand(Command.Command_Fail);
}
}else if(com.getCommand()==Command.Food_Check){
ArrayList<Food> serverArrFood = com.getFoodOrder();
if(sm.checkFood(serverArrFood)){
com.setCommand(Command.Command_OK);
}else{
com.setCommand(Command.Command_Fail);
}
}
oos.writeObject(com);
oos.flush();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Then you may use a hash map to store the connected clients and it will be easy to get a specific client from the map and send message to that. Use a nickname of the client as the key and socket as a value at the time when a new client connects to the sever. Put these values into the map. For Example:
Map<String, Socket> clients = new HashMap();
clients.put(nickname, clientSocket);
While writing simply get that specific client by its key.
clients.get(nickname);
and write to its output stream. When one client sends message to a specific client, it should send the receiver's nickname as part of the message to the server.

Can I use a list of sockets to send to multiple clients?

I have a ArrayList<Socket> listOfSockets that adds a socket when I receive clientsocket = serversocket.accept() like this listOfSockets.add(clientsocket)
and then I send this whole list to another class like this.
Server_Client client = new Server_Client(clientSock, clientSocketList);
Thread X = new Thread(client);
X.start();
Here is the code for my class that I send the list and socket to
public class Server_Client implements Runnable{
//ArrayList<String> UserNameList;
ArrayList<Socket> clientSocketList;
Socket socket = null;
public Server_Client(Socket X, ArrayList<Socket> L){
this.socket = X;
this.clientSocketList = L;
}
#Override
public void run() {
try {
ListenforMessage NewMessages = new ListenforMessage(socket);
Thread myThread = new Thread(NewMessages);
myThread.start();
} catch (Exception e) {
System.err.println(e);
}
}
//------------------------------------------------------------------
//Class that handles incoming messages!
class ListenforMessage implements Runnable{
Socket socket;
DataInputStream IN;
DataOutputStream OUT;
public ListenforMessage(Socket x) {
this.socket = x;
}
#Override
public void run() {
try {
while (true) {
IN = new DataInputStream(socket.getInputStream());
OUT = new DataOutputStream(socket.getOutputStream());
String message = IN.readUTF();
//System.out.println(message);
for (Socket TEMP_SOCK : clientSocketList) {
if(TEMP_SOCK != this.socket){
SendMessage(message);
}
}
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void SendMessage(String m) throws IOException{
try {
DataOutputStream OUT = new DataOutputStream(socket.getOutputStream());
OUT.writeUTF(m);
System.out.println("User said: " + m);
} catch (Exception e) {
}
}
//------------------------------------------------------------------
}
In the ListenforMessage class, in the for-loop I go trough the size of list and if TEMP_SOCK is not this.socket then I want to send a message to that socket, and if it is then don't do anything. But my problem is that when I connect with 2 clients they can't send message to each other. They just send the message to the server and the server sends back the message to the client. My question is, can you use a list like I do to check if the socket is not the socket that you are YOURSELF.
cause now Client1 sends a messages and receive the same messages from sever, and Client2 does the same thing.
I want Client1 to send and Client2 to receive the message(And other sockets on the same list)
Your code doesn't work because you should let SendMessage know to which socket it should send the message (i.e. you should pass TEMP_SOCK to it), instead, you're making it use the socket variable, which is the socket connected to the client that just sent the message.

Sending a message to all clients (Client - Server communication)

So now, I am making a client server app based multithread. In server side, I make a thread for everysingle connection that accepted.
In thread class, I make a method that send a command to client. What i just want is, how to send a parameter to all running client? For simple statement, i just want to make this server send a message to all connected client.
I've been read this post and find sendToAll(String message) method from this link. But when i am try in my code, there is no method like that in ServerSocket .
Okay this is my sample code for server and the thread.
class ServerOne{
ServerSocket server = null;
...
ServerOne(int port){
System.out.println("Starting server on port "+port);
try{
server = new ServerSocket(port);
System.out.println("Server started successfully and now waiting for client");
} catch (IOException e) {
System.out.println("Could not listen on port "+port);
System.exit(-1);
}
}
public void listenSocket(){
while(true){
ClientWorker w;
try{
w = new ClientWorker(server.accept());
Thread t = new Thread(w);
t.start();
} catch (IOException e) {
System.out.println("Accept failed: 4444");
System.exit(-1);
}
}
}
protected void finalize(){
try{
server.close();
} catch (IOException e) {
System.out.println("Could not close socket");
System.exit(-1);
}
}
}
class ClientWorker implements Runnable{
Socket client;
ClientWorker(Socket client){
this.client = client;
}
public void run(){
...
sendCommand(parameter);
...
}
public void sendCommand(String command){
PrintWriter out = null;
try {
out = new PrintWriter(client.getOutputStream(), true);
out.println(command);
} catch (IOException ex) {}
}
}
Thanks for help :)
The below answer, is not recommended for a full fledged server, as for this you should use Java EE with servlets, web services etc.
This is only intended where a few computers want to connect to perform a specific task, and using simple Java sockets is not a general problem. Think of distributed computing or multi-player gaming.
EDIT: I've - since first post - greatly updated this architecture, now tested and thread-safe. Anybody who needs it may download it here.
Simply use (directly, or by subclassing) Server and Client, start() them, and everything is ready. Read the inline comments for more powerful options.
While communication between clients are fairly complicated, I'll try to simplify it, the most possible.
Here are the points, in the server:
Keeping a list of connected clients.
Defining a thread, for server input.
Defining a queue of the received messages.
A thread polling from the queue, and work with it.
Some utility methods for sending messages.
And for the client:
Defining a thread, for client input.
Defining a queue of the received messages.
A thread polling from the queue, and work with it.
Here's the Server class:
public class Server {
private ArrayList<ConnectionToClient> clientList;
private LinkedBlockingQueue<Object> messages;
private ServerSocket serverSocket;
public Server(int port) {
clientList = new ArrayList<ConnectionToClient>();
messages = new LinkedBlockingQueue<Object>();
serverSocket = new ServerSocket(port);
Thread accept = new Thread() {
public void run(){
while(true){
try{
Socket s = serverSocket.accept();
clientList.add(new ConnectionToClient(s));
}
catch(IOException e){ e.printStackTrace(); }
}
}
};
accept.setDaemon(true);
accept.start();
Thread messageHandling = new Thread() {
public void run(){
while(true){
try{
Object message = messages.take();
// Do some handling here...
System.out.println("Message Received: " + message);
}
catch(InterruptedException e){ }
}
}
};
messageHandling.setDaemon(true);
messageHandling.start();
}
private class ConnectionToClient {
ObjectInputStream in;
ObjectOutputStream out;
Socket socket;
ConnectionToClient(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread(){
public void run(){
while(true){
try{
Object obj = in.readObject();
messages.put(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
};
read.setDaemon(true); // terminate when main ends
read.start();
}
public void write(Object obj) {
try{
out.writeObject(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
public void sendToOne(int index, Object message)throws IndexOutOfBoundsException {
clientList.get(index).write(message);
}
public void sendToAll(Object message){
for(ConnectionToClient client : clientList)
client.write(message);
}
}
And here for the Client class:
public class Client {
private ConnectionToServer server;
private LinkedBlockingQueue<Object> messages;
private Socket socket;
public Client(String IPAddress, int port) throws IOException{
socket = new Socket(IPAddress, port);
messages = new LinkedBlokingQueue<Object>();
server = new ConnecionToServer(socket);
Thread messageHandling = new Thread() {
public void run(){
while(true){
try{
Object message = messages.take();
// Do some handling here...
System.out.println("Message Received: " + message);
}
catch(InterruptedException e){ }
}
}
};
messageHandling.setDaemon(true);
messageHandling.start();
}
private class ConnectionToServer {
ObjectInputStream in;
ObjectOutputStream out;
Socket socket;
ConnectionToServer(Socket socket) throws IOException {
this.socket = socket;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
Thread read = new Thread(){
public void run(){
while(true){
try{
Object obj = in.readObject();
messages.put(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
};
read.setDaemon(true);
read.start();
}
private void write(Object obj) {
try{
out.writeObject(obj);
}
catch(IOException e){ e.printStackTrace(); }
}
}
public void send(Object obj) {
server.write(obj);
}
}
There is no method in server socket to send data or message to all running clinet threads.
Please go through the ServerThread.java program which is calling the sendToAll usng server.
// ... and have the server send it to all clients
server.sendToAll( message );
Check out zeroMQ. There are methods known as "pub sub" or "publish subscribe" that will do what you want. You can also use it to communicate between your threads. It is an amazing library in my opinion. It has java or jzmq bindings along with over 30+ others as well so you should be able to use it in your program.
http://www.zeromq.org/

Listening on multiple sockets (InputStreamReader)

I'm having a problem with a little game I'm designing in my class.
The problem is that I got two clients connected to a server. (client1 and client2) They are each running a game, which in the end, closes the window. As the game window is a JDialog, it will then, when it's closed, send a message, through a socket, to the server, telling it that it's done. I want the server to know which of the two clients were completed first. They are reporting through a PrintWriter on the sockets' OutputStream.
What I did was this:
in1 = new BufferedReader(new InputStreamReader(client.getInputStream()));
in2 = new BufferedReader(new InputStreamReader(client2.getInputStream()));
try {
in1.readLine();
} catch (IOException ex) {
Logger.getLogger(gameServer.class.getName()).log(Level.SEVERE, null, ex);
}
try {
in2.readLine();
} catch (IOException ex) {
Logger.getLogger(gameServer.class.getName()).log(Level.SEVERE, null, ex);
}
Problem is that it waits for the first input, before it even starts listening on the second. How can I make it listen on both at the same time? Or solve my problem some other way.
Thanks!
Server connection should work like this:
Server gameServer = new Server();
ServerSocket server;
try {
server = new ServerSocket(10100);
// .. server setting should be done here
} catch (IOException e) {
System.out.println("Could not start server!");
return ;
}
while (true) {
Socket client = null;
try {
client = server.accept();
gameServer.handleConnection(client);
} catch (IOException e) {
e.printStackTrace();
}
}
In hanleConnection() you start a new thread and run the communication for this client in the created thread. Then the server can accept a new connection (in the old thread).
public class Server {
private ExecutorService executor = Executors.newCachedThreadPool();
public void handleConnection(Socket client) throws IOException {
PlayerConnection newPlayer = new PlayerConnection(this, client);
this.executor.execute(newPlayer);
}
// add methods to handle requests from PlayerConnection
}
The PlayerConnection class:
public class PlayerConnection implements Runnable {
private Server parent;
private Socket socket;
private DataOutputStream out;
private DataInputStream in;
protected PlayerConnection(Server parent, Socket socket) throws IOException {
try {
socket.setSoTimeout(0);
socket.setKeepAlive(true);
} catch (SocketException e) {}
this.parent = parent;
this.socket = socket;
this.out = new DataOutputStream(socket.getOutputStream());;
this.in = new DataInputStream(socket.getInputStream());
}
#Override
public void run() {
while(!this.socket.isClosed()) {
try {
int nextEvent = this.in.readInt();
switch (nextEvent) {
// handle event and inform Server
}
} catch (IOException e) {}
}
try {
this.closeConnection();
} catch (IOException e) {}
}
}

Categories

Resources