I recently started to make a 2d java game, now I began the TCP server, though the server runs insanely slow (Average of 2 seconds) and I can't figure out how to stop the input stream from metering all the data into one string. I would greatly appreciate it if someone is able to help me.
ServerCode:
package com.diedericksclan.main.network;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
public class ServerThread extends Thread {
private ServerHandler server;
private ServerSocket dataSocket;
private Socket socket;
private InetSocketAddress address;
private int megabyte = 1024 * 1024;
private int dedicated = 1024;
public int RAM = megabyte * dedicated;
private WriteData send;
private ReadData read;
public ServerThread(ServerHandler server, String serverIP, int ram, int backlog) throws Exception {
this.server = server;
this.dedicated = ram;
//System.out.println(serverIP);
String ip = "localhost";
int port = 2048;
if(serverIP.contains(":")) {
ip = serverIP.split(":")[0];
port = Integer.parseInt(serverIP.split(":")[1]);
} else {
ip = serverIP;
port = 2048;
}
//System.out.println("Makin' the server");
this.dataSocket = new ServerSocket(port, backlog, InetAddress.getByName(ip));
this.address = new InetSocketAddress(dataSocket.getInetAddress(), port);
this.send = new WriteData();
this.read = new ReadData();
//System.out.println("Makin' the data handlers");
//System.out.println("Server has been made, details: " + address.getAddress() + ":" + address.getPort());
}
public ServerThread(ServerHandler server, String ip) throws Exception {
this(server, ip, 1024, 0);
}
public void run() {
//System.out.println("made");
this.send.start();
this.read.start();
while(true) {
try {
socket = dataSocket.accept();
socket.setReceiveBufferSize(megabyte);
socket.setSendBufferSize(megabyte);
socket.setTcpNoDelay(true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void sendData(byte[] data, InetAddress IPaddress, int port) {
this.send.sendData(data, IPaddress, port);
}
public void serverShutdown() {
try {
this.dataSocket.close();
if(this.socket != null) this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public class WriteData extends Thread {
public WriteData() {}
public void sendData(byte[] data, InetAddress IPaddress, int port) {
try {
System.out.println("[" + System.currentTimeMillis() + "] Sending... " + new String(data));
socket.getOutputStream().write(data);
socket.getOutputStream().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ReadData extends Thread {
public ReadData() {}
public void run() {
try {
this.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
byte[] data;
while(true) {
try {
data = new byte[megabyte];
socket.getInputStream().read(data);
System.out.println("[" + System.currentTimeMillis() + "] Server has read, " + new String(data) + ", details: " + socket.getLocalAddress().getHostName() + ":" + socket.getLocalPort());
server.parsePacket(data, socket.getInetAddress(), socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
ClientCode:
package com.diedericksclan.main.network;
import java.io.*;
import java.net.*;
public class ClientThread extends Thread {
private ClientHandler client;
private Socket socket;
private InetSocketAddress address;
private int megabyte = 1024 * 1024;
private WriteData send;
private ReadData read;
public ClientThread(ClientHandler client) {
this.client = client;
this.address = new InetSocketAddress("192.168.1.2", 2048);
socket = new Socket();
try {
socket.setSendBufferSize(megabyte);
socket.setSendBufferSize(megabyte);
socket.setTcpNoDelay(true);
socket.connect(address);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//System.out.println("Made client");
this.send = new WriteData();
this.read = new ReadData();
//System.out.println("Client has been made, details: " + socket.getLocalAddress() + ":" + socket.getLocalPort());
}
public void run() {
//System.out.println("made");
this.send.start();
this.read.start();
}
public void sendData(byte[] data) {
this.send.sendData(data);
}
public void serverShutdown() {
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public class WriteData extends Thread {
public WriteData() {}
public void sendData(byte[] data) {
try {
//System.out.println("[" + System.currentTimeMillis() + "] Sending... " + new String(data) + " to: " + socket.getInetAddress() + ":" + socket.getPort());
socket.getOutputStream().write(data);
socket.getOutputStream().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ReadData extends Thread {
public ReadData() {}
public void run() {
byte[] data;
while(true) {
try {
data = new byte[megabyte];
socket.getInputStream().read(data);
System.out.println("[" + System.currentTimeMillis() + "] Server data recived, " + new String(data).trim());
client.parsePacket(data, socket.getInetAddress(), socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
I did try to improve speed by making 2 separate threads for reading and writing data, in both the client and server, yet there was no improvement,
You have a few problems.
you allow any number of threads to write to the same socket at the same time. This makes developing a protocol very hard.
you need a protocol so you know where a message starts and end. e.g. you send the length first.
you ignore how many bytes where read. The minimum will be 1 and you can get any number of messages up to the size of the buffer at once. TCP is a stream protocol, not a messaging protocol.
If you have a reader and writer process on the same machine you should be able to get the latency to around 10 micro-seconds. (0.000010 seconds)
EDIT here is a simple example
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class PlainIOSample {
static final int RUNS = 1000000;
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(0);
DataSocket ds = new DataSocket(new Socket("localhost", ss.getLocalPort()));
DataSocket ds2 = new DataSocket(ss.accept());
long start = System.nanoTime();
for (int i = 0; i < RUNS; i++) {
// send a small message
ds.write(new byte[64]);
// receive the same message
byte[] bytes = ds2.read();
if (bytes.length != 64)
throw new AssertionError();
}
long time = System.nanoTime() - start;
System.out.printf("Average time to send/recv was %.1f micro-seconds%n",
time / RUNS / 1e3);
ds.close();
ds2.close();
}
static class DataSocket implements Closeable {
private final DataOutputStream dos;
private final DataInputStream dis;
private final Socket socket;
public DataSocket(Socket socket) throws IOException {
dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
this.socket = socket;
}
public void write(byte[] message) throws IOException {
synchronized (dos) {
dos.writeInt(message.length);
dos.write(message);
dos.flush();
}
}
public byte[] read() throws IOException {
synchronized (dis) {
int length = dis.readInt();
byte[] bytes = new byte[length];
dis.readFully(bytes);
return bytes;
}
}
#Override
public void close() throws IOException {
socket.close();
}
}
}
prints
Average time to send/recv was 3.3 micro-seconds
Related
I have a Java program with a client and server sockets, there I want to test that an exception is raised after the server is down.
This is the server:
public class SocketServer implements Runnable {
private bool serverRuns = false;
private int timeout = 10000;
private DataInputStream in;
private DataOutputStream out;
private Socket client;
private ServerSocket server;
private String message = "Ok";
private waitForInstruction = true;
public SocketServer() throws IOException {
ServerSocket server = new ServerSocket(tcpPort,0,ipAdress);
serverRuns = true;
server.setSoTimeout(timeout)
}
private void waitForClient() {
try {
client = server.accept();
client.setSoTimeout(timeout);
in = new DataInputStream(client.getInputStream());
out = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
fail("I/O Error " + e.getMessage());
}
}
public void run() {
waitForClient();
while (serverRuns) {
if (clientSocket.isClosed()) {
waitForClient();
}
try {
while (waitForInstruction == false) {
// Read input message
String inputStreamString = "";
while (in.available() > 0) {
int c = in.read();
inputStreamString += (char) c;
}
out.write(message.getBytes());
System.out.println("Sent bytes: " + out.size());
setWaitForInstruction(true);
}
} catch (IOException E) {
fail("I/O Error " + E.getMessage());
}
}
}
public void closeServerSocket() {
try {
serverRuns = false;
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
void setWaitForInstruction(boolean waitForInstruction) {
this.waitForInstruction = waitForInstruction;
}
public void startServerSocket() {
serverRuns = true;
}
}
This is the client:
public class SocketClient extends Socket {
private InetAddress address;
private short tcpPort;
private DataInputStream in;
private DataOutputStream out;
private static final int timeOut = 10000;
public SocketClient(InetAddress address, short tcpPort) {
this.tcpPort = tcpPort;
this.address = address;
}
public void connect() throws IOException, SocketTimeoutException {
super.connect(new InetSocketAddress(address, tcpPort), timeOut);
}
public void doStuff() throws IOException {
String request = "Ok?";
String InputStreamString = "";
super.setSoTimeout(timeOut);
this.setSoTimeout(timeOut);
out = new DataOutputStream(super.getOutputStream());
in = new DataInputStream(super.getInputStream());
out.writeBytes(requestString);
int c;
do {
if (in.available() > 0) {
c = in.read();
InputStreamString += (char) c;
}
} while (!InputStreamString.equals("Ok"));
System.out.println(InputStreamString);
}
}
I start the server socket thread with:
#BeforeClass
public static void startSocket() throws IOException {
testServer = new SocketServer();
monitor = new Thread(testServer);
monitor.setName("Test Server Thread");
monitor.setDaemon(true);
monitor.start();
}
And the JUnit test is this:
#Before
public void createSocket() throws Exception {
ipAdress = InetAddress.getLocalHost();
SystemConfig.setLoggerConfigFilePath("LoggerConfig.xml");
socketClient = new SocketClient(ipAdress, 5000);
}
#Test
public void checkServerisDown() {
try {
socketClient.connect();
} catch (IOException e) {
fail("IO Error");
}
testServer.closeServerSocket();
monitor.interrupt();
try {
testServer = new SocketServer();
monitor = new Thread(testServer);
monitor.setName(" Test Server Thread");
monitor.setDaemon(true);
// monitor.start();
testServer.startServerSocket();
testServer.setWaitForInstruction(false);
System.out.print("Test (1/1) CHECK SERVER IS DOWN.....\n");
socketClient.doStuff();
System.out.println("NOT OK!");
} catch (IOException e) {
fail("IO Error " + e.getMessage() + " OK");
}
try {
drEstimControlInterface.close();
testServer.getSocket().close();
} catch (IOException e) {
fail("IO Error");
}
}
#AfterClass
public static void closeSocket() throws IOException {
testServer.closeSocket();
}
However the test is not performing as I intended, I thought that this should return an IOException since the server socket has been closed and the thread has been interrupted, but the client socket still gets the answer from the server socket and prints the "NOT OK!". Could anybody tell me why?
You have to close not only ServerSocket but client socket with streams too.
public void closeServerSocket() {
try {
serverRuns = false;
serverSocket.close();
in.close();
out.close();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I have the following issue connecting to a AccessGard (newnet) solution that forwards TPC messages to my application from a POS.
Basically the AG automatically connects from an ip "X.X.X.2" to my pooled server but it never sends any data.
When the POS send the message for some reason the AG sends the TPC request from another IP "X.X.X.132" but it never triggers the serverSocket.accept()
With wiresharck I can see Keep Alive messages from the X.X.X.2 to my server every second. Also I can see the request incoming from ip "X.X.X.132" but it never reaches the server. All the incoming transmissions come to the same port.
here is my server :
public class Server2 {
protected int serverPort = 8005;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread= null;
protected ExecutorService threadPool = Executors.newFixedThreadPool(10);
public Server2()
{}
public void run(){
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
if(isStopped()) {
System.out.println("Server Stopped.") ;
break;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
this.threadPool.execute(
new WorkerRunnable(clientSocket,
"Thread Pooled Server"));
}
this.threadPool.shutdown();
System.out.println("Server Stopped.") ;
}
private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort);
} catch (IOException e) {
throw new RuntimeException("Cannot open port 8005", e);
}
}
private synchronized boolean isStopped() {
return this.isStopped;
}
}
here the worker:
public class WorkerRunnable implements Runnable
{
private static final Logger logger = Logger.getLogger(WorkerRunnable.class);
protected Socket connectionSocket = null;
protected String serverText = null;
public WorkerRunnable(Socket connectionSocket, String serverText) {
this.connectionSocket = connectionSocket;
this.serverText = serverText;
}
public void run() {
try {
System.out.println(read());
} catch (IOException e) {
//report exception somewhere.
e.printStackTrace();
}
}
private String read() throws IOException
{
InputStream in = connectionSocket.getInputStream();
byte[] m = new byte[2];
in.read(m,0,2);
ByteBuffer wrapped = ByteBuffer.wrap(m);
short num = wrapped.getShort();
logger.info("IN message length:" + num +" Hexa:" + String.format("%02x", m[0]) + String.format("%02x", m[1])); System.out.println("IN message length:" + num +" Hexa:" + String.format("%02x", m[0]) + String.format("%02x", m[1]));
byte[] message = new byte[num];
in.read(message,0,num);
String inMessage = Util.bytesToHex(message);
logger.info("Full message:" + inMessage); System.out.println("Full message:" + inMessage );
return inMessage;
}
}
Try to do some concurrent messaging between the server and the client. When they first connect to eachother and the Server sends the test string, the client gets it perfectly fine the first time. And the client can SEND messages just fine to the Server. But my Client class cant constantly check for messages like my Server can and idk what's wrong. Any suggestions?
Server class code:
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.Random;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
String testMessage = "You are now connected and can begin chatting!";
boolean connected = false;
int port;
public Server(int port) {
this.port = port;
}
public void Open() {
//creates Threadpool for multiple instances of chatting
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
System.out.println("Opening...");
ServerSocket srvr = new ServerSocket(port);
while (true) {
Socket skt = srvr.accept();
clientProcessingPool.submit(new ClientTask(skt));
}
} catch (Exception e) {
try {
System.out.println(e);
System.out.print("You're opening too many servers in the same location, fool!\n");
ServerSocket srvr = new ServerSocket(port);
while (true) {
Socket skt = srvr.accept();
clientProcessingPool.submit(new ClientTask(skt));
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
private class ClientTask implements Runnable {
private final Socket skt;
private ClientTask(Socket skt) {
this.skt = skt;
}
#Override
public void run() {
//for sending messages
if (connected == false) {
System.out.println("======================");
System.out.println("Server has connected!");
processMessage(testMessage);
}
//for receiving messages
while (true) {
try {
// Read one line and output it
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String incomingMessage = br.readLine();
if (incomingMessage != null) {
System.out.println("Server: Received message: " + incomingMessage);
processMessage(incomingMessage);
}
//br.close();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.println("Server had error receiving message.");
System.out.println("Error: " + e);
}
}
}
//for processing a message once it is received
public void processMessage(String message) {
PrintWriter out = null;
try {
out = new PrintWriter(skt.getOutputStream(), true);
} catch (IOException ex) {
System.out.println(ex);
System.out.println("Server had error sending message.");
}
System.out.print("Server: Sending message: " + message + "\n");
out.print(message);
out.flush();
connected = true;
try {
skt.shutdownOutput();
//out.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Client class code:
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
class Client {
public String message;
Socket skt;
public int port;
public Client(int port) {
this.port = port;
}
//for receiving messages from Server
public void receiveMessage() {
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
skt = new Socket(InetAddress.getLocalHost().getHostName(), port);
while (true) {
clientProcessingPool.submit(new Client.ClientTask(skt));
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
//for sending messages to Server
public void sendMessage(String outgoingMessage) throws IOException {
try {
skt = new Socket(InetAddress.getLocalHost().getHostName(), port);
PrintWriter pw = new PrintWriter(skt.getOutputStream());
System.out.println("Client: Sending message: " + outgoingMessage);
pw.print(outgoingMessage);
pw.flush();
skt.shutdownOutput();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.println(e);
System.out.print("Client had error sending message.\n");
JOptionPane.showMessageDialog(null, "That User is not currently online.", "ERROR!!", JOptionPane.INFORMATION_MESSAGE);
}
}
private class ClientTask implements Runnable {
private final Socket skt;
private ClientTask(Socket skt) {
this.skt = skt;
}
#Override
public void run() {
while (true) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(skt.getInputStream()));
//while (!in.ready()) {}
String incomingMessage = in.readLine();
if (incomingMessage != null) {
System.out.println("Client: Received message: " + incomingMessage); // Read one line and output it
message = incomingMessage;
}
//skt.shutdownInput();
//in.close();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.print("Client had error receiving message.\n");
}
}
}
}
}
Streams cannot be re-wrapped. Once assigned to a wrapper, they must use that wrapper for the entire life-cycle of the stream. You also shouldn't close a stream until you are done using it, which in this case isn't until your client and server are done communicating.
In your current code, there are a few times where you re-initialize streams:
while (true) {
try {
//Each loop, this reader will attempt to re-wrap the input stream
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String incomingMessage = br.readLine();
if (incomingMessage != null) {
System.out.println("Server: Received message: " + incomingMessage);
processMessage(incomingMessage);
}
//don't close your stream and socket so early!
br.close();
skt.close();
} catch (Exception e) {
//...
}
You get the idea; you can use this knowledge to find the stream problems in your client code as well.
With that said, servers are the middle-man between multiple clients. If you want to be able to type in the server's console to send a message to clients, it shouldn't go to only 1 client (unless you had a system that allowed you to specify a name). You need to store every connection in some kind of collection so when you type in the server's console, it goes to every client that's connected. This also helps when a client wants to send a message to every other client (global message). The server's main thread is primarily for accepting clients; I created another thread to allow you to type in the console.
As for your streams, you should create them whenever you start the ClientTask, both server side and client side:
public class Server {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private Set<User> users = new HashSet<>();
private boolean running;
private int port;
public Server(int port) {
this.port = port;
}
public void start() {
running = true;
Runnable acceptor = () -> {
try(ServerSocket ss = new ServerSocket(port)) {
while(running) {
User client = new User(ss.accept());
users.add(client);
executor.execute(client);
}
} catch(IOException e) {
//if a server is already running on this port;
//if the port is not open;
e.printStackTrace();
}
};
Runnable userInputReader = () -> {
try(Scanner scanner = new Scanner(System.in)) {
while(running) {
String input = scanner.nextLine();
for(User user : users) {
user.send(input);
}
}
} catch(IOException e) {
//problem sending data;
e.printStackTrace();
}
};
Thread acceptorThread = new Thread(acceptor);
Thread userThread = new Thread(userInputReader);
acceptorThread.start();
userThread.start();
}
public void stop() {
running = false;
}
public static void main(String[] args) {
new Server(15180).start();
System.out.println("Server started!");
}
}
In the run() method is where the streams should be wrapped.
class User implements Runnable {
private Socket socket;
private boolean connected;
private DataOutputStream out; //so we can access from the #send(String) method
public User(Socket socket) {
this.socket = socket;
}
public void run() {
connected = true;
try(DataInputStream in = new DataInputStream(socket.getInputStream())) {
out = new DataOutputStream(socket.getOutputStream());
while(connected) {
String data = in.readUTF();
System.out.println("From client: "+data);
//send to all clients
}
} catch(IOException e) {
//if there's a problem initializing streams;
//if socket closes while attempting to read from it;
e.printStackTrace();
}
}
public void send(String message) throws IOException {
if(connected) {
out.writeUTF(message);
out.flush();
}
}
}
It's pretty much the same idea with the client:
1. Connect to Server
2. Create "communication" thread
3. Create "user input" thread (to receive input from console)
4. Start threads
public class Client {
private final String host;
private final int port;
private boolean connected;
private Socket socket;
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws IOException {
connected = true;
socket = new Socket(host, port);
Runnable serverInputReader = () -> {
try (DataInputStream in = new DataInputStream(socket.getInputStream())) {
while (connected) {
String data = in.readUTF();
System.out.println(data);
}
} catch (IOException e) {
// problem connecting to server; problem wrapping stream; problem receiving data from server;
e.printStackTrace();
}
};
Runnable userInputReader = () -> {
try (DataOutputStream out = new DataOutputStream(socket.getOutputStream());
Scanner scanner = new Scanner(System.in)) {
while (connected) {
String input = scanner.nextLine();
out.writeUTF(input);
}
} catch (IOException e) {
//problem wrapping stream; problem sending data;
e.printStackTrace();
}
};
Thread communicateThread = new Thread(serverInputReader);
Thread userThread = new Thread(userInputReader);
communicateThread.start();
userThread.start();
}
public static void main(String[] args) throws IOException {
new Client("localhost", 15180).start();
}
}
There are a few things I used in the code above that you may not be familiar with. They help simplify the syntax for your code:
Lambda Expressions - Prevents the need to create an anonymous class (or subclass) to declare a method
Try-With-Resources - Closes the resources specified automatically once the try block as ended
EDIT
When a user connects, you should store their connection by name or id. That way, you can send data to specific users. Even if your client is running on the same machine as the server, it's still the same idea: client connects to server, server sends message to client based on name or id:
while(running) {
User client = new User(ss.accept());
users.add(client); //add to set
executor.execute(client);
}
Right now, you are simply adding users to a Set. There is currently no way to grab a specific value from this set. What you need to do is give it some kind of "key". To give you an idea, here's an old algorithm I used to use. I have an array full of empty slots. When someone connects, I look for the first empty slot. Once an empty slot is found, I pass the user the index of the array it's being stored at (that will be the user's id), then store the user in the array at the specified index. When you need to send a message to someone, you can use the id to access that specific array index, grab the user you want and send a message:
class Server {
private int maxConnections = 10;
private ExecutorService executor = Executors.newFixedThreadPool(maxConnections);
private User[] users = new User[maxConnections];
//...
while(running) {
Socket socket = ss.accept();
for(int i = 0; i < users.length; i++) {
if(users[i] == null) {
users[i] = new User(socket, i);
executor.execute(users[i]);
break;
}
}
}
//...
public static void sendGlobalMessage(String message) throws IOException {
for(User user : users)
if(user != null)
user.send(message);
}
public static void sendPrivateMessage(String message, int id) {
User user = users[id];
if(user != null) {
user.send(message);
}
}
}
class User {
private Socket socket;
private int id;
private DataOutputStream out;
public User(Socket socket, int id) {
this.socket = socket;
this.id = id;
}
public void send(String message) throws IOException {
out.writeUTF(message);
out.flush();
}
public void run() {
DataInputStream in;
//wrap in and out streams
while(connected) {
String data = in.readUTF();
//Server.sendGlobalMessage(data);
//Server.sendPrivateMessage(data, ...);
sendMessage(data); //sends message back to client
}
}
}
Ok so I have constructed a working example of a client and server which can accept multiple client connections. My problem is is that I cannot connect a client which is not running the same internet connection as the one the server is being hosted on. Is this possible using server sockets?
Here is the code for my server:
import java.io.IOException;
import java.net.*;
public class MultipleSocketServer {
public static Socket connection;
public static String name = "Tyler's Server";
public static int limit = 2;
public static Thread[] clients = new Thread[limit];
public static int current = 0;
public static int port = 25565;
public static String[] connected = new String[limit];
public static ServerSocket socket;
public static void main(String[] args) {
System.out.println("Server starting...");
for(int i = 0; i < limit; i++) {
connected[i] = "";
}
try {
ServerSocket socket = new ServerSocket(port);
while(true) {
Socket connection = socket.accept();
String ip = connection.getRemoteSocketAddress().toString().substring(1, 13);
loop:
for(int i = 0; i < connected.length; i++) {
if(connected[0].equals(ip) || connected[1].equals(ip)) {
break loop;
}else if(!connected[i].equals(ip)) {
connected[i] = ip;
MultiServer_Client client = new MultiServer_Client(connection, i);
Thread run = new Thread(client);
run.start();
break loop;
}
}
}
} catch (IOException e1) {
System.out.println("Could not bind server on: " + port);
System.exit(-1);
}
}
}
And here is the rest:
import java.io.*;
import java.net.Socket;
public class MultiServer_Client implements Runnable {
public String time;
public Socket client;
public StringBuffer process = new StringBuffer();
public BufferedInputStream inputStream;
public InputStreamReader reader;
public BufferedOutputStream outputStream;
public OutputStreamWriter writer;
public StringVis check = new StringVis("");
public StringChangeListener checkListener = new StringChangeListener() {
public void textChanged(StringChangeEvent e) {
System.out.println("Changed");
write("Server recieved message...");
}
};
public boolean connected = true;
public int ID;
public MultiServer_Client(Socket connection, int i) {
client = connection;
ID = i;
try {
//declare text input/output
inputStream = new BufferedInputStream(client.getInputStream());
reader = new InputStreamReader(inputStream);
outputStream = new BufferedOutputStream(client.getOutputStream());
writer = new OutputStreamWriter(outputStream, "US-ASCII");
} catch (IOException e) {
System.out.println("IOException: " + e);
}
System.out.println(MultipleSocketServer.connected[ID] + " connected...");
write("Connected to " + MultipleSocketServer.name);
}
public void run() {
while(connected) {
read();
}
System.out.println("Disconnecting client...");
}
public void write(String authen) {
try {
time = new java.util.Date().toString();
String message = time + ": " + authen + (char) 13;
writer.write(message);
writer.flush();
} catch (IOException e) {
connected = false;
MultipleSocketServer.connected[ID] = "";
}
}
public void read() {
//read from client
int character;
process = new StringBuffer();
try {
while ((character = reader.read()) != 13) {
process.append((char) character);
}
check.setText(process.toString());
process.delete(0, process.length());
} catch (IOException e) {
connected = false;
MultipleSocketServer.connected[ID] = "";
}
}
}
Here's the client code:
import java.net.*;
import java.util.Scanner;
import java.io.*;
public class SocketClient {
public static String host = "69.182.134.79";
public static int port = 25565;
public static void main(String [] args) {
StringBuffer imports = new StringBuffer();
String time;
System.out.println("Client starting...");
try {
//establish client
InetAddress address = InetAddress.getByName(host);
Socket connection = new Socket(address, port);
BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");
while(true) {
Scanner scan = new Scanner(System.in);
String message = scan.nextLine();
//write to server
time = new java.util.Date().toString();
String process = host + ":" + port + " sent data at " + time + ": " + message + (char) 13;
osw.write(process);
osw.flush();
//read from server
int c;
while ((c = isr.read()) != 13) {
imports.append((char) c);
}
System.out.println(imports);
imports.replace(0, imports.length(), "");
if(message.equals("--EXIT")) {
connection.close();
}
}
} catch (UnknownHostException e) {
System.out.println("UnknownHostException: " + e);
} catch (IOException e) {
System.out.println("IOExcepion: " + e);
}
}
}
Change
MultiServer_Client client = new MultiServer_Client(connection, i);
to
MultiServer_Client client = new MultiServer_Client(new Socket([Server IP], port), i);
This should work.
hi to all i have created a server class with threadpool as shown below and it makes use of workerRunnable class . the problem i am facing with this code is when i am trying to send files from two cliensts at same time to this server,it is giving me a irregular response (in the sense first thread wil run till next client request is made as soon as the request cums from the second client it stops the first one and starts working on the second req and second one response is sent to both the clients sockets instead of sending their respective response)...pls can any one tell me where i am going wrong?????
package com.tel.snmp;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPooledServer implements Runnable{
protected int serverPort = 4444;//hk
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread= null;
public BlockingQueue q = new ArrayBlockingQueue(20);
public static int clientconnection = 0;
ThreadPoolExecutor threadpool = new ThreadPoolExecutor(4,10,20,TimeUnit.SECONDS,q);
public ThreadPooledServer(int port){
this.serverPort = port; // wrk2
}
public void run()
{
synchronized(this)
{
this.runningThread = Thread.currentThread();
}
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try
{
//System.out.println("the value of client connection BEFORE is"+clientconnection);
clientSocket = this.serverSocket.accept();
clientconnection++;
System.out.println("the value of client connection is"+clientconnection);
} catch (IOException e)
{
if(isStopped())
{
System.out.println("Server Stopped.") ;
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
this.threadpool.execute(new WorkerRunnable(clientSocket,"Thread pooled server"));
}
System.out.println("Server Stopped.") ;
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop(){
this.isStopped = true;
try {
this.serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort); //wrkr2
}
catch (IOException e) {
throw new RuntimeException("Cannot open port serverPort"+serverPort, e);
}
}
}
-----------------------------Worker Runnable class-----------------------------
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.tel.snmp;
/**
*
* #author harikrishnadv
*/
import com.tel.common.ProtocolSelector;
import java.io.*;
import java.net.*;
/*public class WorkerRunnable implements Runnable{
protected Socket clientSocket = null;
protected String serverText = null;
public WorkerRunnable(Socket clientSocket, String serverText) {
this.clientSocket = clientSocket;
this.serverText = serverText;
}
public void run() {
try {
InputStream input = clientSocket.getInputStream();
OutputStream output = clientSocket.getOutputStream();
long time = System.currentTimeMillis();
output.write(("HTTP/1.1 200 OK\n\nWorkerRunnable: " +
this.serverText + " - " +
time +
"").getBytes());
output.close();
input.close();
System.out.println("Request processed: " + time);
} catch (IOException e) {
//report exception somewhere.
e.printStackTrace();
}
}
}
*/
public class WorkerRunnable implements Runnable
{
FileInputStream fis;
FileOutputStream fos;
BufferedInputStream bis;
BufferedOutputStream bos;
String filename="clientfile";
String fname=null;
//Socket soc;
int flag=0;
int ch;
//static int count=0;// new
protected Socket clientSocket = null;
protected String serverText = null;
public WorkerRunnable(Socket clientSocket, String serverText) {
this.clientSocket = clientSocket;
this.serverText = serverText;
}
public synchronized void run() {
try {
receiveFile();
/*try{
this.wait();
}
catch(InterruptedException i)
{
}*/
if(flag==1)
{
System.out.println("**********************************************************************************************************************************");
sendFile();
}
closeAll();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** Method to send the response file to the client */
public void sendFile() throws IOException {
// SENDING A FILE
//String sendfile=EMS.fileprocessname+EMS.clientcount+".xml";
String sendfile=EM.fileprocessname;//+EM.clientcount;
System.out.println("filename that has been sending to client is"+sendfile);
bos = new BufferedOutputStream(clientSocket.getOutputStream());
//fis = new FileInputStream("C://outputs.xml");
fis = new FileInputStream(sendfile);
while ((ch = fis.read()) != -1) {
bos.write(ch);
bos.flush();
}
bos.write(-1);
bos.flush();
System.out.println("File Sent to :: " + clientSocket);
fis.close();
}
/** Method to receive input file from client */
public void receiveFile() throws IOException {
// RECEIVING A FILE
fname="C://"+filename+ThreadPooledServer.clientconnection+".xml";
bis = new BufferedInputStream(clientSocket.getInputStream());
//fos = new FileOutputStream("C://client.xml");
fos = new FileOutputStream(fname);
while ((ch = bis.read()) != 255) {
fos.write(ch);
fos.flush();
}
System.out.println("File Received from :: " +clientSocket);
fos.close();
if(flag==0){
ProtocolSelector m=new ProtocolSelector();
//m.xmldecider("C://client.xml");
m.xmldecider(fname);
flag=1;
}
}
public void closeAll() throws IOException {
bis.close();
bos.close();
}
}
i wil be thankful for ur valuable reply's
Your clientconnection field is static but is then accessed from your WorkerRunnable receiveFile() method. By the time the receiveFile() method executes there is no guarantee that the value of clientconnection is still correct - another client might have come along and incremented it.
Try changing your WorkerRunnable constructor to take the clientconnection as an argument e.g.
Change:
this.threadpool.execute(new WorkerRunnable(clientSocket,
"Thread pooled server"));
to:
this.threadpool.execute(new WorkerRunnable(clientSocket, clientconnection,
"Thread pooled server"));
Add a clientconnection field to your WorkerRunnable and then change this line:
fname="C://"+filename+ThreadPooledServer.clientconnection+".xml";
to:
fname="C://"+filename+clientconnection+".xml";