Program won't continue after initializing input/output streams? - java

Before people suspect that I have no idea what I'm doing at all (and end up voting this down for no reason at all), please read this:
It connects to my server just fine! I'm getting no errors (from the client OR server), and my server is recognizing the connection. It works with my friend's client that he made, but I wanted to make my own client, and apparently I'm doing something wrong. PLEASE STAY ON TOPIC! Thanks :)
Title basically says it all. I've tested with println messages above and below the setupStream() in my Client.java run(), but only the message above the setupStream() prints. I'm not sure how I'm supposed to initialize my stream without making my program come to a halt.
Client.java
import java.io.IOException;
public class Client extends Stream implements Runnable {
public boolean running = false;
private Thread clientThread;
Frame frame;
public Client() {
super("localhost", 43594);
frame = new ClientFrame(500, 500);
start();
}
public synchronized void start() {
if(running) return;
running = true;
clientThread = new Thread(this);
clientThread.start();
}
public synchronized void stop() {
if(!running) return;
running = false;
clientThread.interrupt();
try {
clientThread.join();
} catch (InterruptedException e) {e.printStackTrace();}
}
public void run() {
try{
setupStream();
while(running) {
System.out.println("running");
}
}catch(IOException e) {
e.printStackTrace();
}finally {
try{
out.close();
in.close();
socket.close();
clientThread.join();
}catch(IOException | InterruptedException e) { e.printStackTrace(); }
}
}
public static void main(String[] args) {
new Client();
}
}
Stream.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Stream {
Socket socket;
ObjectOutputStream out;
ObjectInputStream in;
String data;
public Stream(String host, int port) {
try {
socket = new Socket(host, port);
} catch (IOException e) {
e.printStackTrace();
}
}
protected void setupStream() throws IOException {
out = new ObjectOutputStream(socket.getOutputStream());
out.flush();
in = new ObjectInputStream(socket.getInputStream());
}
}
My Server Thread:
package Server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
public class User extends Thread {
public static int users = 0;
public int ID;
public String username;
boolean online = false;
public static ArrayList<String> usernames = new ArrayList<String>();
Socket socket;
DataOutputStream out;
DataInputStream in;
String input;
public User(Socket socket) {
this.socket = socket;
}
public String decode(String input) {
String[] split = input.split(" ");
if(input.startsWith("::")) {
try {
switch(split[0].substring(2, split[0].length()).toLowerCase()) {
case "setname":
case "changename":
case "newname":
if(usernames.contains(split[1].toLowerCase())) {
out.writeUTF("This name is already taken! Please choose a different one.");
out.flush();
return null;
}
if(username == null) {
username = split[1].substring(0, 1).toUpperCase() + split[1].substring(1, split[1].length());
Server.users.put(split[1].toLowerCase(), Server.user[ID]);
usernames.add(split[1].toLowerCase());
} else {
usernames.remove(username.toLowerCase());
username = split[1].substring(0, 1).toUpperCase() + split[1].substring(1, split[1].length());
usernames.add(split[1].toLowerCase());
}
return null;
case "rank+":
return null;
case "[sm]=":
return null;
}
}catch(IOException e) { }
}
return input;
}
String timeStamp;
public void run() {
try {
out = new DataOutputStream(socket.getOutputStream());
out.flush();
in = new DataInputStream(socket.getInputStream());
while((input = in.readUTF()) != null) {
input = decode(input);
if(input != null) {
if(username != null) {
timeStamp = new SimpleDateFormat("[h:mm:ss] ").format(Calendar.getInstance().getTime());
Server.sendGlobalMessage(timeStamp + username +": "+input);
} else {
timeStamp = new SimpleDateFormat("[h:mm:ss] ").format(Calendar.getInstance().getTime());
Server.sendGlobalMessage(timeStamp + "Guest "+ID+": "+input);
}
}
}
}catch(IOException e) { e.printStackTrace(); } finally {
try{
out.close();
in.close();
socket.close();
} catch(IOException e) { e.printStackTrace(); }
}
}
}
I haven't touched the code of my Server Thread for a while, since it has always worked up until I made my new client.

