Persistent connection not working, opens new connection on every request - java

I am trying to implement a persistent http server in java, being new in socket programming, I am unaware of the complications.
But run function of ThreadHandler class, it stucks forever and keep waiting, but at the same time if new request comes a new connection is being made instead of using the previous connection itself (while the initial connection keep waiting for request).
Please suggest the correction
here is my server code that calls ThreadHandler for threading.
Server code
package httpServer;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class Server {
static int countofconnections = 0;
public static void main(String[] args) throws IOException {
int port = 14998;
ServerSocket socketServerSocket = new ServerSocket(port);
while(true) {
Socket socketClientSocket = socketServerSocket.accept();
countofconnections++;
//Runnable handler = new TinyHttpdSocketHandler(socket);
ThreadHandler threadHandler = new ThreadHandler(socketClientSocket);
Thread socketThread = new Thread(threadHandler, "Thread for " + socketClientSocket.toString());
System.out.println(" connection count is now : " + countofconnections+ " ");
socketThread.setDaemon(true);
socketThread.start();
}
}
}
ThreadHandler code:
package httpServer;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.SocketTimeoutException;
//import java.util.ArrayList;
public class ThreadHandler implements Runnable{
Socket socketClientSocket;
//ServerSocket socketServerSocket;
ThreadHandler(Socket socketClientSocket){
this.socketClientSocket = socketClientSocket;
//this.socketServerSocket = socketServerSocket;
}
#Override
public void run(){
boolean alive = false;
try {
int count = 0;
socketClientSocket.setSoTimeout(40000);
BufferedReader inputFromClient = new BufferedReader(new InputStreamReader(socketClientSocket.getInputStream()));
DataOutputStream outputToClient = new DataOutputStream(socketClientSocket.getOutputStream());
String messegeFromClient = inputFromClient.readLine();
System.out.println(messegeFromClient);
while(messegeFromClient!=null) {
String requestString = messegeFromClient;
System.out.println("entering while loop");
//String in = inputFromClient.readLine();
while(messegeFromClient!=null && !messegeFromClient.equals("")) {
//System.out.printlnln(in);
messegeFromClient = inputFromClient.readLine();
//System.out.println(messegeFromClient);
if(messegeFromClient.startsWith("Connection:")) {
String[] connectionTimeString = messegeFromClient.split(" ");
if(connectionTimeString[1].equals("keep-alive")) {
alive = true;
//System.out.println("keep alive found");
}
}
}
count++;
System.out.println(count);
//System.out.printlnln( messegeFromClient);
String[] tokensStrings = requestString.split(" ");
if(tokensStrings[0].equals("GET")) {
String requestedFilename = tokensStrings[1];
if(requestedFilename.startsWith("/")) {
requestedFilename = requestedFilename.substring(1);
if(requestedFilename.startsWith("~")) {
requestedFilename = "/home/suman/users/"+requestedFilename.substring(1);
}
else {
requestedFilename = "/home/suman/public_html/"+requestedFilename;
}
System.out.println(requestedFilename);
}
File filetosend = new File(requestedFilename);
int filesize = (int) filetosend.length();
FileInputStream fileStream = null;
boolean fileFound = true;
try {
fileStream = new FileInputStream(requestedFilename);
} catch (Exception e) {
fileFound = false;
}
if(fileFound) {
byte[] fileinByte =new byte[filesize];
fileStream.read(fileinByte);
outputToClient.writeBytes("HTTP/1.0 200 Document Follows\r\n");
outputToClient.writeBytes("Content-Length: "+filesize+"\r\n\r\n");
outputToClient.write(fileinByte, 0, filesize);
}
else {
outputToClient.writeBytes("HTTP/1.0 404 Document NOT FOUND\r\n\r\n");
outputToClient.writeBytes("404 document not found");
}
outputToClient.flush();
if(alive) {
socketClientSocket.setKeepAlive(true);
socketClientSocket.setSoTimeout(100000);
}
else {
socketClientSocket.close();
System.out.println("closing socket");
break;
}
//socketClientSocket.setSoTimeout(5000);
}
System.out.println("waiting");
messegeFromClient=inputFromClient.readLine();
while( messegeFromClient == null ) {
//this code should be skipped when a new request is made since message from from client will no longer be null in that case
messegeFromClient=inputFromClient.readLine();
}
if(messegeFromClient==null) {
System.out.println("messege is null... I don't think it would be ever executed.");
}
}
socketClientSocket.close();
System.out.println("closing socket 2");
} catch ( SocketTimeoutException e) {
try {
socketClientSocket.close();
System.out.println("socket closed");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (IOException ie) {
ie.printStackTrace();
}
}
}

Related

How can I make my server recognize more than 1 user's login info in java?

Now I do realize there are lots of the same question but even after reading the answers I seem not to undertsand. So here is the code and I'll explain the problem.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server implements Runnable {
String firstName;
String lastName;
String password;
private ArrayList<ConnectionHandler> connections;
private ServerSocket server;
private boolean done;
private ExecutorService pool;
public Server() {
connections = new ArrayList<>();
done = false;
}
#Override
public void run() {
try {
server = new ServerSocket(9999);
pool = Executors.newCachedThreadPool();
while (!done) {
Socket client = server.accept();
ConnectionHandler handler = new ConnectionHandler((client));
connections.add(handler);
pool.execute(handler);
}
} catch (Exception e) {
shutdown();
}
}
public void shutdown() {
try {
done = true;
pool.shutdown();
if (!server.isClosed()) {
server.close();
}
for (ConnectionHandler ch : connections) {
ch.shutdown();
}
} catch (IOException e) {
// ignore
}
}
class ConnectionHandler implements Runnable {
private Socket client;
private BufferedReader in;
private PrintWriter out;
public void broadcast(String message) {
for (ConnectionHandler ch : connections) {
if (ch != null) {
ch.sendMessage(message);
}
}
}
public ConnectionHandler(Socket client) {
this.client = client;
}
#Override
public void run() {
try {
out = new PrintWriter((client.getOutputStream()), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out.println("To register type 1,to sign in type 2");
//TODO:for loop so only answer is 1 or 2
String message = in.readLine();
switch (message) {
case "1":
out.println("In order to register please enter your first and last name then set a password.");
out.println("Enter first name:");
firstName = in.readLine();
out.println("Enter last name:");
lastName = in.readLine();
out.println("Finally please set a password.");
password = in.readLine();
//TODO: add parameters for passcode
out.println("Now please type 2 to login");
message = in.readLine();
if (message.equals("2")) {
//TODO: copy paste from line 104-x
}
case "2":
out.println("Please enter your first name:");
String messageLogInFN= in.readLine();
out.println("Please enter your last name:");
String messageLogInLN = in.readLine();
out.println("Enter your password:");
String messageLogInPass = in.readLine();
boolean adminAccount = (messageLogInFN.equals("admin") && messageLogInLN.equals("admin") && messageLogInPass.equals("admin123cat"));
if (adminAccount) {
//TODO: add admin permissions
}
boolean Authentication = ((messageLogInFN.equals(firstName) && messageLogInLN.equals(lastName) && messageLogInPass.equals(password)));
if (Authentication) {
out.println("Welcome " + firstName + " " + lastName + "!");
System.out.println(firstName + " " + lastName + " has logged in." );
} else
out.println("Your name or password incorrect!");
}
} catch (IOException e) {
shutdown();
}
}
public void sendMessage(String message) {
out.println(message);
}
public void shutdown() {
try {
in.close();
out.close();
if (!client.isClosed()) {
client.close();
}
} catch (IOException e) {
//ignore
}
}
}
public static void main(String[] args) {
Server server = new Server();
server.run();
}
So I am learning java and saw a tutorial on youtube for a chat room, I programed it following the tutorial, and then I wanted to have a chat room with accounts so I got to coding. Now here is the thing even though I am able to have several devices connected to the server when 2 accounts register the server forgets the first one so there can only be 1 account at the same time. What I am trying to do is have an account system where everyone has their own account that they log in with their first name, last name and passwords. But it doesnt seem to work. How can I make it so that the server doesn't forget all accounts except for the last one that registered?
Edit: Here is the client code if it helps.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client implements Runnable {
private boolean done;
private Socket client;
private BufferedReader in;
private PrintWriter out;
#Override
public void run() {
try {
client = new Socket("127.0.0.1", 9999);
out = new PrintWriter((client.getOutputStream()), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
InputHandler inHandler = new InputHandler();
Thread t = new Thread(inHandler);
t.start();
String inMessage;
while ((inMessage = in.readLine()) != null) {
System.out.println(inMessage);
}
} catch (IOException e) {
shutdown();
}
}
public void shutdown() {
done = true;
try {
in.close();
out.close();
if(!client.isClosed()) {
client.close();
}
} catch (IOException e) {
//ignore
}
}
class InputHandler implements Runnable {
#Override
public void run() {
try {
BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in));
while (!done) {
String message = inReader.readLine();
if(message.equals("/quit")) {
out.println(message);
inReader.close();
shutdown();
} else {
out.println(message);
}
}
} catch (IOException e) {
shutdown();
}
}
}
public static void main(String[] args) {
Client client = new Client();
client.run();
}
}
Also as I said most of this isnt my code and I followed a yt tutorial.

Why do I sometimes get java.net.SocketException: Socket closed on multithreaded Server

I am trying to write a multi-threaded server program with 2 servers.I am testing with 2 clients.Sometimes depending on a md5 hashcode a client connected to a server has to disconnect from said server and connect to the other one.Sometimes this happens without any problems and sometimes I get java.net.SocketException: Socket closed.Here s the code
Broker class(Server):
import java.io.IOException;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.util.ArrayList;
import java.util.List;
public class Broker extends Node implements Runnable {
private static List<Publisher> registeredpublishers = new ArrayList<Publisher>();
private static List<Consumer> registeredConsumers = new ArrayList<Consumer>();
public static List<Consumer> GetConsumers(){
return registeredConsumers;
}
public String Name;
public Integer port;
public Broker(Integer port,String name){
this.port=port;
this.Name=name;
}
ServerSocket providerSocket;
Socket connection = null;
String ip="127.0.0.1";
BigInteger myKeys;
public void run(){
calculateKeys();
Node.getBrokers().add(this);
openServer();
}
void calculateKeys(){
String g =ip+ (port != null ? port.toString() : null);
MessageDigest m = null;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
m.reset();
m.update(g.getBytes());
byte[] digest = m.digest();
myKeys = new BigInteger(1,digest);
BigInteger a=new BigInteger("25");
myKeys=myKeys.mod(a);
System.out.println(myKeys);
}
void openServer()throws NullPointerException {
try {
providerSocket = new ServerSocket(this.port, 10);
while (true) {
acceptConnection();
new BrokerHandler(connection,this).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
providerSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
void acceptConnection()throws NullPointerException {
try {
connection = providerSocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("client connected.");
{
}
}
public static void main(String args[]) {
new Thread(new Broker(54319,"First")).start();
new Thread(new Broker(12320,"Second")).start();
}
}
BrokerHandler Class
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class BrokerHandler extends Thread implements Serializable {
ObjectInputStream in;
ObjectOutputStream out;
String f;
BigInteger theirKeys;
Broker broker;
Object e;
Message request;
public BrokerHandler(Socket connection,Broker broker) throws NullPointerException{
try {
in = new ObjectInputStream(connection.getInputStream());
out =new ObjectOutputStream(connection.getOutputStream());
try {
this.request=(Message)in.readObject();
this.f=request.artist;
this.e =request.entity;
this.broker=broker;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void run(){
if(this.e instanceof Consumer){
calculateMessageKeys(this.request);
checkBroker(this.broker,(Consumer) e);
}
}
public synchronized void disconnect(Socket connection){
try {
in.close();
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}finally {
try {
connection.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public void checkBroker(Broker broker,Consumer consumer) {
int intMyKeys = broker.myKeys.intValue();
int intTheirKeys = theirKeys.intValue();
if (intTheirKeys > 23) {
intTheirKeys = intTheirKeys % 23;
}
if (intTheirKeys <= intMyKeys && intTheirKeys >= intMyKeys - 11) {
consumer.Register(broker, f);
System.out.println(broker.Name + "Client Connected and Registered");
} else {
int thePort = 0;
System.out.println(broker.Name + "Client changing server");
for (Broker broker1 : Node.getBrokers()) {
int KEYS = broker1.myKeys.intValue();
if (intTheirKeys <= KEYS && intTheirKeys >= KEYS - 11) {
thePort = broker1.port;
System.out.println(thePort);
}
}
disconnect(broker.connection);
Consumer a = new Consumer(consumer.artist, thePort);
new ConsumerHandler(a).start();
}
}
public void calculateMessageKeys(Message request) {
MessageDigest m = null;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
m.reset();
m.update(f.getBytes());
byte[] digest = m.digest();
theirKeys = new BigInteger(1,digest);
BigInteger mod=new BigInteger("25");
theirKeys=theirKeys.mod(mod);
System.out.println(theirKeys);
}
}
Consumer class
import java.io.*;
import java.util.Random;
public class Consumer extends Node implements Serializable {
String artist;
Random r=new Random();
int max=12320;
int min=54319;
int port;
Message request;
public Consumer(String artist){
this.artist=artist;
this.port=new Random().nextBoolean() ? max : min;
request= new Message(artist,this.getConsumer());
}
public Consumer(String artist,int port){
this.artist=artist;
this.port=port;
request= new Message(artist,this.getConsumer());
}
public Consumer getConsumer(){
return this;
}
public void Register(Broker broker,String ArtistName){
broker.GetConsumers().add(this);
System.out.println(this.artist);
}
}
ConsumerHandle Class
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class ConsumerHandler extends Thread{
Consumer consumer;
public ConsumerHandler(Consumer consumer){
this.consumer=consumer;
}
void connect(int port) {
Socket requestSocket=null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
requestSocket = new Socket("127.0.0.1", consumer.port);
out = new ObjectOutputStream(requestSocket.getOutputStream());
in = new ObjectInputStream(requestSocket.getInputStream());
System.out.println("Message created.");
out.writeObject(consumer.request);
} catch (UnknownHostException unknownHost) {
System.err.println("You are trying to connect to an unknown host!");
} catch (IOException ioException) {
ioException.printStackTrace();
} finally {
try {
in.close();
out.close();
requestSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
public void run(){
connect(consumer.port);
}
public static void main(String args[]) {
Consumer a=new Consumer("Kevin MacLeod");
Consumer b=new Consumer("Alexander Narakada");
new ConsumerHandler(a).start();
new ConsumerHandler(b).start();
}
}
and the stack trace of when it happens:
java.net.SocketException: Socket closed
at java.base/sun.nio.ch.NioSocketImpl.ensureOpenAndConnected(NioSocketImpl.java:166)
at java.base/sun.nio.ch.NioSocketImpl.beginRead(NioSocketImpl.java:232)
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:300)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:351)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:802)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:937)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:932)
at java.base/java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2778)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:3105)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:3115)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1597)
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2410)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2304)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2142)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1646)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at BrokerHandler.<init>(BrokerHandler.java:26)
at Broker.openServer(Broker.java:59)
at Broker.run(Broker.java:34)
at java.base/java.lang.Thread.run(Thread.java:830)

Java Tor Lib : How to setup Orchid Tor Lib with Java?

I am trying to implement Orchid Tor lib with Java code; unfortunately and because the lack of documentation I am not able to make it work, this is what I did:
....................
private final static String DEFAULT_SOCKS_PORT = "9050";
TorClient torClient = new TorClient();
torClient.addInitializationListener(new TorInitializationListener() {
#Override
public void initializationProgress(String string, int i) {
System.out.println(">>> [ "+ i + "% ]: "+ string);
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void initializationCompleted() {
try {
System.out.println("Tor is ready to go!");
setSystemProperties("127.0.0.1","8118");
System.out.println("is online "+isOnline()); //isOnilne is just function return true if connected by pinging google.com
} catch (Exception e) {
e.printStackTrace();
}
}
});
torClient.enableDashboard(8118);
torClient.enableSocksListener(9050);
torClient.start();
private static void setSystemProperties(String host, String port)
{
System.setProperty("proxyHost", host);
System.setProperty("proxyPort", port);
System.setProperty("http.proxyHost", host);
System.setProperty("http.proxyPort", port);
System.setProperty("https.proxyHost", host);
System.setProperty("https.proxyPort", port);
System.setProperty("socks.proxyHost", host);
System.setProperty("socks.proxyPort", DEFAULT_SOCKS_PORT);
System.setProperty("socksProxyHost", host);
System.setProperty("socksProxyPort", DEFAULT_SOCKS_PORT);
}
This seems to work using Java8.
Dependencies: orchid-1.0.0.jar, jsoup-1.8.2.jar & commons-io-2.4.jar
package orchiddemo;
import com.subgraph.orchid.TorClient;
import com.subgraph.orchid.TorInitializationListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class OrchidDemo {
private static TorClient client;
public static void main(String[] args) {
startOrchid();
}
private static void startOrchid() {
//listen on 127.0.0.1:9150 (default)
client = new TorClient();
client.addInitializationListener(createInitalizationListner());
client.start();
client.enableSocksListener();//or client.enableSocksListener(yourPortNum);
}
private static void stopOrchid() {
client.stop();
}
public static TorInitializationListener createInitalizationListner() {
return new TorInitializationListener() {
#Override
public void initializationProgress(String message, int percent) {
System.out.println(">>> [ " + percent + "% ]: " + message);
}
#Override
public void initializationCompleted() {
System.out.println("Tor is ready to go!");
doTests();
}
};
}
private static void doTests() {
testOrchidUsingProxyObject();
testOrchidUsingSystemPropsProxy();
testOrchidUsingSocket();
}
private static void testOrchidUsingProxyObject() {
Thread thread = new Thread() {
#Override
public void run() {
try {
//Caution: Native Java DNS lookup will occur outside of the tor network.
//Monitor traffic on port 53 using tcpdump or equivalent.
URL url = new URL("https://wtfismyip.com/");
Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("localhost", 9150));
HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy);
uc.setConnectTimeout(10000);
Document document = Jsoup.parse(IOUtils.toString(uc.getInputStream()));
String result = document.select("div[id=tor").text();
System.out.println("testOrchidUsingProxyObject: " + result);
} catch (Exception ex) {
Logger.getLogger(OrchidDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
thread.start();
}
private static void testOrchidUsingSystemPropsProxy() {
Thread thread = new Thread() {
#Override
public void run() {
try {
//Caution: Native Java DNS lookup will occur outside of the tor network.
//Monitor traffic on port 53 using tcpdump or equivalent.
System.setProperty("socksProxyHost", "127.0.0.1");
System.setProperty("socksProxyPort", "9150");
Document document = Jsoup.connect("https://wtfismyip.com/").get();
String result = document.select("div[id=tor").text();
System.out.println("testOrchidUsingSystemPropsProxy: " + result);
System.setProperty("socksProxyHost", "");
System.setProperty("socksProxyPort", "");
} catch (Exception ex) {
Logger.getLogger(OrchidDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
thread.start();
}
private static void testOrchidUsingSocket() {
Thread thread = new Thread() {
#Override
public void run() {
try {
// This does not appear to leak the DNS lookup, but requires confirmation!
Socket socket = client.getSocketFactory().createSocket("www.google.com", 80);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer.println("GET /");
String line;
System.out.println("testOrchidUsingSocket: ");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
socket.close();
} catch (Exception ex) {
Logger.getLogger(OrchidDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
thread.start();
}
}
The DNS leak is a drama, but silvertunnel can help: NetAddressNameService
I'm hoping someone might know of a better way....
Cheers

Sockets - SocketException: Socket Closed - Java

I've been playing around with sockets recently, but I've come across a problem...
I'm getting a "java.net.SocketException: socket closed" exception when I receive data from the server. I haven't closed the socket anywhere, in fact, the only place I use close() is on the scanner to read text from System.in;
Here is my code:
Client:
package packets.sidedcomputer;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import packets.MessagePacket;
import packets.sender.PacketSender;
import packets.side.Side;
public class Client extends SidedComputer
{
volatile boolean finished = false;
volatile String username;
volatile Server server;
public Socket clientSocket;
public ClientReciever reciever;
public Client(Server server, String username) throws UnknownHostException, IOException
{
this.username = username;
this.server = server;
this.reciever = new ClientReciever(this);
}
public void stopClient()
{
finished = true;
}
#Override
public void run()
{
Scanner scanner = new Scanner(System.in);
reciever.start();
while(!finished)
{
try
{
this.clientSocket = new Socket("192.168.1.25", 10501);
String line;
while((line = scanner.nextLine()) != null)
{
PacketSender sender = new PacketSender();
System.out.println("Client sending message \"" + line + "\" to server");
sender.sendPacket(new MessagePacket(line, username), clientSocket);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
scanner.close();
}
#Override
public Side getSide()
{
return Side.CLIENT;
}
}
Server:
package packets.sidedcomputer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import packets.Packet;
import packets.data.PacketData;
import packets.info.ClientInfo;
import packets.reciever.PacketReciever;
import packets.sender.PacketSender;
import packets.side.Side;
public class Server extends SidedComputer
{
volatile boolean finished = false;
public ServerSocket serverSocket;
public volatile List<ClientInfo> clients = new ArrayList<ClientInfo>();
public void stopServer()
{
finished = true;
}
public Server()
{
try
{
serverSocket = new ServerSocket(10501);
}
catch (IOException e)
{
e.printStackTrace();
}
}
#Override
public void run()
{
try
{
while (!finished)
{
Socket clientSocket = serverSocket.accept();
if(clientSocket != null)
{
ClientInfo clientInfo = new ClientInfo(clientSocket);
this.clients.add(clientInfo);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String dataString;
while((dataString = in.readLine()) != null)
{
PacketReciever packetReciever = new PacketReciever();
PacketData packetData = new PacketData();
packetData.decodeInto(dataString);
Packet packet = packetReciever.recievePacket(packetData, packetData.packetID, getSide(), clientSocket.getLocalAddress().getHostAddress().toString(), clientSocket.getLocalPort() + "");
PacketSender packetSender = new PacketSender();
for (ClientInfo client : this.clients)
{
PrintWriter out = new PrintWriter(client.socket.getOutputStream(), true);
packetSender.sendPacketToClient(packet, out);
}
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
#Override
public Side getSide()
{
return Side.SERVER;
}
}
Packet Sender:
package packets.sender;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import packets.Packet;
import packets.data.PacketData;
public class PacketSender implements IPacketSender
{
#Override
public void sendPacket(Packet packet, Socket socket)
{
if(packet.getDefualtID() == 0)
{
PacketData packetData = new PacketData(packet.getDefualtID());
packet.writeData(packetData);
String data = packetData.encodeIntoString();
sendData(socket, data);
}
}
protected void sendData(Socket socket, String data)
{
try
{
try
(
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
)
{
out.println(data);
}
catch (IOException e)
{
System.err.println("Couldn't get I/O for the connection to " + socket);
System.exit(1);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void sendPacketToClient(Packet packet, PrintWriter out)
{
PacketData packetData = new PacketData(packet.getDefualtID());
packet.writeData(packetData);
String data = packetData.encodeIntoString();
out.println(data);
}
}
Client Receiver:
package packets.sidedcomputer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import packets.data.PacketData;
import packets.reciever.PacketReciever;
import packets.side.Side;
public class ClientReciever extends Thread
{
public Client client;
public ClientReciever(Client client)
{
this.client = client;
}
volatile boolean running = true;
public void stopRunning()
{
running = false;
}
#Override
public void run()
{
while(running)
{
if(client.clientSocket != null)
{
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(client.clientSocket.getInputStream()));
String line;
while((line = in.readLine()) != null)
{
PacketReciever reciever = new PacketReciever();
PacketData packetData = new PacketData();
packetData.decodeInto(line);
reciever.recievePacket(packetData, packetData.packetID, Side.CLIENT, client.clientSocket.getLocalAddress().getHostAddress().toString(), client.clientSocket.getPort() + "");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
}
Packet Receiver:
package packets.reciever;
import packets.Packet;
import packets.MessagePacket;
import packets.data.PacketData;
import packets.side.Side;
public class PacketReciever implements IPacketReciever
{
#Override
public Packet recievePacket(PacketData packetData, int id, Side side, String hostName, String port)
{
Packet packet = null;
if(id == 0)
{
packet = new MessagePacket();
packet.readData(packetData);
packet.execute(side, hostName + ":" + port);
}
return packet;
}
}
I think the problem is your try-with-resources call in the sender, which will call close() at the end of the try block and hence close the Socket. Try using a single PrintWriter across all calls to sendData().

Selector.select() does not block

Sorry, I searched around for 2 days before I had to post this question. There are similar questions, but none of them helped me.
I am trying to create a simple chat application where the client uses (non-NIO) Socket to connect to the server that listens with a NIO ServerSocketChannel. The server uses a Selector. Until the first client connects, the Selector.select() method is blocked, as expected. But after the first client connects, Selector.select() does not block and returns immediately. This causes my while loop to run continuously.
Sorry, I've pasted the entire code so that you can copy-paste it and run it. I've just started with Java, so any help/pointers will be very much appreciated. Thank you.
P.S.: Right now, the client sends serialized object (Message object) over the socket connection and the Server reads it. Since the connection is non-blocking, the serialized object is pre-fixed with the object size (in bytes) before it is sent to the server. This allows the server to read the next "x" bytes and un-serialize into a Message object. The server code is a work in progress.
CLIENT CODE----------
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
public class ChatClient {
void go(){
User u = new User();
u.setName("UserA");
try{
u.setInet(InetAddress.getLocalHost());
}catch (UnknownHostException ex){
System.out.println(ex);
return;
}
Message m = new Message();
m.setType(3);
m.setText("This is the 1st message.");
m.setFromUser(u);
try{
Socket sock = new Socket (InetAddress.getLocalHost(), 5000);
DataOutputStream dataOut = new DataOutputStream(sock.getOutputStream());
ByteArrayOutputStream byteTemp = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream (byteTemp);
objOut.writeObject(m);
objOut.flush();
objOut.close();
byte[] byteMessage = byteTemp.toByteArray();
ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(byteMessage.length);
byte[] size = new byte[4];
size = bb.array();
System.out.println("Object size = "+byteMessage.length); //370
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byteOut.write(size);
byteOut.write(byteMessage);
byte[] finalMessage = byteOut.toByteArray();
dataOut.write(finalMessage,0,finalMessage.length);
dataOut.flush();
System.out.println("Flushed out");
}catch (Exception ex){
System.out.println(ex);
}
}
public static void main (String args[]){
new CopyOfChatClient().go();
}
}
SERVER CODE ---------------
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
public class CopyOfChatServer {
Object a, b;//Dummy objects for synchronization
SocketChannel clientSock=null;
Selector selector;
SelectionKey key;
void go(){
try{
a=new Object();//Dummy objects for synchronization
b=new Object();//Dummy objects for synchronization
ServerSocketChannel serverSock = ServerSocketChannel.open();
serverSock.socket().bind(new InetSocketAddress(5000));
//Note: ServerSocketChannel is blocking, but each new connection returned by accept() will be made non-blocking (see below)
selector = Selector.open();
new Thread(new SelectorThread()).start(); //Start the SelectorThread
int i=0;
while (true){
clientSock = serverSock.accept();
if (clientSock!=null){
clientSock.configureBlocking(false); //The default client socket returned by accept() is blocking. Set it to non-blocking.
synchronized (b){
selector.wakeup();
synchronized (a){
key = clientSock.register(selector, SelectionKey.OP_READ); //register new client Socket with selector
key.attach(clientSock);
}//sync(a)
}//sync(b)
i++;
}
System.out.println("Here");
}//while(true)
}catch (Exception ex){
System.out.println(ex);
}
}
class SelectorThread implements Runnable{
Set <SelectionKey> selectedKeys;
int readyChannels;
public void run(){
while (true){
try {
synchronized(a){
System.out.println("1. Selector trying to select");
readyChannels = selector.select();//Note: select() is blocking ?? Does not block. Behaves like non-blocking
System.out.println("2. Selector has selected");
}//sync a
synchronized (b){
//just wait till registration is done in main thread
}
if (readyChannels == 0) continue; //Even if select() is blocking, this check is to handle suprious wake-ups
System.out.println("readyChannels>0");
selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()){
SelectionKey key = keyIterator.next();
keyIterator.remove();//added after the first answer to my question
if (key.isReadable()){
System.out.println("3. Got incoming data");
SocketChannel tempSock = (SocketChannel)key.attachment();
ByteBuffer bb=ByteBuffer.allocate(8000);
int bytesRead=tempSock.read(bb);
System.out.println("4. Bytes read = "+bytesRead);
if (bytesRead>4){
bb.flip();
bb.rewind();
int size = bb.getInt();
System.out.println("5. Size of object = "+size);
byte[] objIn = new byte[size];
for (int i=0;i<size;i++){
objIn[i]=bb.get();
}
bb.compact();
ByteArrayInputStream bIn= new ByteArrayInputStream(objIn);
ObjectInputStream objStream= new ObjectInputStream(bIn);
Message temp1 = (Message) objStream.readObject();
System.out.println("6. Read object back");
System.out.println(temp1.getFromUser().getName());
}
}
}
selectedKeys.clear();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main (String args[]){
new CopyOfChatServer().go();
}
}
MESSAGE Class ----
import java.io.Serializable;
public class Message implements Serializable{
private int type;
private User fromUser;
private User toUser;
private String text;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public User getFromUser() {
return fromUser;
}
public void setFromUser(User fromUser) {
this.fromUser = fromUser;
}
public User getToUser() {
return toUser;
}
public void setToUser(User toUser) {
this.toUser = toUser;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
USER CLASS --------
import java.io.Serializable;
import java.net.InetAddress;
public class User implements Serializable{
private String name;
private InetAddress inet;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public InetAddress getInet() {
return inet;
}
public void setInet(InetAddress inet) {
this.inet = inet;
}
}
You must put
keyIterator.remove()
after
keyIterator.next()
The selector doesn't remove anything from selectedKeys() itself.
NB You don't need to attach the channel to the key as an attachment. You can get it from key.channel().

Categories