Реализация на еднопосочен мост с отдалечени коли

Мост - ресурс (монитор).  Ограничение на броя на колите в една посока за да не бъде блокиран моста (maxCount) . Ако out != null то колата е отдалечена, като нишката за тази кола изпраща към PrintWriter out (клиента) информация при всяка промяна на състоянието на нишката

import java.io.PrintWriter;

public class Bridge {
    private int nVh, countSeq, maxCount;
    private boolean open;
    Bridge(int maxCount){
        nVh = countSeq = 0;
        open = true;
        this.maxCount=maxCount;
    }
    synchronized public int brN(){
        return nVh;
    }
    synchronized public void takeB(boolean lr,PrintWriter out ){
        while((nVh>0)&& (lr==true)||
                (nVh<0) && (lr==false)|| !open){
            System.out.println("\t"+Thread.currentThread().getName()+" waiting");
            if(out != null) {
                out.print(" waiting");     // to the remote client
                if(!open)out.println("\tthe bridge is closed\n");
                else out.println("\tvehicles in oposite direction\n");
            }
            try{     wait();   }
            catch(InterruptedException e){
                System.err.println(e);
            }
        }
        countSeq++;
        if (lr) nVh--;
        else nVh++;
        System.out.println(Thread.currentThread().getName()+" on the bridge in the same direction: "+countSeq);
        if(out != null) {
            out.println(" on the bridge");     // to the remote client
        }        
        if (countSeq==maxCount){open = false; System.out.println("The bridge is closed");}
        
        try {
            Thread.sleep(500);
        }
        catch(InterruptedException ie) {};
    }

    synchronized public void leaveB(boolean lr,PrintWriter out ){
        if (nVh>0) nVh--;
        else nVh++;
        System.out.println("\t\t"+Thread.currentThread().getName()+" leave the bridge");
        if(out != null) {
            out.println("leave the bridge");     // to the remote client
        }    
        if(nVh==0){countSeq=0;open = true; System.out.println("The bridge is open");}
        notifyAll();
    }
}

Сървър - самият той се стартира като нишка от класа Circ. Генерира нишки за обслужване на отдалечените клиенти при поява на нова кола (клиент).

import java.io.*;
import java.net.*;

public class Server extends Thread{
    private static final int PORT = 8080;
    private ServerSocket s=null;
    private Bridge b;
    Server(Bridge b){
        this.b=b;
    }
    public void run(){
        try {
            s = new ServerSocket(PORT);
            System.out.println("Server Started");
            while(true) {
                // Blocks until a connection occurs:
                Socket socket = s.accept();
                try {
                    new ServeOneVehicle(socket,b);
                } catch(IOException e) {
                    // If it fails, close the socket,
                    // otherwise the thread will close it:
                    socket.close();
                }
            }
        }
        catch(Exception ioe){}
        try {
            s.close();
        }
        catch(Exception ioe){}       
    }
}


Нишка за обслужване на отдалечен клиент - получава името и след това на отделни редове посоката на преминаване на колата.

Генерира нишка реализираща  преминаване на отдалечена кола при всяка заявка.
Завършва при команда "END" за поредната пососка.


import java.io.*;
import java.net.*;