I suspect that your server does not create an ObjectOutputStream, so when the client constructs its ObjectInputStream, it blocks waiting for the object stream header, which never arrives.

Related

Problem in Client and Server Architecture. Exception in thread appears

I wrote this code in java based on sockets and thread pool. The server code runs on its own but when I run the client code after running the server, an exception on the server appears. What could be causing this?
Below is the server class which conatains threads for each new client
package java_40;
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.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//Server Implementation
/**
*
* #author Abdullah
*/
public class Server implements Runnable {
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 {
while(!done){
server = new ServerSocket(9999);
pool = Executors.newCachedThreadPool();
Socket client = server.accept();
ConnectionHandler handler = new ConnectionHandler(client);
connections.add(handler);
pool.execute(handler);
}
} catch (IOException ex) {
shutdown();
}
}
public void broadcast(String message){
for(ConnectionHandler ch :connections){
if(ch !=null){
ch.sendMessage(message);
}
}
}
public void shutdown(){
try{
done=true;
if(!server.isClosed()){
server.close();
}
for(ConnectionHandler ch : connections){
ch.shutdown();
}
}catch(IOException e){
// ignore
}
}
class ConnectionHandler implements Runnable{ //handles individual client connection
private final Socket client;
private BufferedReader in;
private PrintWriter out;
private String nickname;
public ConnectionHandler(Socket client){
this.client = client;
}
#Override
public void run() {
if(client != null){
try{
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out.println("Enter nickname");
nickname =in.readLine();
System.out.println(nickname+" connected");
broadcast(nickname + " has joined the chat");
String message;
while((message = in.readLine()) !=null){
if (message.startsWith("/nick"))
{
// TODO: handle nickname
String[] messageSplit = message.split(" ", 2);
if(messageSplit.length == 2){
broadcast(nickname + " renamed themselves to " + messageSplit[1]);
System.out.println(nickname + " renamed themselves to " + messageSplit[1]);
nickname = messageSplit[1];
out.println("Successfully changed nickname to " + nickname);
}else{
out.println("No nickname provided");
}
}
else if(message.startsWith("/quit")){
broadcast(nickname + " has left the chat");
// shutdown();
}
else{
broadcast(nickname + ": " + message);
}
}
} catch(IOException e){
if(this.in != null && this.out != null){
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) {
// TODO code application logic here
Server server =new Server();
server.run();
}
}
below is the client class in which client has been implemented. A great number of clients can connect to the server through cmd.
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package java_40;
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 Socket client;
private BufferedReader in;
private PrintWriter out;
private boolean done;
#Override
public void run() {
try{
Socket client = new Socket("127.0.0.1",9999); // if you want to connect to someone elses server replace the ip with their ip as of now this our own ip
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();
}
}
private 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("/quits")){
inReader.close();
shutdown();
}else{
out.println(message);
}
}
}catch(IOException e){
// shutdown();
}
}
}
public static void main(String[] args) {
client c = new client();
c.run();
}
}

The read from a TCP Server hangs when reading more than once

