简体   繁体   中英

Java - Using sockets to read from and write to files, by different methods

I basically have an application that lets customers make reservations to a cinema for a movie. It also has admins that have control over the users database and content admins that take care of the movie and viewings database.

At this point, we are not required to use an actual database but to read from and write to files. We have to do this through sockets. The files are on the server and the client gets or sends the data through the connection between the sockets.

There are different java files for the admins, the content admins and the users, each one containing the methods used by each user class. All these java files are on the client side.

I have the following questions.

  1. Is it correct that all the "logic" of the program (the .java files containing the methods) is on the client side?

  2. Do I have to use one socket for the server side and one for the client side? In that case, all methods from the different java files communicate and pass data through the one client socket.

  3. Different methods read from and write to different files. How do I tell the data passing through the socket from the client to the server, that it needs to be written to a specific file? (the same for reading from the appropriate file)

Two more specific examples.

a) There is a method that lets admins add users to the Users.txt file. The admin gives the userId (used to differentiate between admins, content admins and users), name, username and password as arguments to the addUser() method through the main method. How do I send the data through the socket and write them to the correct file? Is there a correspondind method on the server side that has a writer that writes the data to the file? Moreover, do I send the data all as a single line, or as different parts?

public void createUser(int userId, String name, String username, String password){

    try{

        PrintWriter Writer = new PrintWriter(new BufferedWriter(new FileWriter("Users.txt", true)));

        boolean appendToFile = true;

        if (appendToFile) {
            Writer.println(userId + " " + name + " " + username + " " + password);
        }

        System.out.println("The user "+getUsername()+" was created!");
        Writer.close();

        }

        catch (IOException e) {

        }

}

b) Another method enables the customer to search for films based on a keyword. We need to search each line of the Films.txt file (it has the structure filmId(int);filmCategory(enum);filmTitle(string);filmDesription;). The searchViewings() method sends the keyword that the user gave, through the socket, and on the server side it needs to search each line of the file for the keyword in the film titles. Again, is there a correspondind method that contains the logic for searching each line of the file? Else, how does the server side with only the keyword available knows what to do with it?

public void searchViewings(String keyword){

    File inputFile = new File("Provoles.txt");

    String currentLine = null;

    boolean flag = false;

    try{

        BufferedReader Reader = new BufferedReader(new FileReader(inputFile));

        System.out.println("The movies that contain the keyword '"+keyword+"' have the following available viewings:");

        while ((currentLine = Reader.readLine()) != null) {

            String s = currentLine;
            String delims = ";";
            String[] tokens = s.split(delims);

            if (tokens[1].indexOf(keyword) != -1){

                flag = true;

                System.out.println("The movie with Film ID '"+tokens[0]+"' and Film Title '"+tokens[1]+"' has an available viewing at the cinema with ID '"+tokens[2]+"'.");

            }

        }   

        if (flag == false){

            System.out.println("There is no movie containing the current keyword.");

        }

        Reader.close();

    }

    catch (IOException e) {

    }
}

The above code was like this before any socket was implemented.

  1. At last, is there an example that uses multiple files that I can read or run?

Is it correct that all the "logic" of the program (the .java files containing the methods) is on the client side?

No not really there has to be somelogic on the server side aswell, written in Java or in another language. Or else there is no way the server can read the file and do logic or send the file to the client.

Do I have to use one socket for the server side and one for the client side? In that case, all methods from the different java files communicate and pass data through the one client socket.

You don't have to, for this you will ofcourse need atleast one socket but you could also use more than one socket. For example a socket that the admins use and a socket that the clients use.

Different methods read from and write to different files. How do I tell the data passing through the socket from the client to the server, that it needs to be written to a specific file? (the same for reading from the appropriate file)

You could send a header through the socket saying something like: read/file1 or write/file4. Or something similar, the point is just sending some data telling the server what to do.

At last, is there an example that uses multiple files that I can read or run?

I don't have one as of this moment but I'll google a bit and update this later if I find one.

I hope this helps :)

To answer your first question, you can either store the app logic on the client (aka thick/fat client) or on the server (thin client). From what I know, there's no one exact answer to which is "better". It really depends on your app. Use thin client (logic stored on the server) if you want the majority of the processing to be done by the server (this is desired for devices with limited processing power, like smart phones). Use fat clients if you'd prefer to perform more of the processing on the clients or if you have limited bandwidth to access your server. There are many articles about fat vs thin clients. Here's one that you might find useful.

I'm a little rusty on sockets, so you might want to take the advice of the other answer, but from what I remember each client will have 1+ socket, and the server will also have 1+ (depending on how you choose to implement your connection) socket. Both client and server will use the same port number. See this article for some simple examples. When I experimented with them, I used ServerSocket for the server and Socket for the client. Check out the different examples in the above link for ideas. If you have additional questions, let me know and I'll do my best to elaborate.

Here's a simple project using sockets and files to read to and write from that I did a while ago. Hopefully viewing this code will clarify the questions you have with your own code. Due to the time constraints, I didn't convert it to include the code snippets you've provided, but if you're still stuck with your own code after taking a look at mine, I'll see what I can do.