class ServeOneVehicle extends Thread {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private Bridge b;
    private String name="";
    public ServeOneVehicle(Socket s, Bridge b)  throws IOException {
        socket = s;
        in = new BufferedReader(
                new InputStreamReader(
                  socket.getInputStream()));
        out =   new PrintWriter(
                new BufferedWriter(  new OutputStreamWriter(
                        socket.getOutputStream())),true);
        this.b=b;
        System.out.println("\t\t\tnew remote connection");
        start();    // Calls run()
  }
  public void run() {
      String leftToRight;
      boolean lr;
    try {
        name = in.readLine();
        while (true) {
             leftToRight = in.readLine();
             if (leftToRight.equals("END")) break;
             if(leftToRight.equalsIgnoreCase("Left"))lr=true;
             else lr=false;
             (new Vehicle(name,lr, b,out)).start();       
        }
        System.out.println("closing connection to "+name);
    } catch (IOException e) {  }
   finally {
      try {
        socket.close();
      } catch(IOException e) {}
    }
  }



Нишка за кола. Ако е локална (name=out=null) генерира име.

Ако е отдалечена (out!=null) създава нишка с име изпратено от клиента и допълнено с посоката на движение.  Комуникира с клиента етапите на преминаване, използвайки публичните методи на класа Bridge.

//for local in constructor's parameter:  name=out=null
import java.io.PrintWriter;

public class Vehicle extends Thread{
  private boolean lr;
  private Bridge b;
  private String name;
  private static int num;
  private PrintWriter out;
  Vehicle(String name,boolean lr, Bridge b, PrintWriter out){
      this.lr=lr;
      this.b = b;
      this.out=out;
      if(name==null)this.name = "V "+ ++num + (lr?" left->":" <-right");  //local vehicle
      else this.name = "\07\t\t"+name + (lr?" left->":" <-right"); //remote vehicle
      super.setName(this.name);
      if(num%10==1)System.out.println("\n\n\n starting new serie "+num/10+"\n\n");
      System.out.println("\t\t\t\tCreating new Vehicle "+this.name);
      if(num%10==0)System.out.println("\t\t\tend of serie "+num/10);
  }
  public void run(){
      try {
          sleep((int)(Math.random()*600));
      } catch (InterruptedException e){}
      b.takeB(lr,out);         //direction, remote or local
      try {
          sleep(3000);
      } catch (InterruptedException e){}
      b.leaveB(lr,out);
  }
}



Главно приложение - стартира сървъра и генерира локално коли (първи и четвърти параметър = null).

public class Circ {
    public static void main(String arg[]){

        Bridge b = new Bridge(4);
        (new Server(b)).start();
        for(int i = 1; ; i++){
            (new Vehicle(null,Math.random()>0.5?true:false, b,null)).start();
            try{
                Thread.sleep(500);
            }catch (InterruptedException e){}
            if((i%10)==0) {
                try{
                    Thread.sleep(20000);
                }catch (InterruptedException e){}
            }
        }
    }
}

Отдалечен клиент - задава име, пита за посока многократно, при 'Enter' завършва. Чака от сървъра, и извежда информация на конзолата за промяна на състоянието на нишката докато не получи съобщение за "leave bridge".

import java.net.*;
import java.io.*;
public class RemVehicleClient {
    private static final int PORT = 8080;
    private static String name;
    public static void main(String[] args)throws IOException {
        String server = null;
        InetAddress addr =  InetAddress.getByName(server);
        System.out.println("addr = " + addr);
        Socket socket = new Socket(addr, PORT);                   
        //Socket s=new Socket(); //s.connect(new  InetSocketAddress(host,port),timeout);
        // Guard everything in a try-finally to make       
        // sure that the socket is closed:
        try {
            System.out.println("socket = " + socket);
            BufferedReader in =
                    new BufferedReader(
                            new InputStreamReader(socket.getInputStream()));
            BufferedReader sin =  new BufferedReader(
                    new InputStreamReader(System.in));

            // Output is automatically flushed
            // by PrintWriter:
            PrintWriter out =   new PrintWriter(
                    new BufferedWriter(  new OutputStreamWriter(
                            socket.getOutputStream())),true);
            System.out.print("Your name please:");
            name = sin.readLine();
            out.println("REMOTE CLIENT: "+name);
            for(;;) {
                System.out.print("input L(left->right) or R(right->left) [empty for finish] :");
                String s = sin.readLine();
                if(s.length()==0) break;
                if(!(s.equalsIgnoreCase("L"))&&!(s.equalsIgnoreCase("R"))) {
                    System.out.println("L or R or 'Enter' please");
                    continue;
                }

                out.println(s.equalsIgnoreCase("L")?"Left":"Right");
                String servM;
                do {
                    servM=in.readLine();    // message from server
                    System.out.println(servM);  
                }while(!servM.startsWith("leave"));  //variable number of messages

            }
            out.println("END");
        }
        finally {
            System.out.println("closing...");
            socket.close();
        }
    }
}