I am testing some TCP code and it seems to work fine except for one problem. The read from the socket hangs in one of the methods when there is nothing more to read:
Here is the TCP code:
package com.comp424.service;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TCPService implements Runnable
{
protected int serverPort;
protected InetAddress bindAddress;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread = null;
protected ExecutorService threadPool = Executors.newFixedThreadPool(10);
public TCPService(String host,int port)
{
serverPort = port;
try
{
bindAddress = InetAddress.getByName(host);
}
catch (UnknownHostException e)
{
throw new RuntimeException("Failed to get bind address", e);
}
}
private void start()
{
try
{
serverSocket = new ServerSocket(serverPort, 10, bindAddress);
}
catch (IOException e)
{
throw new RuntimeException("Cannot open port " + serverPort, e);
}
}
public void run()
{
synchronized (this)
{
runningThread = Thread.currentThread();
}
start();
while (!isStopped())
{
Socket clientSocket = null;
try
{
clientSocket = serverSocket.accept();
}
catch (IOException e)
{
if (isStopped())
{
System.out.println("Server Stopped.");
break;
}
throw new RuntimeException("Error accepting client connection", e);
}
threadPool.execute(new ClientHandler(clientSocket));
}
threadPool.shutdown();
System.out.println("Server Stopped.");
}
public synchronized void stop()
{
isStopped = true;
try
{
serverSocket.close();
}
catch (IOException e)
{
throw new RuntimeException("Error closing server", e);
}
}
private synchronized boolean isStopped()
{
return isStopped;
}
}
package com.comp424.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import com.comp424.impl.dao.DaoFactory;
import com.comp424.intf.dao.ICourseDao;
import com.comp424.intf.dao.IPersonDao;
import com.comp424.intf.dao.IRegisterCourseDao;
import com.comp424.model.Course;
import com.comp424.model.Person;
public class ClientHandler implements Runnable
{
private static IRegisterCourseDao registrationDao;
private static IPersonDao personDao;
private static ICourseDao courseDao;
protected Socket clientSocket = null;
public ClientHandler(Socket socket)
{
registrationDao = DaoFactory.getInstance().getCourseRegistrationDao();
personDao = DaoFactory.getInstance().getPersonDao();
courseDao = DaoFactory.getInstance().getCourseDao();
clientSocket = socket;
}
public void run()
{
try
{
String command = null;
OutputStream output = clientSocket.getOutputStream();
BufferedReader buffer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
command = buffer.readLine();
while (command != null)
{
String separator = ":";
StringTokenizer tokenizer = new StringTokenizer(command, separator);
List<String> tokens = new ArrayList<>();
while (tokenizer.hasMoreElements())
{
tokens.add((String) tokenizer.nextElement());
}
int operation = Integer.parseInt(tokens.get(0));
switch (operation)
{
case 1:
try
{
Person person = personDao.findByID(Long.parseLong(tokens.get(1)));
Course course = courseDao.findByID(Long.parseLong(tokens.get(2)));
registrationDao.register(person, course);
output.write(("0\r\n").getBytes());
}
catch (Exception e)
{
e.printStackTrace();
output.write(("1\r\n").getBytes());
}
break;
case 2:
try
{
Person person = personDao.findByID(Long.parseLong(tokens.get(1)));
Course course = courseDao.findByID(Long.parseLong(tokens.get(2)));
registrationDao.register(person, course);
output.write(("0\r\n").getBytes());
}
catch (Exception e)
{
e.printStackTrace();
output.write(("1\r\n").getBytes());
}
break;
case 3:
try
{
Person person = personDao.findByID(Long.parseLong(tokens.get(1)));
List<Course> courses = registrationDao.findByPerson(person);
for (Course c : courses)
{
output.write((c.getName() + "\r\n").getBytes());
}
}
catch (Exception e)
{
e.printStackTrace();
output.write(("1\r\n").getBytes());
}
break;
}
command = buffer.readLine();
}
output.close();
}
catch (IOException e)
{
// report exception somewhere.
e.printStackTrace();
}
}
}
And here is the code where it just hangs in findRegisteredCourses() after reading two strings returned instead of exiting the while loop:
while (response != null)
{
result.add(response);
System.out.println("findRegisteredCourses():Response = " + response);
response = reader.readLine();
}
Full code for findRegisteredCourses():
#Override
public List<String> findRegisteredCourses(String personID) throws Exception
{
try (Socket server = new Socket("localhost", 7000))
{
List<String> result = new ArrayList<>();
DataOutputStream writer = new DataOutputStream(server.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream()));
String operation = "3:" + personID + "\r\n";
writer.writeBytes(operation);
writer.flush();
String response = reader.readLine();
while (response != null)
{
result.add(response);
System.out.println("findRegisteredCourses():Response = " + response);
response = reader.readLine();
}
server.close();
return result;
}
}
You're continuing to try to read from the server until it's closed the socket - whereas the server is waiting for another command from the client. Neither side is going to do anything, as they're waiting for the other.
Basically, you need to change your protocol, either to have some "here's the end of the response" indication (such as an empty line, if that's not a valid value in the response data), or to only have a single request/response per connection.
Your suggested "fix" of using the ready() method is very broken - it basically means you assume there's no more data as soon as there's a pause. Maybe the server is taking a while to find the next item. Maybe there's a delay on the network - or maybe it's finished. You can't tell, and basically you're violating the design of streaming protocols (such as TCP) by trying to infer information from the fact that there's no data available right now. Don't do that - fix your protocol.
Deleted my original answer because it was wrong as per #Jon Skeet's comments. I now just send a special end of data token and it works fine.

Sending a String through socket. Server not receiving it

I've been struggling lately to find a way to deliver strings through a socket file. I'm planning to create a remote tool(client) to execute things based on the received message(server).
I've searched answers for my problem on google and i found some things and managed to understand things but I also got some problems (i'm new to programming, not yet in college).
I would appreciate any help in this matter
SocketService.java ---- class file = serverside
package socket;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
public class ServiceSocket {
static ServerSocket myService;
static Socket thesocket;
static Thread socketThread;
public static boolean socketRunning;
public static DataInputStream socketMessage;
public static void initialise(String localhost, int portNumber ){
// make a server socket//////
try {
myService = new ServerSocket(portNumber);
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
//////////////////////////////
}
public static void deploySocket(){
socketThread = new Thread() {
public void run(){
// making connection
System.out.println("VVaiting for connection...");
try {
thesocket = myService.accept();
System.out.println("Connection made");
socketRunning = true;
} catch (IOException e) {
e.printStackTrace();
}
////////////////////////////////////
try {
StartBrain();
} catch (IOException e1) {
e1.printStackTrace();
}
if(socketRunning = false) {
try {
thesocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
socketThread.start();
}
public static String getSocketMessage() throws IOException {
try {
socketMessage = new DataInputStream(thesocket.getInputStream());
} catch (IOException e1) {
e1.printStackTrace();
}
boolean looprunning = true;
String message = null;
System.out.println("entering loop");
do {
try {
while (socketMessage.readUTF() != null) {
message = socketMessage.readUTF();
looprunning = false;
}
} catch (EOFException e) {
}
}while(looprunning);
System.out.println("Message received from UTF: " + message);
System.out.println("loop exited vvith message");
if(message == null) {
message = "no message";
}
return message;
}
public static void StartBrain() throws IOException {
System.out.println("socket brain started");
String BrainMessage = getSocketMessage();
if(BrainMessage == "command") {
System.out.println("Command EXECUTED HAHA");
} else if(BrainMessage == "taskschedule") {
System.out.println("task scheduled");
} else {
System.out.println("no command received");
}
}
Main.java ----- class file = serverside
package main;
import socket.ServiceSocket;
public class Main {
public static void main(String[] args) {
ServiceSocket.initialise("localhost", 3535);
ServiceSocket.deploySocket();
}
}
}
Main.java = CLIENT
package mainPackage;
import java.io.*;
import java.net.*;
import java.util.concurrent.TimeUnit;
public class Main {
private static Socket clientSocket;
public static void sendMessage(String message) throws IOException, InterruptedException {
DataOutputStream dOut = new DataOutputStream(Main.clientSocket.getOutputStream());
dOut.writeUTF(message);
dOut.flush();
dOut.close();
}
public static void main(String[] args) throws Exception {
// String modifiedSentence;
clientSocket = new Socket("localhost", 3535);
System.out.println("Initializing");
sendMessage("command");
boolean running = true;
while(running) {
TimeUnit.SECONDS.sleep(3);
sendMessage("taskschedule");
}
clientSocket.close();
}
}
main problem
do {
try {
while (socketMessage.readUTF() != null) {
message = socketMessage.readUTF();
looprunning = false;
}
} catch (EOFException e) {
}
}while(looprunning);
it doesn't read the string/UTF
It does read it, here:
while (socketMessage.readUTF() != null) {
and then throws it away as you're not assigning the return-value to a variable, and then tries to read another one, here:
message = socketMessage.readUTF();
but the one (first) message you send is already gone.
You have problem in
while (socketMessage.readUTF() != null) {
message = socketMessage.readUTF();
looprunning = false;
}
First call to method readUTF() will block thread and read UTF string from socket, but you discard this value and try read string second time.
If you replace socketMessage.readUTF() != null with looprunning server will log this messages:
VVaiting for connection...
Connection made
socket brain started
entering loop
Message received from UTF: command
loop exited vvith message
no command received
P.S.
Command is not recognized because use compare objects (string is object) with ==, but you must use equals.
public static void StartBrain() throws IOException {
System.out.println("socket brain started");
String BrainMessage = getSocketMessage();
if (BrainMessage.equals("command")) {
System.out.println("Command EXECUTED HAHA");
} else if (BrainMessage.equals("taskschedule")) {
System.out.println("task scheduled");
} else {
System.out.println("no command received");
}
}
Server log:
VVaiting for connection...
Connection made
socket brain started
entering loop
Message received from UTF: command
loop exited vvith message
Command EXECUTED HAHA

Java NIO - SocketChannel.write() on server many times but Client only receive result once

I'm doing an exercise requires making a server - client chat program using Java Non-Blocking IO. At the moment, the way the program works is simple: when a client send a message to the server, the server (which already keep track of all the clients) echo the message back to all the clients.
This is my some parts of my server-side code:
public static ByteBuffer str_to_bb(String msg) {
try {
return encoder.encode(CharBuffer.wrap(msg));
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
private static void broadcastMessage(String nickname, String message) {
System.out.println(">clientSocketChannels size " + clientSocketChannels.size());
Iterator clientSocketChannelsIterator = clientSocketChannels.iterator();
while (clientSocketChannelsIterator.hasNext()) {
SocketChannel sc = (SocketChannel) clientSocketChannelsIterator.next();
try {
ByteBuffer bb = str_to_bb(message);
System.out.println("bufferRemaining: " + bb.remaining()); // returns 2048
int writeResult = sc.write(bb);
System.out.println("writeResult: " + writeResult); // returns 2048
} catch (IOException e) {
e.printStackTrace();
}
}
}
The following is my client-side code:
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* Created by ThaiSon on 7/6/2015.
*/
public class ChatRoomClientGUI {
private JTextArea textAreaMessages;
private JTextField textFieldMessage;
private JButton buttonSendMsg;
private JPanel jPanel1;
private JLabel txtFieldInfo;
private static InetAddress inetAddress;
private static final int PORT = 1234;
private static Socket socket = null;
private static Scanner input = null;
private static PrintWriter output = null;
private static ChatRoomClientGUI singleton;
public ChatRoomClientGUI() {
singleton = this;
buttonSendMsg.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if (e.getButton() == MouseEvent.BUTTON1) {
String message = textFieldMessage.getText();
output.println(message);
textFieldMessage.setText("");
}
}
});
}
public static void main(String[] args) {
JFrame promptFrame = new JFrame();
Object nickname = JOptionPane.showInputDialog(promptFrame, "Enter your nickname:");
promptFrame.dispose();
JFrame frame = new JFrame("ChatRoomClientGUI");
frame.setContentPane(new ChatRoomClientGUI().jPanel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
System.out.println("> Client with nickname " + nickname);
try {
inetAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
accessServer(nickname.toString());
}
private static void accessServer(String nickname) {
try {
socket = new Socket(inetAddress, PORT);
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
output.println(nickname); // Register nickname with the server
//TODO update the txtFieldInfo content
// Create a new thread to listen to InputStream event
InputStreamEvent inputStreamEvent = new InputStreamEvent(socket);
inputStreamEvent.start();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleInputStream(){
String response = input.nextLine();
System.out.println("TODO " + response);
singleton.textAreaMessages.append(response + "\n");
}
static class InputStreamEvent extends Thread{
Socket socket;
public InputStreamEvent(Socket socket){
this.socket = socket;
}
public void run(){
try {
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[2048];
int read;
while (true){
if(inputStream.available() > 0){
handleInputStream();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The problem I'm facing with now is that when I use a client (which works well with the old multithreaded server) to send message to the server, the client only get return the first message it sends. All the next responses from the server is empty (the server does send back, but only an empty message).
So my attempts to debug includes:
check if the messages from the client has reach the server or not. They does.
log the buffer.remaining() and socketChannel.write(buffer) result as shown above, all the log result seems to be normal to me.
Hope you guys can help me with this.
This:
if(inputStream.available() > 0){
Get rid of this test. With it, your client is smoking the CPU. Without it, it will block in readLine() as God intended.
Are you sure your server is still sending lines? with line terminators? If it isn't, readLine() will block forever looking for one, until end of stream or an exception occurs.
I referred the code explain by EJP on this link Java NIO Server/Client Chat App - sending data only by closing the socket
it solves my problem. use this code
import java.nio.channels.SocketChannel;
import java.nio.channels.Selector;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.util.Scanner;
import java.nio.channels.SelectionKey;
import java.net.InetSocketAddress;
public class Client {
public static void main(String args[]) {
try {
ByteBuffer buf = ByteBuffer.allocate(200);
Scanner scanner = new Scanner(System.in);
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
boolean isConnected = socketChannel.connect(new InetSocketAddress("localhost", 5000));
if(isConnected) {
System.out.println("Connected, de-registering OP_CONNECT");
}
new Thread(new Runnable(){
private SocketChannel socketChannel;
private Selector selector;
public Runnable init(SocketChannel socketChannel, Selector selector) {
this.socketChannel = socketChannel;
this.selector = selector;
return this;
}
public void run() {
try {
ByteBuffer buf = ByteBuffer.allocate(200);
while(!Thread.interrupted()) {
int keys = selector.select();
if(keys > 0) {
for(SelectionKey key : selector.selectedKeys()) {
if(key.isConnectable()) {
boolean finishConnectResult = socketChannel.finishConnect();
socketChannel.register(this.selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
System.out.println("Finished Connect : " + finishConnectResult);
}
if(key.isReadable()) {
int bytesRead = 0;
while((bytesRead = socketChannel.read(buf)) > 0) {
buf.flip();
while(buf.hasRemaining()) {
System.out.print((char)buf.get());
}
buf.clear();
}
if(bytesRead == -1) {
key.channel().close();
}
}
}
}
Thread.sleep(10);
}
} catch(IOException e) {
e.printStackTrace();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}.init(socketChannel, selector)).start();
while(true) {
while(scanner.hasNextLine()) {
buf.clear();
buf.put(scanner.nextLine().getBytes());
buf.flip();
socketChannel.write(buf);
buf.flip();
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
I have done the mistake setting this flag
key.interestOps(SelectionKey.OP_READ);
)
instead of below.
use this
socketChannel.register(this.selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);

send a message to specific client threads

I have this Server class,
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public static ArrayList<String> waiting = new ArrayList<String>();
public static ArrayList<String> playing = new ArrayList<String>();
public static ArrayList<Integer> score = new ArrayList<Integer>();
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(4321);
while (true) {
try {
Socket socket = server.accept();
new EchoThread(socket).start();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void addClient(String name) {
waiting.add(name);
}
public int getNumClients() {
return waiting.size();
}
public String getClientName(int i) {
return waiting.get(i);
}
public void play() {
int scr = 0;
for (int i = 0; i < 4; i++) {
playing.add(waiting.get(0));
score.add(scr);
waiting.remove(0);
}
}
public boolean checkIfPlaying(String name) {
if (playing.indexOf(name) >= 0) {
return true;
} else {
return false;
}
}
}
and the Thread Class,
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoThread extends Thread {
protected Socket socket;
public EchoThread(Socket clientSocket) {
this.socket = clientSocket;
}
public void run() {
Server s = new Server();
DataInputStream in = null;
DataOutputStream out = null;
String line;
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
while (true) {
try {
line = in.readLine();
String[] prot = line.split(":");
if (prot[0].equals("/login")) {
s.addClient(prot[1]);
} else if (prot[0].equals("/waiting")) {
if (s.checkIfPlaying(prot[1])) {
out.writeBytes("Playing" + "\r\n");
} else {
if (s.getNumClients() >= 4) {
s.play();
out.writeBytes("Playing" + "\r\n");
} else {
out.writeBytes(s.getNumClients() + "\r\n");
}
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
If the client connect to the server, the name of the client is stored in Server Class Array, waiting.
If the waiting clients is equals to 4, it will remove from the waiting array and put it in playing array.
I would like to make the server send message to the first 4 clients in playing array.
How can I do it?
For your Server Class, I would change your ArrayList< String > for waiting and playing to ArrayList< EchoThread >. This way your Server class is tracking each client object themselves instead of just their names. When you instantiate your EchoThread objects, I would pass the local server object to each EchoThread that way each object knows about the server that instantiated them.
Server Class
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public ArrayList<EchoThread> waiting = new ArrayList<EchoThread>();
public ArrayList<EchoThread> playing = new ArrayList<EchoThread>();
public ArrayList<Integer> score = new ArrayList<Integer>();
public static void main(String[] args) {
try {
// Instantiate a single server object that you can pass into your connected clients
Server myServer = new Server();
ServerSocket server = new ServerSocket(4321);
while (true) {
try {
Socket socket = server.accept();
// Pass myServer into Echo Thread
new EchoThread(myServer, socket).start();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Have to synchronize this since multiple clients could be adding to this list at the same time
public synchronized void addClient(EchoThread client) {
waiting.add(client);
}
public int getNumClients() {
return waiting.size();
}
public String getClientName(int i) {
return waiting.get(i).getCName();
}
public void play() {
int scr = 0;
for (int i = 0; i < 4; i++) {
EchoThread clientBeingMovedToPlaying = waiting.get(0);
playing.add(clientBeingMovedToPlaying);
score.add(scr);
waiting.remove(0);
// This will be a new method in your EchoThread class
clientBeingMovedToPlaying.SendServerPlayingMessage();
}
}
public boolean checkIfPlaying(String name) {
boolean isPlaying = false;
for(EchoThread client : playing) {
if (client.getName().contentEquals(name)) {
isPlaying = true;
break;
}
}
return isPlaying;
}
}
For your Echo Thread class, I would make your variables in your run method class variables so they can be used throughout the class
EchoThread Class
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoThread extends Thread {
protected Socket socket;
protected Server s;
protected DataInputStream in;
protected DataOutputStream out;
protected String line;
protected String clientName;
// This way, each EchoThread object knows about the server
public EchoThread(Server theServer, Socket clientSocket) {
this.s = theServer;
this.socket = clientSocket;
}
public void run() {
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
while (true) {
try {
line = in.readLine();
String[] prot = line.split(":");
if (prot[0].equals("/login")) {
// Original code
//s.addClient(prot[1]);
// New code
clientName = prot[1];
s.addClient(this);
} else if (prot[0].equals("/waiting")) {
if (s.checkIfPlaying(prot[1])) {
out.writeBytes("Playing" + "\r\n");
} else {
// You don't want multiple clients firing the play method, so you need to synchronize your server object
synchronized (s) {
if (s.getNumClients() >= 4) {
s.play();
out.writeBytes("Playing" + "\r\n");
} else {
out.writeBytes(s.getNumClients() + "\r\n");
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
public String getCName() {
return clientName;
}
public void SendServerPlayingMessage() {
if (out != null) {
// Send whatever message you want
}
}
}
I think this'll get you what your wanting... Forgive any syntax or logical errors, I don't have an IDE right in front of me at the moment.

Categories

Resources