简体   繁体   中英

Java Socket request handling

I'm attempting to write a simple file transfer program using the Java Socket and ServerSocket libraries. I've used these libraries successfully once before, but in this case I seem to have a problem getting the server side to slow down long enough once the connection is made in order for the client side to make a request. The problem appears to be happening as the main method on the server side enters the second while loop, calls handleRequest() , and once in handleRequest() , throws a SocketExeption error when it tries to read in the client's request. The program does not pause long enough to allow the user on the client side to send a request. I've tried moving code around within the main's second while loop to no avail. Any help in getting the server side to slow down and listen would be greatly appreciated. Thanks!

Edit: Here's the exceptions thrown:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
    at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
    at sun.nio.cs.StreamDecoder.read(Unknown Source)
    at java.io.InputStreamReader.read(Unknown Source)
    at java.io.BufferedReader.fill(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at FTServe.handleRequest(FTServe.java:92)
    at FTServe.main(FTServe.java:218)

End Edit

Here's my code:

Server side

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


public class FTServe {
    BufferedReader stdIn;
    static BufferedReader in = null;
    static PrintWriter out = null;
    static ServerSocket serverSocket;

    FTServe() {
    }

    /**********************************************************
     * Desc: starts on host A, validates the parameter, and waits on port 
     * 30021 for client request
     * Parameters:
     * Returns:
     * @param portNum 
     **********************************************************
     */
    private Socket startUp(int portNum) throws IOException {
        serverSocket = null;
        Socket clientSocket = null;

        //server to listen on port 30021
        //ftserve starts on host A, and validates the command-line parameters.

        try {
            serverSocket = new ServerSocket(portNum);
            System.out.println("Waiting for client....");
        } catch (IOException e) {
            System.err.println("Could not listen on port: " + portNum);
            System.exit(1);
        }

        //waits for client message and accepts connection (client IP address and port)
        try {
            clientSocket = serverSocket.accept();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }
        return clientSocket;
    }

    /**********************************************************
     * Desc: accepts, interprets and handles client requests
     * Parameters:
     * Returns:
     * @param server 
     * @param server 
     * @throws IOException 
     **********************************************************
     */
    public static void handleRequest(FTServe server) throws IOException {

        Socket dataSocket = null;
        String message = in.readLine();
        if (message != null) {
            if (message.equalsIgnoreCase("list")) {
                int portNum = 30020;
                dataSocket = server.startUp(portNum);
                sendDirectory();
            }
            else if (message.contains("get <")) {
                int j = 0;
                String requestedFile = null;
                char letter;
                String prefix = "get <";
                requestedFile = message.substring(message.indexOf(prefix + prefix.length(), message.length()-2));
                //open port 30020 to send data to client
                dataSocket = server.startUp(30020);
                sendFile(dataSocket, requestedFile);    
            }
            else {
                out.println("Invalid command. Please enter 'list' or 'get <filename>:  ");
            }

            dataSocket.close();
        }
    }

    /**********************************************************
     * Desc: sends list of files in directory to client
     * Parameter: String requestedFile, Socket dataSocket
     * Returns: 
     * @param dataSocket 
     * @param requestedFile 
     * @throws IOException 
     **********************************************************
     */
    private static void sendDirectory() {
        String path = new File(".").getAbsolutePath();
        File dir = new File(path);
        File[] listFiles = dir.listFiles();

        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isFile()) {
                String fileName = listFiles[i].getName();
                out.print(fileName + "     ");
            }
        }
    }

    /**********************************************************
     * Desc: sends file to client on port 30020
     * Parameter: String requestedFile, Socket dataSocket
     * Returns: 
     * @param dataSocket 
     * @param requestedFile 
     * @throws IOException 
     **********************************************************
     */
    private static void sendFile(Socket dataSocket, String requestedFile) throws IOException {
        File sendFile = new File(requestedFile);
        if (sendFile.isFile()){
            byte[] fileByteArray = new byte[(int) requestedFile.length()];

            FileInputStream fis = new FileInputStream(requestedFile);
            BufferedInputStream bis = new BufferedInputStream(fis);

            DataInputStream dis = new DataInputStream(bis);
            dis.readFully(fileByteArray, 0, fileByteArray.length);

            //opens output stream and sends file info and file to the client
            OutputStream os = dataSocket.getOutputStream(); 
            DataOutputStream dos = new DataOutputStream(os);
            dos.writeUTF(sendFile.getName());           
            dos.writeLong(fileByteArray.length);
            dos.write(fileByteArray, 0, fileByteArray.length);
            dos.flush();
        }
        else out.println("That is not a valid filename.");
    }

    /***********************************************************
     * Desc: closes server socket
     * Parameter: serverSocket
     **********************************************************
     */
    private void closeSocket(ServerSocket serverSocket) throws IOException {
        serverSocket.close();
    }

    /***********************************************************
     * Desc: Main method
     **********************************************************
     */
    public static void main(String[] args) throws IOException {
        int goodbye = 0; //if goodbye == 1, close client connection; if goodbye == -1, close server socket

        while (goodbye != -1) {
            goodbye = 0;
            FTServe server = new FTServe();
            Socket socket = null;
            int portNum = 30021;

            socket = server.startUp(portNum);

            String message;

            System.out.println("When you wish to disconnect from client, simply enter 'bye'. \nTo close socket, enter 'exit'.");
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); 

            System.out.println("Connection from " + socket.getLocalAddress().getHostName() + " successful.  \n\nWaiting on client...");

            //gets inputs and outputs from client
            out = new PrintWriter(socket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            while (goodbye == 0) {

                server.handleRequest(server);

                //close connection to client if goodbye == 1 because server entered bye
                if (goodbye == 1) {
                    System.out.println("Connection to client closing...");
                    out.println("Connection to client closing...Goodbye");
                    in.close();
                    out.close();
                    socket.close();
                    server.closeSocket(serverSocket);
                }
            }

            //server.startUp();
            System.out.println("Enter 'exit' to close, else enter 'go' to continue listening for client. When server is listening, Ctrl-C will end program");
            System.out.print("Server> ");
            if (stdIn.readLine().equals("exit")) {
                server.closeSocket(serverSocket); 
                goodbye = -1;
            }
        }

        System.out.println("The program is closing. Goodbye!");
    }
}

