Server with multiclients via thread - java

I'm having a bit of trouble, now I have looked at this tutorial
http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
This tutorial gives you a server that multiple clients can connect to, when they connect to the server they are told to go along with a knock knock job, now I understand how to transfer the data and what not, but how does the threads work?
I'm working on a networked pong game where a server will hold the positions and pass them to the clients, now I have a client connected to the server and the ball position is passed to the client, works fine, a bit jumpy but I'm sure a thread with .sleep will help. but anyways my question is, how can i get my client to become a thread? and how can I store them?
For example here is the knock knock server multiThread class
package knockKnockServer;
import java.net.*;
import java.io.*;
public class KKMultiServerThread extends Thread {
private Socket socket = null;
public KKMultiServerThread(Socket socket) {
super("KKMultiServerThread");
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye"))
break;
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here in the server we have
package knockKnockServer;
import java.net.*;
import java.io.*;
public class MultiKKServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new KKMultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
Now looking at the server it will create a new KKMultiServerThread on each connection, but how can i store them? can i make a array of KKMultiServerThread?
I tried to make an array of KKMultiServerThread
and when i try this line
multi[0] = new KKMultiServerThread(serverSocket.accept()).start();
I get this error "cannot convert void to Thread"
If anyone can shine some light on my problem it would be great.
Canvas
Update
I now have my own thread class
package Pong;
import java.net.*;
import java.io.*;
public class PongPlayerThread extends Thread
{
private Socket socket = null;
private String pongData = "";
public PongPlayerThread(Socket socket, int id)
{
super("PongPlayerThread");
this.socket = socket;
}
public void passData(String data)
{
pongData = data;
}
public void run()
{
try
{
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while(true)
{
out.println(pongData);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
the pongData is a string that holds all the information together in a string, now if i declare a player1 at the top of my pong server like so
private static PongPlayerThread player1;
and do this line when it is listening
while(listen)
{
PongPlayerThread player1 = new PongPlayerThread(serverSocket.accept(), 0).start();
}
it gives me this error "cannot convert from void to PongPlayerThread" how do i fix this?

Your array declaration is missing the object type
KKMultiServerThread multi[0] = new KKMultiServerThread(serverSocket.accept()).start();
Why bother though? Unless the threads needs to communicate with each other, letting the threads run freely is ok. The Run() method defines the entire lifetime of the socket as far as the server is concerned. Each thread has a separate copy of the state of the game (as long as you don't use statics) and will happily communicate with the client without any extra intervention.
This is a case where the Socket/Thread library in Java is doing you a big favor, don't make it more complicated unless you have a specific need.

When ever a client connects to the server. The server will typically create a new thread specifically for that client. Here is some pseudo code:
WHILE SERVER IS RUNNING
SERVER WAITS FOR A CLIENT TO CONNECT
SERVER ACCEPTS THE CLIENT IF THERE IS ENOUGH MEMORY TO CREATE A NEW THREAD
SERVER CREATES A NEW THREAD ROUTINE FOR THE CLIENT PASSING THE CLIENT INFORMATION TO THE THREAD
SERVER CONTINUES TO LISTEN WHILE EACH THREAD IS SPECIFICALLY TAILORED FOR THE CLIENTS
REPEAT
You asked what steps are needed to reduce lag? Well for starters, set a maximum allowed connections. You do not want 5000 clients having their own thread. Unless your machine can handle all that and still run. Use UDP instead of TCP, and data compression try to minimize bandwidth don't send 50 GB of information at a time; if all you need is a couple of bytes of information to send. Try to send information of positions not as strings but in bytes. For example you can send the position X=5Y=0 as 50 and parse the first decimal digit as X and the second decimal digit as Y.
Instead of passing the client socket inside the thread routine pass a unique identifier for the client. Since Pong is two players limit the connections to two clients. 0 for Player 1 and 1 for Player 2. So
new KKMultiServerThread(clientID).start(); // clientID is of type int
Edit:
int id = 0;
while(serverIsRunning)
{
Client client = server.accept();
if (id > 2) client.Close(); // Do not accept.
Thread.New(id).Start();
id++;
}

Related

How to connect multiple players via sockets in java?

I'm currently working on a tcg (Trading card Game) in java. The UI for the players and the game itself are working fine, I just need to connect them now. I have a class Game.java that contains all the information about the current match as well as the methods to manipulate that state (for example, playing a card). Then I have the GUI (a JavaFX application) which is supposed to get the appropriate information from the Game instance and ddiplay it to the user as well as sending out requests to do stuff like playing a card. As far as I understand I now need to create a Server class that connects to 2 sockets and checks the requests. However, all the examples I found online only echoed Strings and never manipulated a data structure or returned something like an int. How would I go about that?
One example I found went like this:
public class EchoMultiServer {
private ServerSocket serverSocket;
public void start(int port) {
serverSocket = new ServerSocket(port);
while (true)
new EchoClientHandler(serverSocket.accept()).start();
}
public void stop() {
serverSocket.close();
}
private static class EchoClientHandler extends Thread {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public EchoClientHandler(Socket socket) {
this.clientSocket = socket;
}
public void run() {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
if (".".equals(inputLine)) {
out.println("bye");
break;
}
out.println(inputLine);
}
in.close();
out.close();
clientSocket.close();
}
}
There are 2 things missing: How do I get a different output type, like an int, and how do I respond to input that changes the game state? For example when someone plays a card I want to show it in both GUIs not just in the one that sent the request.
Another thing I'm interested in is how to open up a new game. Since only 2 players should ever get placed together in a game, the first connection should wait for the 2nd client to start a game. And then, when I get 2 more, i need to open another game that runs parallel to it.

Java chat program works on localhost, but not when hosting on Heroku

Long story short, I stole and modified some code from GeeksForGeeks to practice with sockets. Running code modified for localhost works fine on desktop, but when modifying and attempting to host on Heroku, I can't seem get a connection between the server and client. Server appears to launch and run fine on Heroku, and logs connections that I'm not even making (no idea where those are coming from). Client on the other hand seems to connect, but then doesn't do anything when I send a message. Server doesn't even log my attempted connection, so I know it probably isn't even connecting.
Server code: https://github.com/RenegadeB5/socket in /src/main/java/
Client Code:
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client
{
public static void main(String args[]) throws UnknownHostException, IOException
{
Scanner scn = new Scanner(System.in);
// establish the connection
Socket s = new Socket("<my app name>.herokuapp.com", 80);
// obtaining input and out streams
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
// sendMessage thread
Thread sendMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (true) {
// read the message to deliver.
String msg = scn.nextLine();
try {
// write on the output stream
dos.writeUTF(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
// readMessage thread
Thread readMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (true) {
try {
// read the message sent to this client
String msg = dis.readUTF();
System.out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
sendMessage.start();
readMessage.start();
}
}
I've tried so many different combinations and solutions, and can't find any examples of this being done before. I'd like to know what I'm doing wrong so that I can move on from this headache. Thanks in advance!
Java Socket and ServerSocket use TPC, which is not supported for free by Heroku. As a result, the server will run fine, but anything being sent via TCP, including connection attempts, will not make it to your server unless they are done via http.

Java Socket Timeout although I can connect remote via Telnet [duplicate]

I am trying to build a client/server program and it works fine. When i send a message it gets shown on the server and then it waits for a response from the server but i cant do anything while i wait for a response.
My question is : how can i wait for a response in the background while i can still send messages and just show the server message when it is sent(if it is sent).
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException,UnknownHostException{
// Specify remote address and port
Socket cs = new Socket("localhost", 1337);
// Input and Output
DataInputStream dis = new DataInputStream(cs.getInputStream());
DataOutputStream dos = new DataOutputStream(cs.getOutputStream());
// Writing message to the server
String message = null;
Scanner scan = new Scanner(System.in);
while(true){
message = scan.nextLine();
if(message.equals("exit")) System.exit(0);
dos.writeUTF(message);
dos.flush();
// Check for messages from server ---> Here i wait for a message from the server but how can i wait in background without having my program freeze?
}
}
}
The simplest way in Java is to listen for server data in a separate thread.
Make the input stream final and insert something like this before the while loop reading from the console:
new Thread() {
public void run() {
try {
while (true) {
System.out.println(dis.readUTF());
}
} catch(IOException e) {
e.printStackTrace();
}
}
}.start();
This creates an anonymous subclass of Thread, which will execute the run method in the background when start is called.
When your code grows, you may want to implement the Runnable interface in a separate class and hand it in to the Thread constructor instead.

Implementing a simple java TCP server

There are two readers plugged to the internal network. They just send data to the server machine, where I want to have this java app running receiving the data. It won't be that much data. Each reader could be transmitting single strings like "1234567" to a rate as much as maybe half a dozen times per second.
Without entering into much detail about the readers, they are datalogic and both are different models, but with this in common: They are configured to transmit the data via tcp/ip to a certain ip:port.
I tested the data trasmission with this software: https://www.hw-group.com//products/hercules/index_en.html to see if I'm receiving the data properly and it does check out, it works well.
The problem comes when I run my TCP server implementation: I receive the data from one of the devices 100% of the times, while the other one is hit and miss: Sometimes the data sent over the network never makes it to my app and I don't know why.
I'm pasting the code of what I'm using: It's simple but, with my java knowledge and after digging around the internet, it's the best I came up with.
Here's the java file with the main:
package tcpserverclasstest;
public class TCPServerClassTest {
public static void main(String[] args) throws InterruptedException {
TCPServerThread myTCPServerThread = new TCPServerThread();
myTCPServerThread.start();
}
}
Here's TCPServer.java:
package tcpserverclasstest;
import java.io.IOException;
import java.net.Socket;
import java.io.*;
public class TCPServer extends Thread {
public static final int PORT_NUMBER = 4413;
protected Socket socket;
public TCPServer(Socket socket) {
this.socket = socket;
System.out.println("New client connected from " + socket.getInetAddress().getHostAddress());
start();
}
public void run() {
InputStream in = null;
try {
in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String request;
request = br.readLine();
System.out.println("Message received:" + request);
} catch (IOException ex) {
System.out.println("Unable to get streams from client");
} finally {
try {
in.close();
socket.close();
System.out.println("Socket closed");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
And here's TCPServerThread.java:
package tcpserverclasstest;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerThread extends Thread {
public static final int PORT_NUMBER = 4413;
protected Socket socket;
public void run(){
System.out.println("Waiting for incoming connections on port " + PORT_NUMBER);
ServerSocket server = null;
try {
server = new ServerSocket(PORT_NUMBER);
server.setReceiveBufferSize(262144);
server.setReuseAddress(true);
while (true) {
new TCPServer(server.accept());
}
} catch (IOException ex) {
System.out.println("Unable to start server.");
} finally {
try {
if (server != null)
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I tried to implement the server on a thread since I want to implement this into a bigger project in the future and I don't want that app locked in the loop that is waiting for connections.
Any clues on what should I do to see why I'm not receiving some of the data? Any suggestion on a better way to achieve this?
Thanks!
first thing that comes to mind is your server only connects to one of the clients. Your TCPServerThread's run method listens for one connection and when it is made it initializes a TCPServer with this connection, meaning only one of the readers connects. Maybe after connecting to one reader you can listen for other.
Second, your TCPServer reads only one line and then closes the connection, and a line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed. So your readers should send linefeed ('\n', or '\r', or '\r\n'). If not you shouldn't use readLine, maybe read some amount of data in a while loop.
To debug your TCP connections and really be sure the data is actually coming to your server, you can use WireShark. This shows all the packets coming in your network card and you can filter based on tcp.port to see only your connections.

open multiple server socket ports for multiple clients

I am trying to open multiple ports on a server socket so that i could connect multiple clients. Each time i create a create a thread and start it (i know the overridden run method will be invoked) i open a port and listen for a client .
But the problem is that when i run the client socket project and try to connect to the port i opened in server ,it says java.net.connectException : connection refused:connect.
I also noticed a peculiar thing happenning.The output in the console window is different every time i run the "server code "
i have been working on this for the last 3 days and i have achieved nothing i guess.
note: this problem is unique for me as i have not found this particular problem on this forum any where so please be kind as i am a newbie to java and socket programming though i have been coding on c++ for quite some time now .
server socket
import java.io.*;
import java.net.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.*;
public class TryThreads extends Thread
{
private int Portnumber;
private static String inputLine;
public TryThreads(int portNumber)
{
Portnumber = portNumber;
setDaemon(true);
}
public static void main(String[] args)
{
//create three threads
Thread first = new TryThreads(63400);
Thread second = new TryThreads(63401);
first.start();
second.start();
//third.start();
System.out.println("ending main");
return;
}
public void run()
{
try
{
System.out.println("one socket port opened");
ServerSocket serverSocket = new ServerSocket(Portnumber);
System.out.println("one socket port opened");
while (true)
{
System.out.println("ending main2");
//System.out.println("one socket port opened");
Socket clientSocket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while((inputLine = bufferedReader.readLine()) != null)
System.out.println(inputLine);
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
client socket
import java.io.*;
import java.net.Socket;
public class client
{
private static PrintWriter printWriter;
public static void main(String[] args)
{
BufferedReader in = null;
try
{
Socket socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
printWriter.println("EYYYYYAAAAAAAA!!!!");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
In your TryThreads constructor, use:
setDaemon(false);
You have set your server threads to be daemon threads and they are therefore terminating as soon as main exits, so your server is stopping as soon as you start it.
See Thread.setDaemon():
The Java Virtual Machine exits when the only threads running are all daemon threads.
By the way, after the above issue is corrected, be aware that your implementation will lead to the server receiving a "connection reset" SocketException, which will break your server thread out of its loop and prevent it from accepting additional exceptions. You can fix this on the client side by doing socket.close() before you exit to ensure a graceful shutdown, but you will still want to fix it on the server side since you cannot assume that clients will be well-behaved.
Normally whenever you want to write a message using PrintWriter, you need to flush it when your done (printwriter.flush()). That makes sure the message is sent.

Categories

Resources