Alright, so I've coded what is going to be a simple communication program using a server, really as a test more than anything else, so I know it's missing a lot, but with the following Client class:
public class Client {
private ObjectInputStream in;
private ObjectOutputStream out;
private Socket socket;
private String server;
private int port;
public Client(String ip, int p){
port = p;
server = ip;
}
public boolean start(){
try{
socket = new Socket(server, port);
}catch(Exception e){
System.out.println("Exception");
e.printStackTrace();
return false;
}
try{
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("All declared");
}catch(Exception e){
System.out.println("Exception");
e.printStackTrace();
return false;}
new LThread().start();
return true;
}
private void sendMessage(Message msg){
try{
out.writeObject(msg);
}catch(Exception e){}
}
public static void main(String[] args){
int portNum = 1500;
String servers = "localhost";
Client client = new Client(servers, portNum);
System.out.println("Client started");
if(!client.start()){
System.out.println("Didn't work");
return;
}
System.out.println("Client started again");
Scanner scan = new Scanner(System.in);
while(true){
String i = scan.nextLine();
client.sendMessage(new Message(2, i));
}
}
class LThread extends Thread{
public void run(){
System.out.println("Lthread running");
while(true){
try{
String message = (String)in.readObject();
System.out.println(message);
}catch(Exception e){
e.printStackTrace();}
}
}
}
}
The program simply stops when it reaches the point at which it declares its ObjectInput and Output Streams. The program doesn't exit, it doesn't appear to enter the catch block, and I cannot, at all, figure out what on earth could possibly be causing it. The line "All declared." is never printed, but anything before it is printed. Could anyone please tell me why my program just ceases to function at this point without displaying any errors?
EDIT: I figure that there could be an error somewhere in my Server file, so here's the class:
public class Server {
private static int uid;
private ArrayList<ClientThread> clients;
private int port;
private boolean cont;
public Server(int p){
port = p;
clients = new ArrayList<ClientThread>();
}
public void start(){
System.out.println("Started");
cont = true;
try{
ServerSocket srvr = new ServerSocket(port);
System.out.println("Declared socket");
while(cont){
Socket sk = srvr.accept();
System.out.println("Socket accepted");
if(!cont)break;
ClientThread t = new ClientThread(sk);
clients.add(t);
t.start();
}
try{
srvr.close();
for(ClientThread t : clients){
t.in.close();
t.out.close();
t.socket.close();
}
}catch(Exception e){
e.printStackTrace();
}
}catch(Exception e){
e.printStackTrace();
}
}
private synchronized void broadcast(String msg){
for(int i=clients.size(); --i >= 0;){
ClientThread t= clients.get(i);
if(!t.writeMsg(msg)){
clients.remove(i);
}
}
}
public static void main(String[] args){
int portNum = 1500;
Server server = new Server(portNum);
server.start();
}
class ClientThread extends Thread{
Socket socket;
ObjectInputStream in;
ObjectOutputStream out;
String name;
int id;
Message m;
ClientThread(Socket s){
id = ++uid;
socket = s;
try{
System.out.println("Before");
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("After");
}catch(Exception e){
e.printStackTrace();}
}
public void run(){
boolean c = true;
while(c){
try{
m = (Message)in.readObject();
switch(m.getType()){
case 2:
broadcast(m.getMessage());
}
}catch (Exception e){
e.printStackTrace();}
}
}
public boolean writeMsg(String msg){
if(!socket.isConnected()){
return false;
}
try{
out.writeObject(msg);
}catch(Exception e){
e.printStackTrace();}
return true;
}
}
}
Alright, another edit. So I added those two printlns to the try statement in ClientThread's constructor, and, just like with client, it runs until I try to initialize the streams, and then it just stops. Again, no errors, no anything; it just completely stops in its tracks. I cannot figure out why on earth this happens, but if it means anything, I'm using the Eclipse IDE to run it.
I snagged on this the first time I used ObjectInputStream and ObjectOutputStream. At the root cause of your problem is within the constructor ObjectInputStream. The constructor will read from the underlying stream in an attempt to get header information such as the wire format version.
In order to prevent your client and server from infinity waiting for the other to send the information first, you should invert the order of the input and output streams, then flush the output stream explicitly. The following at the construction of the streams in the client and server will fix your problem:
out = new ObjectOutputStream(socket.getOutputStream());
out.flush();
in = new ObjectInputStream(socket.getInputStream());
Related
So I am working on socket programming project, where the client connects first to an authentication server and once the login is successful the client is then connected to the game server.
I created a basic code and hardcoded the username/password for now, but will be using a database later.
the problem I am facing is that I do not know how to transfer the client from authentication server to game server once login is successful
here is my loginServer thead that handle the login part.
public class LoginServerThread extends Thread {
private Socket socket;
public LoginServerThread(Socket socket){
this.socket = socket;
}
#Override
public void run(){
try{
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("Client Connected");
PrintWriter output = new PrintWriter(socket.getOutputStream(),true);
String echoString;
boolean unlock = false;
while (!unlock){
output.println("USERNAME: ");
echoString = input.readLine();
if(echoString.equals("exit")){
break;
} else if (echoString.equals("username")){
for(int i = 0; i < 3;){
output.println("PASSWORD: ");
echoString = input.readLine();{
if(echoString.equals("password")){
output.println("Login Successful");
unlock = true;
break;
}else{
i++;
}
}
}
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
Assume authentication and game server deploy in one jvm.When login success don't close the socket,but tranfer the socket to GameServerThread:
LoginServer just check authentication:
public class LoginServer {
private static final Logger log = LoggerFactory.getLogger(LoginServer.class);
public static void main(String[] args) throws Exception {
ServerSocket loginServer = new ServerSocket();
SocketAddress serverSocketAddress = new InetSocketAddress("localhost", 5230);
loginServer.bind(serverSocketAddress);
for (; ; ) {
Socket socket = loginServer.accept();
if (loginCHeck(socket)) {
// transfer to game server thread to process
log.info("socket check begin create thread to process");
new GameServerThread(socket).run();
} else {
// authentication failed process
}
}
}
public static boolean loginCHeck(Socket socket) {
// check authentication
return true;
}
}
public class GameServerThread extends Thread {
private Socket socket;
public GameServerThread(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
// do your really want to do
}
}
This method has the following shortcoming:
One socket need one thread to process,when have two many client the server's thread may run out. In order to overcome this,you can use Java NIO API to do the same work.
I've been trying to make the code below to have multiple clients communicate with the same server.
Currently, it works one client at a time with the server but it seems to be that when the second client opens, code stops at new ObjectInputStream(connection.getInputStream()); in the Class 3 (client) - see below.
I've tried making the inputstream object transient to be shared in different threads but it didn't work, nor with making runClient method synchronized.
If I were to implement Serializable in the client class using serialVersionUID, how can I make multithreading work with the same server or is there any better way..?
Class 1 - server main
public class EchoServer {
private ServerSocket server;
private int portNum;
public static final int DEFAULT_PORT = 8081;
public EchoServer(int portNum) {
this.portNum = portNum;
}
public void runServer() {
System.out.println("Echo Server started...");
try {
server = new ServerSocket(portNum);
Socket connection = server.accept();
new Thread(new ClientHandler(connection)).run();
} catch(IOException ex) {
System.err.println("Error encountered! Port is likely already in use! Exiting program...");
ex.printStackTrace();
}
}
public static void main(String[] args) {
if (args.length > 0) {
(new EchoServer(Integer.parseInt(args[0]))).runServer();
} else {
(new EchoServer(DEFAULT_PORT)).runServer();
}
}
}
Class 2
public class ClientHandler implements Runnable {
private ObjectOutputStream output;
private ObjectInputStream input;
private String message;
/** Integer to hold the message number. */
private int messagenum;
private Socket connection;
public ClientHandler(Socket connection) {
this.connection = connection;
}
#Override
public void run() {
do{
handleRequest();
} while (true);
}
public void handleRequest() {
try {
output = new ObjectOutputStream(this.connection.getOutputStream());
input = new ObjectInputStream(this.connection.getInputStream());
do {
try {
message = (String) input.readObject();
System.out.println(messagenum +" Output> " +message);
} catch (EOFException | SocketException e) {
message = null;
}
if (message != null) {
output.writeObject(messagenum +" FromServer> " +message);
output.flush();
++messagenum;
}
} while (message != null);
input.close();
output.close();
this.connection.close();
} catch (IOException | ClassNotFoundException ex) {
System.err.println("Error encountered! Exiting program...");
ex.printStackTrace();
}
}
}
Class 3 - client main
public class EchoClient implements Serializable {
private static final long serialVersionUID = 1L;
private Socket connection;
private ObjectOutputStream output;
private transient ObjectInputStream input;
private String message = "";
private static String serverName;
public static final String DEFAULT_SERVER_NAME = "localhost";
private static int portNum;
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
public EchoClient(String serverName, int portNum) {
this.serverName = serverName;
this.portNum = portNum;
}
public synchronized void runClient() {
try {
connection = new Socket(InetAddress.getByName(serverName), portNum);
output = new ObjectOutputStream(connection.getOutputStream());
input = new ObjectInputStream(connection.getInputStream());
do {
System.out.print("Input> ");
message = keyboard.readLine();
if (message != null){
output.writeObject(message);
output.flush();
message = (String) input.readObject();
System.out.println(message);
}
} while (message != null);
input.close();
output.close();
connection.close();
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (ClassNotFoundException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
switch (args.length) {
case 2:
(new EchoClient(args[0], Integer.parseInt(args[1]))).runClient();
break;
case 1:
(new EchoClient(DEFAULT_SERVER_NAME, Integer.parseInt(args[0]))).runClient();
break;
default:
(new EchoClient(DEFAULT_SERVER_NAME, server.EchoServer.DEFAULT_PORT)).runClient();
}
}
}
Call server.accept() in the loop to accept multiple client connections as mentioned in the other answers. Start a new thread with the Thread.start method instead of Thread.run- What's the difference between Thread start() and Runnable run().
volatile boolean isRunning = true;
public void runServer() {
System.out.println("Echo Server started...");
try {
server = new ServerSocket(portNum);
while(isRunning) {
Socket connection = server.accept();
new Thread(new ClientHandler(connection)).start();
}
} catch(IOException ex) {
System.err.println("Error encountered! Port is likely already in use! Exiting program...");
ex.printStackTrace();
}
}
run server needs to wait for connections in a loop otherwise it will connect once and that is it. It needs to close its connections too. Clean up its threads. that's just in server main. I'm pretty sure this is a duplicate. So keep on researching
As said by efekctive, you need your server.accept() in a loop, else it will accept the first client and exit the program. So put these two lines in runServer() in a loop like this:
boolean isRunning = true;
while(isRunning){
Socket connection = server.accept();
new Thread(new ClientHandler(connection)).run();
}
I have a multithreaded server and can have multiple clients at once connected. These threads call a class that has multiple linked lists and the clients can add and remove information to it.
For example
This is the server
public class ShareServer {
public static void main(String[] args) throws IOException {
//if (args.length != 1) {
//System.err.println("Usage: java ShareServer <port number>");
//System.exit(1);
//}
//int portNumber = 2000;
boolean listening = true;
try (ServerSocket serverSocket = new ServerSocket(2000)) {
while (listening) {
new ClientThread(serverSocket.accept()).start();
}
} catch (IOException e) {
System.err.println("Could not listen on port " + 2000);
System.exit(-1);
}
}
}
This is the clientsthread
public class ClientThread extends Thread {
private Socket socket = null;
private ObjectOutputStream out;
private ObjectInputStream in;
FindMatch look= new FindMatch();
string fruit;
public ClientThread(Socket socket) {
super("ClientThread");
this.socket = socket;
}
public void run() {
try {
out = new ObjectOutputStream (socket.getOutputStream());
in = new ObjectInputStream (socket.getInputStream());
int count=0;
boolean flag = false;
try{
fruit = (Double)in.readObject();
flag = look.checkForMatch(string fruit);
if(flag==true)
sendMessage("found a match")
}
catch(ClassNotFoundException classnot){
System.err.println("Data received in unknown format");
}
socket.close();
}catch (IOException e) {
e.printStackTrace();
}
}
void sendMessage(string fuit)
{
try{
out.writeObject(msg);
out.flush();
System.out.println("server>" + msg);
}
catch(IOException ioException){
ioException.printStackTrace();
}
}
}
public LinkedList<String> fruitEntries = new LinkedList<Integer>();
public LinkedList<?> clientID = new LinkedList <?>();
this is the code that it calls
boolean checkFormatch(string fruit){
for(int i = 0; i< fruitEntries.length();i++){
if(fruit == fruitEntries.get(i)){
tell client at clientID(i);
fruitEntries.remove(i);
clientID.remove(i);
retutn true;
}
}
}
This code is far from perfect I just threw this together. the general idea is right though. I will have maybe 6 linked lists of info in mine.
I'm not sure how to keep track of what thread a client has either so I would appreciate help with that.
Personally I would use RMI instead of sockets. RMI handles all the messy listening threading etc.
Consider using one of the java.util.concurrent classes -- ConcurrentSkipListMap
ConcurrentHashMap
Also, when you compare Strings you need fruit.compareTo(...) which is rather slow so creating a hash is probably better.
I've got a simple client and server that I've written to teach myself a bit of networking. The way it's set up is I've got a main server class which will deal with creating/destroying sockets, and the ConnectionThread class that represents each connection (each of which is given its own thread). The client is super simple.
The problem lies in creating the input/output streams in the ConnectionThread class. I'm not sure exactly what the problem is, but it crashes when the simple test client tries to connect, giving me this:
~~MMO Server Alpha .1~~
Constructed Server
Server Initialized, preparing to start...
Server preparing to check if it should be listening...
Server should be listening, continuing as planned.
ServerSocket passed to ConnectionThread: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=6969]
Constructing ConnectionThread.
Socket[addr=/10.0.1.10,port=55332,localport=6969]
ConnectionThread constructed.
Exception in thread "main" java.lang.NullPointerException
at ConnectionThread.init(ConnectionThread.java:65)
at Server.listen(Server.java:98)
at Server.start(Server.java:62)
at Server.main(Server.java:122)
ConnectionThread added to queue.
Establishing in and out streams:
null
Here are the classes (amended for brevity):
public class Server {
int PORT;
boolean shouldListen;
ArrayList<ConnectionThread> connections = new ArrayList<ConnectionThread>();
ServerSocket serverSocket;
public Server() {
try {
PORT = 6969;
shouldListen = true;
serverSocket = new ServerSocket(PORT);
}
catch (IOException e) {
System.out.println("Error in server constructor.");
System.exit(1);
}
}
public void start() {
System.out.println("Server preparing to check if it should be listening...");
listen();
System.out.println("Server finished listening.");
}
public void listen() {
while (shouldListen) {
ConnectionThread conn = null;
System.out.println("Server should be listening, continuing as planned.");
try {
conn = new ConnectionThread(serverSocket);
}
catch (Exception e) {
System.out.println("____Error constructing ConnectionThread. Could there be another instance of the server running?");
System.exit(1);
}
System.out.println("ConnectionThread constructed.");
connections.add(conn);
System.out.println("ConnectionThread added to queue.");
conn.init();
System.out.println("Finished ConnectionThread initialization, verifying...");
if (conn.isInitialized) {
System.out.println("ConnectionThread Initialized, preparing to start new thread.");
(new Thread(conn)).start();
}
}
}
public static void main(String[] args) {
System.out.println("~~MMO Server Alpha .1~~");
Server server = new Server();
System.out.println("Constructed Server");
server.init();
System.out.println("Server Initialized, preparing to start...");
server.start();
}
}
Here's the ConnectionThread class:
public class ConnectionThread implements Runnable {
boolean shouldBeListening = true;
boolean isThereAnUnsentOutgoingMessage = false;
String outgoingMessage = "OUTGOING UNINITIALIZED";
boolean IsThereAnUnsentIncomingMessage = false;
String incomingMessage = "INCOMING UNITIALIZED";
boolean isInitialized = false;
PrintWriter out;
BufferedReader in;
String currentInputMessage = "Test Input Message from the Server ConnectionThread";
String previousInputMessage = null;
Socket socket;
public ConnectionThread(ServerSocket s) {
System.out.println("ServerSocket passed to ConnectionThread: " + s);
/*
* The purpose of the constructor is to establish a socket
* as soon as possible. All transmissions/logic/anything else
* should happen in init() and/or run().
*/
System.out.println("Constructing ConnectionThread.");
try {
Socket socket = s.accept();
System.out.println(socket);
}
catch (IOException e) {
System.out.println("Error in ConnectionThread constructor");
System.exit(1);
}
}
public void init() {
/*
* Everything should be set up here before run is called.
* Once init is finished, run() should be set to begin work.
* This is to ensure each packet is efficiently processed.
*/
try {
System.out.println("Establishing in and out streams:");
System.out.println(socket);
out = new PrintWriter(socket.getOutputStream(), true);
System.out.println("ConnectionThread: Output Stream (PrintWriter) Established");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("ConnectionThread: InputStream (BufferedReader) Established");
}
catch (IOException e) {
System.out.println("Error in ConnectionThread method Init.");
System.exit(1);
}
isInitialized = true;
}
And optionally, here's the test client:
public class TestClient {
static PrintWriter out;
BufferedReader in;
public final int PORT = 6969;
Socket socket = null;
InetAddress host = null;
public TestClient() {
out = null;
in = null;
socket = null;
host = null;
}
public void connectToServer() {
System.out.println("Connecting to server...");
try {
host = InetAddress.getLocalHost();
socket = new Socket(host.getHostName(), PORT);
}
catch (Exception e) {
System.out.println("Error establishing host/socket");
System.exit(1);
}
try {
System.out.println("Establishing I/O Streams");
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch (Exception e) {
System.out.println("Error establishing in/out streams");
System.exit(1);
}
}
public static void main(String[] args) {
System.out.println("~~TestClient Alpha .1~~");
TestClient c = new TestClient();
c.connectToServer();
System.out.println("Should be connected to server. Sending test message...");
while (true) {
System.out.println("here");
out.println("Hello there");
}
}
}
The 'socket' variable in the constructor of ConnectionThread shouldn't be local. It is shadowing the member variable.
It is customary to call accept() in the listen() loop, and pass the accepted socket to the ConnectionThread.
As EJP said, in your ConnectionThread constructor you think that you are assigning the value to the socket field, however you are actually assigning the value to the socket method variable, thus the socket field remains null, and in init() you see socket as null.
In addition to EJP answer: you did not provide ConnectionThread.run() method, but I assume you are going to use fields in, out and socket in your run() method. Since these fields are not marked as volatile or final, depending on your luck and number of core on your computer, you may also get NullPointerException at run() method.
This is because new variable value may be not propagated between caches and new thread will not see value of changed.
Explanation of this possible problem is here - The code example which can prove "volatile" declare should be used
I implemented simple server-client chat in Java. Here the source for the server:
public class Server {
final private static int PORT = 50000;
private static class Read extends Thread {
private static Socket socket;
private static String address;
public Read(Socket socket) {
this.socket = socket;
address = socket.getInetAddress().toString().substring(1);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
while (true) {
msg = in.readLine();
if (msg == null) {
in.close();
return;
}
System.out.println(address + ": " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static class Write extends Thread {
private static Socket socket;
public Write(Socket socket) {
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String msg;
while (true) {
if (socket.isClosed()) {
out.close();
return;
}
if (stdin.ready()) {
msg = stdin.readLine();
out.println(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket;
boolean listening = true;
serverSocket = new ServerSocket(PORT);
while (listening) {
Socket socket = serverSocket.accept();
String address = socket.getInetAddress().toString().substring(1);
System.out.println("Connection Established " + address);
Thread read = new Read(socket);
Thread write = new Write(socket);
read.start();
write.start();
try {
read.join();
write.join();
} catch(InterruptedException e) {
}
socket.close();
System.out.println("Connection Closed " + address);
}
serverSocket.close();
}
}
It works fine but there is a problem. For every established connection the memory continuously grows. I presume the problem is that the memory allocated for the threads is not released afterwards but I'm not quite sure. How can I fix that?
EDIT: The client program:
class Client {
final private static int PORT = 50000;
private static class Read extends Thread {
private Socket socket;
private String address;
public Read(Socket socket) {
this.socket = socket;
address = socket.getInetAddress().toString().substring(1);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
while (true) {
msg = in.readLine();
if (msg == null) {
System.out.println("Connection closed " + address);
System.exit(0);
}
System.out.println(address + ": " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static class Write extends Thread {
private Socket socket;
public Write(Socket socket) {
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
Scanner sc = new Scanner(System.in);
String msg;
while (true) {
msg = sc.nextLine();
out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
PrintWriter out;
BufferedReader in;
Scanner sc = new Scanner(System.in);
while (true) { //for the test only
Socket socket = null;
try {
socket = new Socket("78.90.68.125", PORT);
} catch(java.net.ConnectException e) {
System.out.println("Connection error: host unreachable");
System.exit(1);
}
/*
String address = socket.getInetAddress().toString().substring(1);
System.out.println("Connection established " + address);
Thread read = new Read(socket);
Thread write = new Write(socket);
read.start();
write.start();
try {
read.join();
write.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
finally {
*/
socket.close();
// }
//System.out.println("Connection closed " + address);
}
}
}
Try making
private static class Read extends Thread {
private static Socket socket;
private static String address;
and
private static class Write extends Thread {
private static Socket socket;
to non-static.
Also, I dont know how you checking for memory, but do remember that Java is garbage collected and you will see increase in memory usage initially till the time garbage collector (GC) collects it and will increase again till next GC run. So it consistently increasing without any dip for long time only then there is a memory leak else you are good to go.
I ran the above code as is and ran for around 1-2 hours and it is steady memory usage of around 54MB on Mac machine using JDK 6. I am not using JConsole that comes with jdk to see mem usage. I found NO issues.
Below is the graph as I mentioned in my ans also, you have peak and dip ..in the end when I stopped client it is flat.
Ivan,
a few things to work with Threading.
Never do this:
try {
read.join();
write.join();
} catch(InterruptedException e) {
}
Always put something into the catch clause, and be it a log.error. You have no chance to know it occurs.
Then, all streams/closings etc must go into a finally block. Otherwise you cannever be sure to close everything necessary.
YOu might want to reuse connections. Try this:
http://commons.apache.org/pool/
Can you tell us if you reach the sysout for closing connections regulary?
Basically try to create log statements every time you open a connection and every time you close it. Probably you see what you are missing.
Try putting your socket.close() inside a finally block to ensure that it runs.
But I think your code may have bigger problems in that since you are not using a connection pool, you are needlessly opening new connections.