Client side

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


public class FTClient {

    static BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter out = null;
    static BufferedReader in = null;
    FTClient() {
    }

    /**********************************************************
     * Desc: initiates contact with server
     * Parameter: iPadd == server IP address, portNum == server port
     * Returns: Client socket
     **********************************************************
     */
    private Socket initiateContact (String iPadd, int portNum) throws IOException {
        Socket clientSocket = null;
        //ftclient starts on host B, and validates the command-line parameters.
        try {
            //create connection between client and server           
            clientSocket = new Socket(iPadd, portNum);
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: " + iPadd + ".");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to: " + iPadd + ".");             
            System.exit(1);
        } 
        return clientSocket;
    }

    /**********************************************************
     *Desc: sends client message to server
     *Parameter: String msg
     *Returns: Boolean true if client message == bye, else false
     **********************************************************
     */
    private boolean sendMessage(String fromUser) throws IOException {   

        if (fromUser.equals("bye")) {
            out.println("Client> " + fromUser);
            return true;
        }
        else if (fromUser != null) out.println("Client> " + fromUser);
        return false;
    }


    /**********************************************************
     * Desc: sends client command: 'list or get <filename>'
     * Parameters:
     * Returns:
     * @param request 
     * @return 
     * @throws IOException 
     **********************************************************
     */
    private boolean makeRequest(String request) throws IOException {
        //ftclient sends a command (list  or get <filename>) on connection to port 30020.
        if (request.equals("bye")) {
            out.println(request);
            return true;
        }
        else if (request != null) out.println(request);
        return false;
    }

    /**********************************************************
     * Desc: saves the file in the current default directory (handling "duplicate file name" error if necessary), 
     * and displays a "transfer complete" message on-screen or sends an appropriate error message 
     * (“File not found”, etc.) to ftclient on connection P, and ftclient displays the message on-screen.
     * Parameters:
     * Returns:
     * @return 
     * @throws IOException 
     **********************************************************
     */
    private void receiveFile()
    {
        //code remains to be written
    }

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        FTClient client = new FTClient();
        boolean goodbye = false;
        Socket socket, datasocket;
        String iPadd = args[0];
        String port = args[1];
        int portNum = Integer.parseInt(port);

        //initate contact with server
        socket = client.initiateContact(iPadd, portNum);

        System.out.println("When you wish to exit, simply enter 'bye'.");

        out = new PrintWriter(socket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        //client sends request, then initiates contact with data socket to receive data
        while (!goodbye) {
            System.out.println("Server> Enter 'list' to display a directory of files. \nEnter 'get <filename>' to retrieve a file.  " +
                    "\nPlease enter a command: ");
            String request = stdIn.readLine();
            goodbye = client.makeRequest(request);
            int dataPort = 30020;
            Socket dataSocket = client.initiateContact(iPadd, dataPort);
            client.receiveFile();

        }

    }

}

You are trying to create a serversocket everytime.

What you should be doing is on start up create a thread to handle socket acceptances. The thread that handles acceptances should then hand off any client to another thread.

something like

public ServerSocketProcessor implements Runnable{

    private boolean execute;
    private int commandPortNumber;
    private int dataPortNumber;

    public ServerSocketProcessor(int commandPortNumber, int dataPortNumber, SocketHandler socketHandler){
        this.commandPortNumber= commandPortNumber;
        this.dataPortNumber= dataPortNumber;
        this.socketHandler = socketHandler;
    }

    public void run(){
        this.execute = true;
        try{
           // only ever want one server socket and keep it running for lifetime
           // of your program
           ServerSocket commandServerSocket = new ServerSocket(this.commandPortNumber);
           ServerSocket dataServerSocket = new ServerSocket(this.dataPortNumber);
           try {
               // keep running until another process says to stop
               while(this.execute){
                   // accept will cause the server socket to wait until
                   // a connection is made
                   Socket commandSocket = commandServerSocket .accept();
                   // handle new connection then go back to waiting for a new
                   // connection.
                   Socket dataSocket = dataServerSocket.accept();
                   socketHandler.handle(commandSocket, dataSocket);
               }
           } finally{
               serverSocket.close();
           }
        } catch (exception e){
            // do something
        }
    }

}

SocketHandler just creates threads to handle the incoming connection

public class SocketHandler{

    public void handle(Socket commandSocket, Socket dataSocket){
         // create thread to handle socket
    }

}

client side

public static void main(String[] args) throws IOException {
    FTClient client = new FTClient();
    boolean goodbye = false;
    Socket socket, datasocket;
    String iPadd = "127.0.0.1";
    String port = "30021";
    int portNum = Integer.parseInt(port);

    //initate contact with server
    socket = client.initiateContact(iPadd, portNum);

    System.out.println("When you wish to exit, simply enter 'bye'.");

    out = new PrintWriter(socket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    //client sends request, then initiates contact with data socket to receive data
    while (!goodbye) {
      System.out.println("Server> Enter 'list' to display a directory of files. \nEnter 'get <filename>' to retrieve a file.  " +
              "\nPlease enter a command: ");
      String request = stdIn.readLine();
      goodbye = client.makeRequest(request);
    }
    client.cleanUp(); // in this you should close any datastreams and close the socket

  }

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