Hello I am creating a server for the turn based game. I achieved connecting people to the server in the separated threads and they can send messages to server and recieve answer from server. However, now I need to connect two people to one room and make them communicate with each other (I do not know if through server or just somehow connect them with each other. These people connect to server and can communicate with it when every of them has one clientHandler. However, when I make a clientHandler which handles two sockets it does not work. Does somebody know how to make handler (room on a server) in which the pair of clients could send message to each other?
public void handlePVPGame(Socket playerWhite, Socket playerBlack, int pointerId) throws IOException {
int firstPlayerId = pointerId;
pointerId +=1;
int secondPlayerId = pointerId;
ClientHandler clientHandlerWhite = new ClientHandler(playerWhite);
ClientHandler clientHandlerBlack = new ClientHandler(playerBlack);
new Thread(clientHandlerWhite).start();
new Thread(clientHandlerBlack).start();
// This does not work
// TwoClientsHandler twoClientsHandler = new TwoClientsHandler(playerWhite, playerBlack);
// new Thread(twoClientsHandler).start();
// ClientHandlerClass
public class ClientHandler implements Runnable {
private final Socket clientSocket;
private PrintWriter printWriter;
private BufferedReader bufferedReader;
private InputStreamReader inputStreamReader;
public ClientHandler(Socket socket)
{
this.clientSocket = socket;
}
#Override
public void run() {
try {
printWriter = new PrintWriter(clientSocket.getOutputStream());
inputStreamReader = new InputStreamReader(clientSocket.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
String receivedMessage;
while ((receivedMessage = bufferedReader.readLine())!= null){
System.out.printf(
" Sent from the client: %s\n",
receivedMessage);
printWriter.println("Welcome to server");
printWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Class which does not work
public class TwoClientsHandler implements Runnable{
private final Socket playerWhite;
private PrintWriter printWriterWhite;
private InputStreamReader inputStreamReaderWhite;
private BufferedReader bufferedReaderWhite;
private final Socket playerBlack;
private PrintWriter printWriterBlack;
private InputStreamReader inputStreamReaderBlack;
private BufferedReader bufferedReaderBlack;
public TwoClientsHandler(Socket playerWhite,Socket playerBlack) {
this.playerWhite = playerWhite;
this.playerBlack = playerBlack;
}
#Override
public void run() {
try {
printWriterWhite = new PrintWriter(playerWhite.getOutputStream());
inputStreamReaderWhite = new InputStreamReader(playerWhite.getInputStream());
bufferedReaderWhite = new BufferedReader(inputStreamReaderWhite);
printWriterBlack = new PrintWriter(playerBlack.getOutputStream());
inputStreamReaderWhite = new InputStreamReader(playerBlack.getInputStream());
bufferedReaderWhite = new BufferedReader(inputStreamReaderWhite);
String receivedMessage;
while ((receivedMessage = bufferedReaderWhite.readLine())!= null){
System.out.printf(
" Sent from the client: %s\n",
receivedMessage);
printWriterWhite.println("Welcome to server");
printWriterWhite.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I suggest sticking to a one-thread one-client approach. It is a much simpler solution requiring the creation of the protocol according to which users will send the messages. Say, your game is chess. Mike opens the application:
You create a separate thread for Mike and give him some UUID
You assign this UUID to the specific room
You keep UUID as a key and Room as the value in the ConcurrentHashMap
Room has an array of UUIDs and potentially whose the next turn
In the Server thread, you assign to Mike UUID 5 and room 3. Now when Mike wants to move his bishop to D5, he sends for example 5BD5. Then:
You parse this message according to your protocol, so you extract UUID from the first character of the message -- 5, chess piece -- B, being bishop and square of the chessboard -- D5.
Having UUID extracted you immediately have a room and from the room you have the second player whom potentially you'd like to pass the messages from Mike.
This way you have perfectly separated rooms from one another. The server will convey the messages between the users only within the same room.
You can have several threads in one socket using Java NIO Selector, however, for your purpose above solution seems to be simpler.
Related
I am creating a simple java program that creates two threads when it starts, each of these thread creates a server that listen to different port(ie port 5500, 5100), those servers each have clients, now i want the servers to be able to pass information from their client to each other. How do i do that. this is the code i have for the servers
class SocketSeverBrooker extends Thread{
int portNumber = 5500;
ServerSocket serverSocket = null;
int clientID = 10000;
public void run(){
try {
serverSocket = new ServerSocket(portNumber);
while(true){
try{
// i am accepting acconection from a client
Socket clientsocket = serverSocket.accept();
new Thread(new BrokerRunnable(clientsocket)).start();
System.out.println("a broker has connected with id "+ clientID);
clientID++;
}catch(IOException e){
System.out.println("client could not connect");
}
}
}catch (IOException e){
System.out.println("could not create a connection");
}
}
}
class BrokerRunnable implements Runnable{
protected Socket clientSocket;
public BrokerRunnable(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
// create two way communication
// this is used to get input from the connected client clientSocket.getInputStream()
// new BufferedReader();
try{
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);// write the sever
String arg1;
arg1 = in.readLine();
System.out.println( arg1);
Scanner scanner = new Scanner(System.in);
String msgToBrokker = scanner.nextLine();
out.println(msgToBrokker);
}catch(IOException e){
System.out.println("could not read");
}
}
}
I am unable to ask a question using a comment. Hence writing here. Sorry.
What i understood from the question, Please correct me if this is not the case.
We have multiple servers (S) and each may have multiple clients (C) too.
S1 -> S1C1, S1C2, ...., S1Cn
S2 -> S2C1, S2C2, ...., S2Cn
......
Sm -> SmC1, SmC2, ...., SmCn
Servers to share information with other servers that can be passed to clients.
If above understanding is correct, then you should have a common object (like a list, map) which can be shared by all the Servers. This object will store the information from all the servers. You will need to put a logic how will you which information to read by a server (for ex. S1 shouldn't read the information added by itself).
Hope this helps.
I am trying to improve the speed at which the sockets transfer information but i am unsure how to do so. the pourpose of the code is to transfer a number, the date, and a short xml which is being sent in the form of a string.
this is the server code
import java.net.*;
import java.io.*;
public class SSocket extends Thread
{
private ServerSocket serverSocket;
public SSocket(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(100000);
}
public void run()
{
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
while(true)
{
try
{
Socket server = serverSocket.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
int cor=in.readInt();
int i=0;
String transaccion = in.readUTF();
String fecha = in.readUTF();
System.out.println(cor);
System.out.println(transaccion);
System.out.println(fecha);
DataOutputStream out =
new DataOutputStream(server.getOutputStream());
if(transaccion!=null && fecha != null && cor>0){
out.writeInt(cor);
}
else {
out.writeInt(-1);
}
if (i==100){
out.flush();
i=0;
}
i++;
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = 1337;
try
{
Thread t = new SSocket(port);
t.start();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
the code for the client is
import java.net.*;
import java.io.*;
public class ClientSocket
{
public static void send(int correl, String transaccion, String fecha)
{
String serverName = "localhost";
int port = 1337;
try
{
Socket client = new Socket(serverName, port);
int i=0;
OutputStream outToServer = client.getOutputStream();
DataOutputStream out =
new DataOutputStream(outToServer);
out.writeInt(correl);
out.writeUTF(transaccion);
out.writeUTF(fecha);
InputStream inFromServer = client.getInputStream();
DataInputStream in =
new DataInputStream(inFromServer);
int corin=in.readInt();
if(corin>0){
Envio.updater(corin);
}
else {
}
if (i==100){
out.flush();
i=0;
}
i++;
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
i have done some reading on the mater and it seems that posible solutions are to use either a buffer or swich to a datagram. however my experience on working with sockets is rather limited and i am unsure which would be best to use for this situation or if there is another option i havent yet considered. this code will be moving many transactions and i wish to do it in as short time as posible.
thanks in advance
ps. sorry for my bad english it is not my first language
Datagrams imply UDP, which is an unreliable delivery protocol so you're not guaranteed to get all content. That's probably not what you want; I'd stay with plain Sockets (which use TCP, which has reliable delivery).
Will the same client be calling send() repeatedly and connecting to the same server each time? That is, will there be many messages going across a single connection, or will each message be to a different server, with only a single message (or only a few) going to each of the many servers? If there's just one server that a client is going to connect to and if a given client is going to send lots of messages, you should keep the Socket open between send() calls; setting up and tearing down Sockets is expensive, so you're paying a high price for making a new connection each time.
Also, your server appears to only be able to handle a single connection at a time: you accept a connection, read from it, and then close it and accept a new one. So to make this work for more than one client, you'll need to separate the logic for accepting connections onto a different thread from the logic that reads data. If you'll only have a few clients at a time, you can just start a new thread to read from each socket as you create it for a new client; if you'll have lots of clients (thousands), you'll probably need to look at NIO for its ability to service multiple sockets from a single thread. But I suspect you're a long way from having that problem, if you ever do, so I'd just spawn a new thread for each socket.
I'm using a server socket to accept clients on the main thread, when a thread is accepted,the clients socket is given to a handler which is started in a new thread to process communications. However, before I start running my server to access clients, it connects to a second server which it must list to and be able to respond to and pass on the messages it gets to it's clients.
Hopefully this image illustrate what I mean:
The small server must be continuously listening for input from the big server, and also able to output responses.
//Default constructor
private smallServer(){}
//method to initialise and start the server
public static void StartServer(int port) throws IOException {
smallServer ss = new smallServer();
ss.bs= new bigServerClient(ss);
Thread nsc_Thread = new Thread(ss.bsc);
bsc_Thread.start();
//accepts clients and starts new thread for them
ss.ServerRun(port);
}
private void ServerRun(int port) throws IOException {
ServerSocket server = new ServerSocket(port);
server.setSoTimeout(50);
while (run) {
Socket client = null;
try {
client = server.accept();
} catch (SocketTimeoutException e) {
}
if (client != null) {
ClientHandler handler = new ClientHandler(client, this);
Thread handleThread = new Thread(handler);
handleThread.start();
}
}
if (!run) {
synchronized (ClientHandler.handlers) {
for (ClientHandler handler : ClientHandler.handlers) {
handler.terminateHandler();
}
}
System.exit(0);
}
}
public void processBigServerCommand(String toProcess) {
System.out.println("RESEAVED: " + toProcess);
}
The big server client(on the small server) then does this:
public class bigServerClient implements Runnable {
private smalsServer ss;
private PrintWriter printer;
private BufferedReader reader;
private Socket socket;
public bigServerClient(smallServer _ss) throws IOException {
ss = _ss;
socket = new Socket("Localhost", 5000);
printer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printer.flush();
SendBigServerMessage("Starting String");
}
private void SendBigServerMessage(String toSend) {
printer.print(toSend);
printer.flush();
}
#Override
public void run() {
try {
while (ss.state()) {
String inputLine;
while ((inputLine = reader.readLine()) != null) {
ss.processBigServerCommand(inputLine);
System.out.println(inputLine);
}
}
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException ex) {
}
}
}
}
From what's above, can anyone see why the big server client isn't responding to the big server when a message is sent? I'm guessing it's something to do with the main thread blocking the second thread, but I'm not sure... Any help would be greatly appreciated.
You lost me in your code...
Simplify it.
Your smallServer (see class names conventions) should have persistent connection to BigServer (effectively it is BigServer client) - you can implement it in your smallServer class, it should connect (once) and open I/O to BigServer (once) and close everything once the connection is terminated.
As your smallServer will handle multiple clients and pass their requests to BigServer there is no guarantee of the order of BigServer responses - you should do something to handle that (maybe pass UUID with requests?)
Simplify your smallServer and make sure that it runs...
Given the following code:
Client c1 = new Client();
c1.connect("127.0.0.1",1300);
Connect function:
public void connect(String serverName, int port)
{
try {
Socket socket = new Socket(serverName,port);
connection = new ConnectionProxy(socket);
connection.start();
}
catch(IOException e)
{
e.printStackTrace();
}
}
(ConnectionProxy class extends Thread) :
public class ConnectionProxy extends Thread {
private Socket socket;
private InputStream is;
private OutputStream os;
private StringConsumer client;
public ConnectionProxy(Socket socket)
{
this.socket = socket;
try {
is = socket.getInputStream();
os = socket.getOutputStream();
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void run () {
DataInputStream dis = new DataInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
while (socket != null)
{
try {
String msg = dis.readUTF();
System.out.println(msg);
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
I'm trying to implement a chat and I'm finding it difficult to send a message written by a client to all of the currently connected clients.
How could I do that? Should I hold the reference for each object (like c1) on the server side, or should I hold that ConnectionProxy thread on the server side?
If not, how do I implement that correctly and efficiently?
Would love to get some help!
Thanks!
Without being given much code, I'll outline what you'd want to do to achieve your goal.
On your server:
Keep an array or something similar of all connected client objects
Implement a send() function in your client class
Implement a broadcast() function that loops through the client list and sends each of them the message (using the aforementioned send() function
Make sure to keep track of (and remove) any dead/disconnected clients from your list, otherwise you'll run into trouble trying to send to them.
On your client:
Make sure you send a "connection terminated" message when you close/disconnect to tell the server you're leaving (makes it easier for the server to remove you)
The server should create a new client handler thread for each incoming connection.
For example, on the server side try something like:
ServerSocket server = new ServerSocket(port);
while (true) {
Socket client = server.accept();
//add incoming client to connected clients vector.
HandleClient c = new HandleClient(client);
clients.add(c);
}
After creating and storing clients in your vector of clients, you can the implement on the HandleClient class run() method a bufferReader (again not a must) to get your client text
I am currently developing a prototype for a game and I need a simple server to run it.
At this stage, I don't want to invest the time learning about all the different full-featured multiplayer game servers already there (smartfox, etc...)
I know how to develop a basic Server with Threads listening on Sockets but I have ran into a roadblock. Here's the run() function of the Thread
public void run() {
try {
out = new PrintWriter(mSocket1.getOutputStream(), true);
in = new BufferedReader( new InputStreamReader( mSocket1.getInputStream() ) );
String inputLine1 = null, outputLine;
out.println("hello");
out.flush();
while( (inputLine1 = in.readLine()) != null) {
outputLine = mGameControl.processInput(mPlayerNum, inputLine1);
out.println(outputLine);
out.flush();
if(outputLine.contentEquals("bye"))
break;
}
Terminate();
}
catch(IOException e) { e.printStackTrace(); }
}
Now my problem is that the thread is blocked waiting for input. I do have other similar Threads connected to other client which may result in information being dispatched to all clients...
How can I modify it so that a different Thread can interact with it and push info to the client?
Just write a synchronised public method which writes to your PrintWriter, and allow other threads to use it to send messages to your client. Call the same method from your read loop to avoid two threads writing at the same time.
Here's a tested example:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTest {
public static class Client implements Runnable {
private final BufferedReader in;
private final PrintWriter out;
public Client(Socket clientSocket) throws IOException {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) );
}
public void run() {
send("Hello");
String inputLine1 = null, outputLine;
try {
while( (inputLine1 = in.readLine()) != null) {
outputLine = inputLine1.toLowerCase();
System.out.println(inputLine1);
send(outputLine);
if(outputLine.contentEquals("bye"))
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void send(String message) {
out.println(message);
out.flush();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket s = new ServerSocket(5050);
Socket clientSocket = s.accept();
Client client = new Client(clientSocket);
Thread clientThread = new Thread(client);
clientThread.start();
int i = 1;
while (true) {
Thread.sleep(1000);
client.send("Tick " + (i++));
}
}
}
Use Netty to handle your connections and query treatments. Since I discovered that project, I never touched sockets directly anymore (except when writing C programs, etc.)
There are actually some examples to look at and the documentation is quite extensive. The project is very well alive since a couple of years already, and is not soon to die! There's a fairly large user base behind it.
If you only need to perform a non-blocking read on the socket, one of the simplests ways is to use available(). Call available and if there is data to read (bytes pending > 0), perform the read, any way, wait using Thread.sleep() and try to read again. This allow the thread to do while waiting for input data and cat react to external signals.
The use of selectors is encouraged when you need to perform high-performance non-blocking read using one thread and several sockets (java.nio.channels.Selector).