Hello everyone i have created a multi threaded chat server that looks like this:
public class Main {
public static ServerSocket server;
public static Socket connection;
public static int backLog = 100;
public static int numberOfConnected;
public static boolean connected = false;
public final static int potNumber = 6080;
public static PrintWriter pw;
public static Scanner input;
public static int i = 0;
public static void main(String[] args) {
startServer();
}
public static void startServer(){
try {
server = new ServerSocket(potNumber, backLog);
waitingForConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void waitingForConnection() {
connected = false;
i++;
while (!connected) {
try {
if (connected) {
}
connection = server.accept();
Server s = new Server(connection, pw = new PrintWriter(connection.getOutputStream()), input = new Scanner(connection.getInputStream()));
s.start();
numberOfConnected++;
waitingForConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The idea is that this is suppose to be a chat server so when one connects to the server it starts the following thread:
threads
public void run(){
while (connection.isConnected()) {
if (input.hasNext()) {
String fullMessage = input.nextLine();
if (fullMessage.equalsIgnoreCase("Connect")) {
connectHim();
}else {
chatMessage(fullMessage);
}
}
}
}
private void chatMessage(String fullMessage) {
String name = fullMessage.substring(0, fullMessage.indexOf(" "));
String message = fullMessage.substring(fullMessage.indexOf(" "), fullMessage.length());
pw.println(name+": "+message);
pw.flush();
}
private void connectHim() {
String name = input.nextLine();
pw.println(0);
pw.flush();
pw.println(1);
pw.flush();
pw.println();
pw.flush();
pw.println(name);
pw.flush();
}
So my problem is the following:
if the user that is bound to thread 1 (this is an example) and the user bound to thread 2 sends a message to the server how will i send that message to the user bound on thread 1?
One of options is to use Hashtable or HashMap (just call Collections.synchronizedMap(myMap) in case of Map usage). When you start new Thread, give him unique name (for example user nick name ) and put it to your collection where key - Thread name, and value - Thread as Object.
if the user that is bound to thread 1 (this is an example) and the user bound to thread 2 sends a message to the server how will i send that message to the user bound on thread 1?
For example you have user1, user2, user3. Now you build 3 Threads and put them to HashMap, like:
Map<String, Thread> threadMap = new HashMap<String,Thread>();
threadMap = Collections.synchronizedMap(threadMap);
YourThread th1 = new YourThread();
threadMap.put("user1", th);
YourThread th2 = new YourThread();
threadMap.put("user2", th);
YourThread th3 = new YourThread();
threadMap.put("user3", th);
....
Set<String> userSet = threadMap.keySet();
Iterator<String> it = userSet.iterator();
Thread currThread = null;
while(it.hasNext()){
String key = it.next();
currThread = threadMap.get(key);
// do something with currThread
}
Related
I am trying to figure out NIO in Java doing some simple client-server project.
The case is I have to concurrent clients in cached thread pool executor, who are communicating with single-threaded server using non-blocking NIO channels.
The problem is that last client cannot receive last server's sent message. It locks in infinite loop waiting for upcoming data.
ClientTask class:
public class ClientTask extends FutureTask<String> {
private Client client;
private List<String> reqList; // requests list (without last and first)
private boolean showRes; // print request results
public ClientTask(Client client, List<String> reqList, boolean showRes) {
super(() -> ClientTask.getLogWhenArrives(client, reqList, showRes));
this.client = client;
this.reqList = reqList;
this.showRes = showRes;
}
public static ClientTask create(Client c, List<String> reqList, boolean showRes) {
return new ClientTask(c, reqList, showRes);
}
private static String getLogWhenArrives(Client client, List<String> reqList, boolean showRes) {
client.connect();
String response = client.send("login " + client.getId());
if (showRes) System.out.println(response);
for (String req : reqList) {
response = client.send(req);
if (showRes) System.out.println(response);
}
String responseLog = client.send("bye and log transfer");
client.close();
return responseLog;
}
}
Client send():
public String send(String req) {
ByteBuffer reqBuffer = ByteBuffer.wrap((req + END).getBytes());
try {
channel.write(reqBuffer);
} catch (IOException e) {
e.printStackTrace();
}
return receive();
}
Client receive()
public String receive() {
StringBuilder result = new StringBuilder();
try {
inBuff.clear();
readLoop:
while (true) { // THIS LOOP WON'T END
int n = channel.read(inBuff);
if (n == -1) {
break;
}
if (n > 0) {
inBuff.flip();
CharBuffer cb = charset.decode(inBuff);
while (cb.hasRemaining()) {
char c = cb.get();
if (c == END.charAt(0)) {
break readLoop;
}
result.append(c);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
Main:
public class Main {
public static void main(String[] args) throws Exception {
String fileName = System.getProperty("user.home") + "/PassTimeServerOptions.yaml";
Options opts = Tools.createOptionsFromYaml(fileName);
String host = opts.getHost();
int port = opts.getPort();
boolean concur = opts.isConcurMode();
boolean showRes = opts.isShowSendRes();
Map<String, List<String>> clRequests = opts.getClientsMap();
ExecutorService es = Executors.newCachedThreadPool();
List<ClientTask> ctasks = new ArrayList<>();
List<String> clogs = new ArrayList<>();
Server s = new Server(host, port);
s.startServer();
// start clients
clRequests.forEach( (id, reqList) -> {
Client c = new Client(host, port, id);
if (concur) {
ClientTask ctask = ClientTask.create(c, reqList, showRes);
ctasks.add(ctask);
es.execute(ctask);
}
});
if (concur) {
ctasks.forEach( task -> {
try {
String log = task.get();
clogs.add(log);
} catch (InterruptedException | ExecutionException exc) {
System.out.println(exc);
}
});
clogs.forEach( System.out::println);
es.shutdown();
}
s.stopServer();
System.out.println("\n=== Server log ===");
System.out.println(s.getServerLog());
}
}
Server is sending all the info and channels are open and connected.
I've been given this question and I've been trying since days but I'm not able to get the correct output. Any help would be appreciated.
Develop a simple chat application between two users using Send-Wait-Receive Protocol:
Once a user sends a message, he waits until a message is received from the other user. The users are "User1" and "User2".
At initial stage of application, User1 is in sending mode and User2 is in receiving mode. These two users are sending and receiving the messages alternatively.
-Create a Chat class with two methods: sendMessage and recvMessage
-Create two threads to represent two users,User1 and User2.
-Use Interthread communication to exchange messages.
-No need to maintain any chat history.
OUTPUT:
User1(User2):HI
User2(User1):HI
User2(User1):Hello
User1(User2):Hello
class Chat{
Scanner sc=new Scanner(System.in);
String message;
ArrayList<String> user1 = new ArrayList<String>();
ArrayList<String> user2 = new ArrayList<String>();
boolean sendMode = true;
String name = "";
String otherName = "";
synchronized void recvMessage(){
name = Thread.currentThread().getName();
while(sendMode) {
try{
wait();
}catch(InterruptedException e){
System.out.println("InterruptedException caught");
}
}
System.out.println(name);
if (name.contentEquals("User1")) {
otherName="User2";
}
else {
otherName="User1";
}
System.out.println(name+"("+otherName+"):" + message);
sendMode=true;
System.out.println("rcv");
notify();
}
synchronized void sendMessage(){
name = Thread.currentThread().getName();
while(!sendMode) {
try{
wait();
}catch(InterruptedException e){
System.out.println("InterruptedException caught");
}
}
System.out.println(name);
if (name.contentEquals("User1")) {
otherName="User2";
}
else {
otherName="User1";
}
System.out.print(name+"("+otherName+"):");
message=sc.next();
if(name.contains("User1")) {
user1.add(message);
}
else {
user2.add(message);
}
System.out.println("send");
sendMode=false;
notify();
}
}
class Person1 implements Runnable{
Chat ex;
public Person1(Chat ex) {
this.ex = ex;
Thread u2=new Thread(this, "User1");
u2.start();
}
public void run() {
while(true) {
ex.sendMessage();
}
}
}
class Person2 implements Runnable{
Chat ex;
public Person2(Chat ex) {
this.ex=ex;
Thread u1=new Thread(this, "User2");
u1.start();
}
public void run() {
while(true) {
ex.recvMessage();
}
}
}
class Main{
public static void main(String args[])
{
Chat ex =new Chat();
new Person1(ex);
new Person2(ex);
}
}
the output I'm getting is:
User1(User2):hi
User2(User1):hi
User2(User1):hello
User1(User2):hello
User2(User1):what's up
User1(User2):what's
User2(User1):User1(User2):up
User2(User1):
Basically the threads are not in doing their job in order. The first 4 lines of output are right. But after that, it's always user2 sending the message and user1 receiving it.
Please help me out.
There is two issues with your code first is that you are using:
message=sc.next();
and instead you should be using:
message=sc.nextLine();
Using next() will only return what comes before the delimiter
(defaults to whitespace). nextLine() automatically moves the scanner
down after returning the current line.
From this SO thread.
That is why for the first inputs without spaces it works fine, but as soon as you send a string with spaces:
what's up
you ran into problems.
The second part is that with your current design only one of the threads send and another receives. For having both communication with each other instead of a monologue, I would suggest to do something like:
class Chat{
Scanner sc=new Scanner(System.in);
String message;
final Object rec = new Object();
final Object send = new Object();
boolean msg_send = false;
boolean msg_recv = false;
void recvMessage(){
synchronized (send){
while(!msg_send) {
try{
send.wait();
}catch(InterruptedException e){
System.out.println("InterruptedException caught");
}
}
msg_send = false;
}
synchronized (rec) {
String name = Thread.currentThread().getName();
System.out.println(name);
String otherName = name.contentEquals("User1") ? "User2" : "User1";
System.out.println(name + "(" + otherName + "):" + message);
System.out.println("rcv");
msg_recv = true;
rec.notify();
}
}
void sendMessage(){
synchronized (send) {
String name = Thread.currentThread().getName();
System.out.println(name);
String otherName = name.contentEquals("User1") ? "User2" : "User1";
System.out.print(name + "(" + otherName + "):");
message = sc.nextLine();
System.out.println("send");
msg_send = true;
send.notify();
}
synchronized (rec) {
while (!msg_recv) {
try {
rec.wait();
} catch (InterruptedException e) {
System.out.println("InterruptedException caught");
}
}
msg_recv = false;
}
}
}
class Person1 implements Runnable{
Chat ex;
public Person1(Chat ex) {
this.ex = ex;
Thread u2=new Thread(this, "User1");
u2.start();
}
public void run() {
while(true) {
ex.sendMessage();
ex.recvMessage();
}
}
}
class Person2 implements Runnable{
Chat ex;
public Person2(Chat ex) {
this.ex=ex;
Thread u1=new Thread(this, "User2");
u1.start();
}
public void run() {
while(true) {
ex.recvMessage();
ex.sendMessage();
}
}
}
class Main{
public static void main(String args[])
{
Chat ex =new Chat();
new Person1(ex);
new Person2(ex);
}
}
Waiting and notifying using two objects representing when the message was received and send:
final Object rec = new Object();
final Object send = new Object();
Then you need the reason about when should you synchronize on one or the other object.
I'm writing a program where I need to send multiple http requests to a lot of domains using socket. I used thread pool and socket when I start the program. It starts fast then it slows down, finally it freezes (terminal is still running).
public class HttpRequest implements Runnable{
private String url;
private Socket s;
public boolean scanned;
private String extension;
public HttpRequest(String url,String extension) throws UnknownHostException, IOException {
this.url=url;
this.extension=extension;
s=new Socket(url,80);
//
//s.setSoTimeout(600000);
}
public void run() {
String data="";
String html="";
try {
PrintWriter p=new PrintWriter(s.getOutputStream(),true);
p.println("GET /"+extension+" HTTP/1.1");
p.println("Host:"+url);
p.println("");
BufferedReader r= new BufferedReader(new InputStreamReader(s.getInputStream()));
if(r.readLine().indexOf("200 OK")!=-1) {
while ((data=r.readLine())!=null) {
html+=data;
Document d =Jsoup.parse(html);
Element form=d.select("form").first();
String value=form.attr("enctype");
if(value=="multipart/form-data") {
System.out.println("value is :"+value);
System.out.println(" found"+this.url+"/"+extension);
}
System.out.println(d.title() + this.url+"/"+extension+" "+Thread.currentThread().getName());
}}
else {
System.out.println("failed => "+this.url +"/"+ extension +" "+Thread.currentThread().getName());
}
s.close();
//}
}catch(Exception e) {
}
}
}
here is the main
I have a domain array which contain urls which I will make a request to
ExecutorService exe= Executors.newFixedThreadPool(40);
for (int i =0 ; i <= domains.length-1; i++) {
h=new handeler(domains[i]);
exe.execute(h);
}
I want to send an object having OS Name to a server. This OS Name output should be of PC sending object but it displays OS Name of PC running server..
Here is my code :
//Client : it can send data i.e. object to server
class Client
{
private Socket socket = null;
private ObjectOutputStream outputStream = null;
public Client(String con){
System.out.println("conn value: "+con);
java.util.Timer t = new java.util.Timer();
try{
socket = new Socket(con, 27051);
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
outputStream = new ObjectOutputStream(socket.getOutputStream());
SI sysinfo=new SI();
outputStream.writeObject(sysinfo);
System.out.println("Sent Data: "+sysinfo.otherInfo());
} catch (Exception se) {
t.cancel();
}
}
}, 0, 1);
}
catch(Exception em)
{
}
}
}
//Server class: should receive data from client
class Server extends SwingWorker<Void,Void>{
Socket csocket=null;
protected Void doInBackground() throws Exception {
final ServerSocket ssock = new ServerSocket(27051);
System.out.println("Server Listening..!!");
while (true) {
try{
Socket sock = ssock.accept();
new Thread(new Server(sock)).start();
}
catch(Exception e){
System.out.println("unabke to create socket");
}
}
}
Server() throws Exception{
doInBackground();
}
Server(Socket csocket) {
this.csocket=csocket;
Thread t1=new Thread(r1);
t1.start();
}
Runnable r1=new Runnable()
{
public void run() {
try {
System.out.println("Run initated");
while(true)
{
if(csocket.isClosed())
{
break;
}
else{
System.out.println(csocket);
ObjectInputStream inStream = new
ObjectInputStream(csocket.getInputStream());
SI sysinfo= (SI) inStream.readObject();
System.out.println("Received: "+sysinfo.otherInfo());
System.out.println(ObjectStreamClass.lookup(sysinfo.getClass()).getSerialVersion
UID());
}
}
}
catch (Exception e) {
System.out.println("Exception"+ e.getMessage());
}
}
};
}
//class undergoing serialization
public class SI implements Serializable
{
private static final long serialVersionUID = 1L;
String otherInfo()
{
OperatingSystemMXBean bean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
.getOperatingSystemMXBean();
String os_name=bean.getName();
return os_name;
}
}
//class A: It has main function and it executes first and user decides whether he/she want to be in server mode or in client mode. As user cannot be in 2 modes simultaneously..
class A
{
public static void main(String[] args) throws Exception
{
System.out.println("Enter 0 for Server 1 for Client Mode");
Scanner s=new Scanner(System.in);
int i=s.nextInt();
if(i==0)
{
Server ser=new Server();
ser.execute();
}
else if(i==1)
{
System.out.println("Enter IP");
String conn=s.next();
Client c=new Client(conn);
}
else
System.out.println("Invalid Selection exit..");
}
}
As I wrote in my comment you must transfer the data, not the function. Some sample code below...
First, change your SI class as follows:
public class SI implements Serializable {
private static final long serialVersionUID = 1L;
private String osName;
public void setOsName(String osName) { this.osName = osName; }
public void getOsName() { return this.osName; }
}
Second, modify your client to first determine the OS and the build the SI object...
...
OperatingSystemMXBean bean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
.getOperatingSystemMXBean();
String osName=bean.getName();
SI sysinfo = new SI();
sysinfo.setOsName(osName);
...
outputStream.writeObject(sysinfo);
...
Third, modify your server accordingly.
I'm creating a token ring with sensors where every sensor is a process apart. When i start a sensor it communicates with the gateway and gets the list of the actual sensors already on the system .
The problem is that every time i start a new process i want every already existing sensor to get the updated list, so to understand that other sensors have been added and the list is no longer the one they had but a new updated one.(So lets say the processes must always have the same list). I use a server which i call serverSocket which listens for messages. I can make it possible for the server to understand that the list has been changed but what i cant do is how to change the value of the sensorList found on my SensorClient class, to be updated? In the code bellow i show what i'm doing but the sensorList keeps being the old one,not being updated :/ Can anyone please help me? Thank you :)
SensorClient where i start a new process sensor
public class SensorClient {
public static void main(String[] args) throws Exception {
Sensor sensor = new Sensor(type,identificator,portnumber,ipnumber,gatewayAddr,timestamp);
Gson gson = new Gson();
String message = gson.toJson(sensor);
Client c = Client.create();
WebResource r = c.resource("http://localhost:9999/gateway/");
ClientResponse response = r.path("sensors/add").type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).post(ClientResponse.class, message);
if (response.getStatus() == 200) {
repeat = false;
Type collectionType = new TypeToken<ArrayList<Sensor>>(){}.getType();
ArrayList<Sensor> sensorList = gson.fromJson(response.getEntity(String.class), collectionType);
System.out.println("Starting the sensor ...");
System.out.println("Push exit when you want to delete the sensor!");
int position = 0;
for(int i = 0; i< sensorList.size();i++){ if(sensorList.get(i).getIdentificator().equalsIgnoreCase(sensor.getIdentificator()) ) position = i;
}
sensors.Sensor.simulation(type, identificator);// special thread for sensors simulations
createSensor.getInstance().setPrevNextWhenAdd(position,sensorList);
serverSocket serverSocket = new serverSocket(portnumber,sensorList,position,sensorList.get(position).getNext());
serverSocket.start();
StopSensor stopSensor = new StopSensor(identificator,portnumber,position,sensorList);
stopSensor.start();
oneSensor s = new oneSensor(portnumber,sensorList);
s.start();
} else {
repeat = true;
count +=1;
System.out.println("Error. Wrong data! ");
}
}
while (repeat );
}
}
}
The serverSocket thread
public class serverSocket extends Thread {
public int port,nextPort;
ArrayList<gateway.Sensor> sensorList;
public static int position;
public serverSocket(int port, ArrayList<gateway.Sensor> sensorList,int position,int nextPort) {
this.port = port;
this.nextPort=nextPort;
this.sensorList= sensorList;
this.position=position;}
public void run() {
ServerSocket welcomeSocket;
Socket connectionSocket;
try {
welcomeSocket = new ServerSocket(port);
while (true) {
connectionSocket = welcomeSocket.accept();
receivedMessages thread = new receivedMessages(connectionSocket,sensorList,position,nextPort);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
System.err.println("Error!!!!!!!!!");
}
}
}
The receivedMessages thread
public class receivedMessages extends Thread {
private BufferedReader inFromClient;
private Socket connectionSocket;
ArrayList<gateway.Sensor> sensorList;
int position,nextPort;
public receivedMessages(Socket socket, ArrayList<gateway.Sensor> sensorList,int position,int nextPort){
connectionSocket = socket;
this.sensorList=sensorList;
this.position=position;
this.nextPort=nextPort;
try {
inFromClient = new BufferedReader( new InputStreamReader(connectionSocket.getInputStream()));
} catch (IOException e) { e.printStackTrace(); }
}
#Override
public void run() {
try {
String message = (inFromClient.readLine().toString());
if (message.startsWith("Next") || message.startsWith("Previous")) {
System.out.println(message);
} else if (message.startsWith("The")) {
System.out.println(message); createSensor.getInstance().setPrevNextWhenDelete(position, sensorList);
} else {// i receive the message that the list has changed
System.out.println(message);
sensorList = createSensor.getInstance().getSensorList();
System.out.println("Updated " + sensorList);}
This class has methods used by gateway to register a sensor when it makes the request
public class createSensor {
private static createSensor instance = null;
private ArrayList<Sensor> sensor = new ArrayList<>();
public int position, prevPosition, nextPosition, prevPort, nextPort;
private createSensor() { }
public static synchronized createSensor getInstance() {
if (instance == null) {
instance = new createSensor();
}
return instance;
}
public synchronized ArrayList insertSensor(String type, String identificator, int port, String id, String gatwayAddr, long timestamp) throws IOException {
sensor.add(new Sensor(type, identificator, port, id, gatwayAddr, timestamp));
return new ArrayList<>(sensor); //
}
}
public synchronized boolean hasMeasurements() {
while (InnerBuffer.getInstance().emptyInnerBuffer())
return false;
return true;
}
public synchronized void setPrevNextWhenDelete(int position,ArrayList<Sensor> sensorList) throws IOException {
//code
}
public synchronized ArrayList<Sensor> getSensorList() {
return new ArrayList<>(sensor);
}
public synchronized int size() {
return sensor.size();
}
public synchronized String returnRecentMeasurement (String id){
String recentMeasurement=null;
for (Sensor sensori : sensor) {
if (sensori.getIdentificator().equalsIgnoreCase(id))
recentMeasurement= InnerBuffer.getInstance().returnRecentMeasurements(id);
else
recentMeasurement = null;}
return recentMeasurement;
}
public synchronized void setPrevNextWhenAdd() throws IOException { //some other code where int position, prevPosition, nextPosition, prevPort, nextPort get their values. }}