A few things to note if you run this code:

  • This project uses server and client GUIs that are a little messy (I'm not very good at designing GUIs), but the functionality should still be useful.
  • You need to provide the same port number as a command line argument for both the server and client. You can do this in Eclipse via Run button dropdown -> Run configurations... -> arguments tab ->typing a port number (I used 12345) -> click run). Do this for both the server and client.
  • Make sure to run the server before you run the client
  • This example only reads from files. There's no writing functionality.
  • Once the client has successfully started, type the name of the file you want to read from (ie: readfile1.txt) including the file extension.
  • This uses relative path names starting from the root project directory so if your Users.txt file is in your src folder, you'd type "src/Users.txt".
  • Type the file name in the client's input field at the top of the client GUI to have the entire contents of that file printed below. You can type as many file names as you want one at a time.

Server code

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;


public class FileServer extends JFrame {
//main function
public static void main(String[] args) {
    int port = Integer.parseInt(args[0]);
    //String file = args[1];
    FileServer server = new FileServer(port);
    server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    server.runServer();
}

//FileServer class declarations
private File file; //for this example, the file is stored in the root project directory and includes the file extension (ie: .txt, etc)
private ServerSocket ss;
private Socket connection;
private JTextField field;
private JTextArea displayArea;
private int portNum;
private ObjectOutputStream oos;
private ObjectInputStream ois;

public FileServer(int port) {
    super("Server");
    //file = new File(f); //sent from client or done here?
    portNum = port;
    field = new JTextField();
    field.setEditable(false);
    field.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    sendData(event.getActionCommand());
                    field.setText("");
                }
            }); //ends addActionListener
    add(field, BorderLayout.NORTH);

    displayArea = new JTextArea();
    add(new JScrollPane(displayArea));

    setSize(500, 300);//size of JFrame
    setVisible(true);
}//end constructor

/**
 * code that executes the server obj.  Think of it as FileServer's main().  This is called from main().
 */
