简体   繁体   中英

Java Server/Client socket stops responding

I am having trouble with my client/server program. The server is supposed to get a file from the client then convert it to xml, and then stream the xml file back to the client.

As of now everything works up to the point of streaming the xml file back to the client. I can successfully send my file to the server and convert it to XML.

The server does not send anything to the client. The client is stuck in the area of reading bytes in from the InputStream. On line 57 in the Client class.

public class Server {    
    private ServerSocket serverSocket;
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;

    public static void main(String[] args) { 

        int port = 8081;
        Server srv = new Server(port);
    }

    public Server(int portNumber) {
        try {
            serverSocket = new ServerSocket(portNumber);
            clientSocket = serverSocket.accept();

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


            byte[] myArray = new byte[22000]; // should be file size
            InputStream is = clientSocket.getInputStream();
            FileOutputStream fos = new FileOutputStream("file.csv");
            BufferedOutputStream bos = new BufferedOutputStream(fos);

            int bytesRead;
            int current = 0;


            bytesRead = is.read(myArray, 0, myArray.length);
            current = bytesRead;

            do {
                bytesRead = is.read(myArray, current, (myArray.length - current) );
                if (bytesRead >= 0)
                    current += bytesRead;
            } while (bytesRead > -1);

            bos.write(myArray, 0, myArray.length);
            bos.flush();
            boolean flag = false;
            System.out.println("Server: finished receiving file");



            XMLWriter xmlWrite = new XMLWriter();
            xmlWrite.createXmlDocument("file_copy.csv");

            sendXML("server_file.XML");



            clientSocket.close();
            System.out.println("Server: disconnected with client");


        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void sendXML(String fileName) {

        System.out.println("Sending file");
            File file = new File(fileName);
    BufferedInputStream bis;
    try {
        FileInputStream fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        DataInputStream dataIn = new DataInputStream( bis );
        OutputStream outStream = clientSocket.getOutputStream();
        int length;
        try {
            length = dataIn.readInt();
            System.out.println("S: " + dataIn.readInt());
            byte[] data = new byte[ length ];
            dataIn.readFully(data, 0, data.length);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

}


public class Client {

    private Socket mainSocket;

    public static void main(String[] args) { 

        int port = 8081;
        Client cli = new Client(port);
    }

    public Client(int portNumber) {

        try {
            mainSocket = new Socket("localhost", portNumber);

            // send file to server
            File file = new File("Passengers.csv");
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            OutputStream outStream = mainSocket.getOutputStream();

            byte[] myBytes = new byte[(int) file.length()];

            bis.read(myBytes, 0, myBytes.length);
            outStream.write(myBytes, 0, myBytes.length);
            outStream.flush();

            System.out.println("Client: Done sending file");

                        byte[] fileData = new byte[30000];
        InputStream is = mainSocket.getInputStream();
        FileOutputStream fos = new FileOutputStream("client_file.XML");
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        DataOutputStream dataOut = new DataOutputStream( bos );
        dataOut.writeInt( fileData.length );
        dataOut.write( fileData ); 


        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    }

This loop will run until the stream is closed, not until the client finishes sending data.

do {
    bytesRead = is.read(myArray, current, (myArray.length - current) );
    if (bytesRead >= 0)
        current += bytesRead;
} while (bytesRead > -1);

This is because InputStream.read will block until at least one byte of data is available or the stream is closed, causing a -1 to be returned. Since the client is done sending data but the stream is still open it will block forever.

A solution is to first send the length of the file in the first 4 bytes using something like DataOutputStream / DataInputStream , and then have the client send exactly that many bytes and the server read exactly that many bytes before moving on.

Client:

// Connect to the server and read in file data
byte[] fileData = ...;
DataOutputStream dataOut = new DataOutputStream( outStream );
dataOut.writeInt( fileData.length );
dataOut.write( fileData );
// Get reply from server

Server:

// Create ServerSocket and get Client connection
DataInputStream dataIn = new DataInputStream( is );
int length = dataIn.readInt();
byte[] data = new byte[ length ];
dataIn.readFully( data );
// Continue to process client connection

The general idea behind this kind of network communication is that every block of data, or packet, is prefixed with it's length before being send. This means that the recipient of the data can read in that number and know exactly how many bytes remain to form the complete block or packet. Communication goes along something like this for both sides of the connection. The only difference is in how you process the data.

public byte[] readPacket( DataInputStream dataIn ) throws IOException {
    int length = dataIn.readInt();
    byte[] packet = new byte[ length ];
    dataIn.readFully( packet );
    return packet;
}

public void writePacket( DataOutputStream dataOut, byte[] packet ) throws IOException {
    dataOut.writeInt( packet.length );
    dataOut.write( packet );
}

Only you would call these from some sort of loop preferably on background threads but it's not required for what you want to do. For your case you want to read in the file on the client side into a byte[] and then use writePacket to send it to the server. On the server side you would use readPacket to read in the file from the client. The same thing takes place when sending data back to the client but with the roles switched.

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