public void runServer() {
    try {
        ss = new ServerSocket(portNum, 100); //creates server socket with port # specified by user and a queue of 100
        while (true) { //infinite loop to continually listen for client connections
            try {
                waitForConnection(); //wait for client connections
                getStreams(); //get I/O streams
                processConnection(); 
            }
            catch (EOFException e) {
                e.printStackTrace();
            }
            finally {
                closeConnection();
            }
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}//end runServer

/**
 * creates socket obj to interact with client.  Socket created when connection with client made
 * @throws IOException 
 */
public void waitForConnection() throws IOException {
    displayMessage("Waiting for connection\n");
    connection = ss.accept(); //returns socket obj when connection made with client
    displayMessage("Connection made with " + connection.getInetAddress().getHostName());
}//end waitForConnection

/**
 * gets IO stream objs for FileServer class
 */
public void getStreams() {
    try {
        oos = new ObjectOutputStream(connection.getOutputStream());
        oos.flush();
        ois = new ObjectInputStream(connection.getInputStream());
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    displayMessage("\n Got both IO streams \n");
}//end getStreams

/**
 * receives filename sent from client and creates file
 */
public void processConnection() throws IOException {
    sendData("Connection successful");
    setTextFieldEditable(true);
    do { //added do while for testing
        try {
            String message = (String) ois.readObject(); //should read in filename then create file obj
            displayMessage("\n " + message + " received from client\n");
            displayMessage("Type in absolute path of file in text field above");
            file = new File(message);
            if(!file.exists()) {
                sendData("File not found");
            }
            else {
                Scanner cin = new Scanner(file);
                while(cin.hasNextLine()) {
                    message = cin.nextLine();
                    sendData(message);
                }
                cin.close();
            }

        }
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    } while(true);
}//end processConnection

/**
 * closes IO streams
 */
public void closeConnection() throws IOException {
    displayMessage("\nClosing connections\n");
    setTextFieldEditable(false); 
    oos.close();
    ois.close();
    connection.close();
}//end closeConnection

/**
 * sends message to client
 * @param message
 */
public void sendData(String message) {
    try{
        oos.writeObject(message);//this is what sends message
        oos.flush();
        displayMessage("\n in sendData: " + message + "\n");
    }
    catch(IOException e) {
        displayArea.append("\n Error writing object");
        e.printStackTrace();
    }
}//end sendData

public void displayMessage(final String message) {
    SwingUtilities.invokeLater(
            new Runnable() {
                public void run() {
                    displayArea.append(message);
                }
            });//end SwingUtilties
}

private void setTextFieldEditable( final boolean editable )
   {
      SwingUtilities.invokeLater(
         new Runnable() 
         {
            public void run() // sets enterField's editability
            {
               field.setEditable( editable );
            } // end method run
         } // end anonymous inner class
      ); // end call to SwingUtilities.invokeLater
   } // end method setTextFieldEditable

}

Client code

import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class FileClient extends JFrame 
{
    public static void main(String[] args) {
    int port = Integer.parseInt(args[0]);
    String fileName = args[1]; //must use absolute path for filename
    FileClient app = new FileClient("127.0.0.1", port, fileName);
    app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    app.runClient();
}

 private JTextField enterField; // enters information from user
 private JTextArea displayArea; // display information to user
 private ObjectOutputStream output; // output stream to server
 private ObjectInputStream input; // input stream from server
private String message = ""; // message from server
private String chatServer; // host server for this application
private Socket client; // socket to communicate with server
private int portNum;
private String fileName;
private File file;

// initialize chatServer and set up GUI
public FileClient( String host, int port, String fileName )
{
  super( "Client" );
  portNum = port;
  this.fileName = fileName;
  //file = new File(fileName);
  chatServer = host; // set server to which this client connectsS

  enterField = new JTextField(); // create enterField
  enterField.setEditable( false );
  enterField.addActionListener( //need to find a way to send fileName to server without having to type it in
     new ActionListener() 
     {
        // send message to server
        public void actionPerformed( ActionEvent event )
        {
           sendData( event.getActionCommand() );
           enterField.setText( "Messages will be displayed in other text box" );
        } // end method actionPerformed
     } // end anonymous inner class
  ); // end call to addActionListener

  add( enterField, BorderLayout.NORTH );

  displayArea = new JTextArea(); // create displayArea
  add( new JScrollPane( displayArea ), BorderLayout.CENTER );

  setSize( 500, 300 ); // set size of window
  setVisible( true ); // show window
} // end Client constructor

// connect to server and process messages from server
public void runClient() 
{
  try // connect to server, get streams, process connection
  {
     connectToServer(); // create a Socket to make connection
     getStreams(); // get the input and output streams
     processConnection(); // process connection
     sendData(fileName); //sends name of file to server to retrieve
     displayMessage("Sent request for " + fileName + " to server.");
  } // end try
  catch ( EOFException eofException ) 
  {
     displayMessage( "\nClient terminated connection" );
  } // end catch
  catch ( IOException ioException ) 
  {
     ioException.printStackTrace();
  } // end catch
  finally 
  {
     closeConnection(); // close connection
  } // end finally
} // end method runClient

// connect to server
private void connectToServer() throws IOException
{      
  displayMessage( "Attempting connection\n" ); //not getting here

  // create Socket to make connection to server
  client = new Socket( InetAddress.getByName( chatServer ), portNum );

  // display connection information
  displayMessage( "Connected to: " + 
     client.getInetAddress().getHostName() );
} // end method connectToServer

// get streams to send and receive data
private void getStreams() throws IOException
{
  // set up output stream for objects
  output = new ObjectOutputStream( client.getOutputStream() );      
  output.flush(); // flush output buffer to send header information

  // set up input stream for objects
  input = new ObjectInputStream( client.getInputStream() );

  displayMessage( "\nGot I/O streams\n" );
 } // end method getStreams

 // process connection with server
 private void processConnection() throws IOException //problem possibly due to processConnection being in infinite loop?
{
  // enable enterField so client user can send messages
  setTextFieldEditable( true );

  do // process messages sent from server
  { 
     try // read message and display it
     {
        message = input.readObject().toString(); // read new message
        displayMessage( "\n" + message ); // display message
     } // end try
     catch ( ClassNotFoundException classNotFoundException ) 
     {
        displayMessage( "\nUnknown object type received" );
        classNotFoundException.printStackTrace();
     } // end catch

  } while ( !message.equals( "SERVER>>> TERMINATE" ) );
} // end method processConnection

// close streams and socket
private void closeConnection() 
{
  displayMessage( "\nClosing connection" );
  setTextFieldEditable( false ); // disable enterField

  try 
  {
     output.close(); // close output stream
     input.close(); // close input stream
     client.close(); // close socket
  } // end try
  catch ( IOException ioException ) 
  {
     ioException.printStackTrace();
  } // end catch
} // end method closeConnection

// send message to server
private void sendData( String message ) //need to send filename to server
{
  try // send object to server
  {
     output.writeObject(message);
     //output.writeObject(fileName); //is writeObject the appropriate write method?
     output.flush(); // flush data to output
     displayMessage( "\nCLIENT>>> " + message );
  } // end try
  catch ( IOException ioException )
  {
     displayArea.append( "\nError writing object" );
     ioException.printStackTrace();
  } // end catch
} // end method sendData

// manipulates displayArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
  SwingUtilities.invokeLater(
     new Runnable()
     {
        public void run() // updates displayArea
        {
           displayArea.append( messageToDisplay );
        } // end method run
     }  // end anonymous inner class
  ); // end call to SwingUtilities.invokeLater
} // end method displayMessage

// manipulates enterField in the event-dispatch thread
private void setTextFieldEditable( final boolean editable )
{
  SwingUtilities.invokeLater(
     new Runnable() 
     {
        public void run() // sets enterField's editability
        {
           enterField.setEditable( editable );
        } // end method run
     } // end anonymous inner class
  ); // end call to SwingUtilities.invokeLater
} // end method setTextFieldEditable
} // end class Client

I hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM