将请求发送到服务器java

时间:2013-01-06 18:13:13

标签: java

我为服务器和客户端编写了一些代码,用于将文件从服务器传输到客户端,它就像一个魅力;但是我几乎没有问题。我想在GUI下构建这个代码,我想列出文件夹中的所有文件,但是如何让客户端在看到提供的文件列表后选择他想要的文件(如何将字符串发送到服务器为了选择文件)?

服务器代码

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



class TCPServer {

    public static void listfile(){

    File folder = new File("c:/");
    File[] listOfFiles = folder.listFiles();

    for (int i = 0; i < listOfFiles.length; i++) {
      if (listOfFiles[i].isFile()) {
        System.out.println("File " + listOfFiles[i].getName());
      } else if (listOfFiles[i].isDirectory()) {
        System.out.println("Directory " + listOfFiles[i].getName());
      }
    }
  }


    public static void main(String args[]) {

        listfile();

        while (true) {
            ServerSocket welcomeSocket = null;
            Socket connectionSocket = null;
            BufferedOutputStream outToClient = null;

            try {
                welcomeSocket = new ServerSocket(3248);
                connectionSocket = welcomeSocket.accept();
                outToClient = new BufferedOutputStream(connectionSocket.getOutputStream());
            } catch (IOException ex) {
                // Do exception handling
            }


            if (outToClient != null) {

                String FileName = "carexception.java";

                File myFile = new File("C:\\"+FileName);

                byte[] mybytearray = new byte[(int) myFile.length()];

                FileInputStream fis = null;

                try {
                    fis = new FileInputStream(myFile);
                } catch (FileNotFoundException ex) {
                    // Do exception handling
                }
                BufferedInputStream bis = new BufferedInputStream(fis);

                try {
                    bis.read(mybytearray, 0, mybytearray.length);
                    outToClient.write(mybytearray, 0, mybytearray.length);
                    outToClient.flush();
                    outToClient.close();
                    connectionSocket.close();

                    // File sent, exit the main method
                    return;
                } catch (IOException ex) {
                    // Do exception handling
                }
            }

        }
    }
}

客户代码

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

class TCPClient {

    public static void main(String args[]) {
        Scanner s = new Scanner(System.in);
        byte[] aByte = new byte[1];
        int bytesRead;

        Socket clientSocket = null;
        InputStream is = null;

        try {
            clientSocket = new Socket("127.0.0.1", 3248);
            is = clientSocket.getInputStream();
        } catch (IOException ex) {
            // Do exception handling
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        if (is != null) {

            FileOutputStream fos = null;
            BufferedOutputStream bos = null;
            try {
                fos = new FileOutputStream("E:\\sss.java");
                bos = new BufferedOutputStream(fos);
                bytesRead = is.read(aByte, 0, aByte.length);

                do {
                        baos.write(aByte);
                        bytesRead = is.read(aByte);
                } while (bytesRead != -1);

                bos.write(baos.toByteArray());
                bos.flush();
                bos.close();
                clientSocket.close();
            } catch (IOException ex) {
                // Do exception handling
            }
        }
    }
}

4 个答案:

答案 0 :(得分:2)

要完成你必须改变的东西之后的事情。

您可以假定特定的协议顺序,即客户端需要向服务器发送请求以便服务器执行任何操作,因此服务器在建立连接时始终处于侦听状态。

你应该,

  1. 介绍发送请求和接收回复的循环
  2. 弄清楚如何发送字符串对象
  3. 分解文件发送部分,这样你就不会分配比操作系统可以提供给你更大的字节数组(例如,考虑一个4GB的文件,为整个文件分配一个字节数组可能很麻烦)。
  4. 所以,考虑到这一点,我们可以开始。关于步骤1,这可以使用while循环来完成。如果我们假设服务器总是侦听请求,那么服务器“请求循环”可能看起来像这样。

    ClientRequest request;
    while (request.getType() != RequestType.Complete) {
        // receive new request
        // depending on type, send response
    }
    

    我们在这里添加了两个类,一个ClientRequest封装了来自客户端的消息,一个枚举RequestType定义了客户端感兴趣的请求类型,例如文件列表或文件内容。

    public enum RequestType {
       None, Complete, RequestFileList, RequestFileContent
    }
    
    public class ClientRequest {
       private RequestType type;
       public ClientRequest() {
           type = RequestType.None;
       }
    
       public RequestType getType() {
           return type;
       }
    }
    

    现在我们需要以某种方式将它附加到套接字,因此我们添加了一个接收请求的方法,并将该请求分配给当前请求实例。

    ClientRequest request = new ClientRequest();
    while (request.getType() != RequestType.Complete) {
        // receive new request
        receiveRequest(clientSocket.getInputStream(), request);
        if (request.getType() != RequestType.Complete) {
            // pick a response
        }
    }
    
    private void receiveRequest(DataInputStream socketStream, ClientRequest request) {
        // get a type of request
        byte type = socketStream.readByte();
        request.setType(RequestType.from(type));
        // get parameters for request, depending on type
        if (request.getType() == RequestType.RequestFileContent) {
            // receive file id (file name for instance, or some other id that you prefer)
            String argument = readString(socketStream);
            request.setArgument(argument);
        }
    }
    

    这会在RequestType中添加from方法,将字节转换为请求,setType中的ClientRequest方法和readString方法。我们还在ClientRequest中添加了一个新字段和相应的get和set方法。

    public enum RequestType {
        // types as before
        ;
        public static RequestType from(byte b) {
            switch (b) {
                case 1: return RequestType.Complete;
                case 2: return RequestType.RequestFileList;
                case 3: return RequestType.RequestFileContent;
                default: return RequestType.None;
             }
        }
    }
    
    public class ClientRequest {
        private String argument;
        public void setType(RequestType value) {
            type = value;
        }
    
        public String getArgument() {
            return argument;
        }
    
        public void setArgument(String value) {
            this.argument = value;
        }
    }
    
    private String readString(DataInputStream socketStream) {
        int length = socketStream.readInt();
        byte[] stringBytes = new byte[length];
        socketStream.read(stringBytes);
        return new String(stringBytes, "UTF-8");
    }
    

    现在我们进入下一步,回应请求。只需添加一个开关盒并处理请求类型。

    {
        // depending on type, send response
        handleRequest(clientSocket.getOutputStream(), request);
    }
    
    private void handleRequest(DataOutputStream socketStream, ClientRequest request) {
        switch (request.getType()) {
            case RequestType.RequestFileList: {
                String[] fileList = getFileList(getCurrentDirectory());
                // send response type
                socketStream.write(ResponseType.ResponseFileList.getByte());
                // send number of files
                socketStream.writeInt(fileList.length);
                // send each string
                for (String fileName : fileList) {
                    sendString(socketStream, fileName);
                }
            }
            break;
            case RequestType.RequestFileContent: {
                // send response type ResponseType.ResponseFileContent
                // send length of file so other party can determine number of bytes to receive
                // send file contents in chunks of a fixed byte array length
                // send last part of file contents, if length of file is not evenly divided by array chunk size
            }
            break;
        }
    }
    

    sendString方法只是readString方法的“颠倒顺序”。

    private void sendString(DataOutputStream socketStream, String value) {
        int length = value.length();
        socketStream.writeInt(length);
        byte[] stringBytes = value.getBytes("UTF-8");
        socketStream.write(stringBytes);
    }
    

    ResponseType是一个类似于RequestType中的值的枚举,因此客户端可以处理服务器发送的响应类型。

    通过这些更改,您将能够请求文件列表并显示服务器发送的文件的响应。当用户选择要接收的文件时,客户端可以向服务器发送新请求,服务器可以将适当的文件内容发送给客户端。

    客户端应用程序必须使用服务器指定用于读取和写入套接字流的相应方法来定义类似的ClientRequest类(可能名称为ServerResponse)。这可以通过将套接字封装在一个类中来进一步抽象,并在接收到GUI可以订阅的请求或响应时使用侦听器模式,但这超出了我的范例。

    如果您觉得我需要澄清任何内容,请发表评论,我会尽力回答。

答案 1 :(得分:1)

你怎么问文件?按名字!我认为服务器接受命令并响应响应。您可以使用服务器命令的格式:CMD_NAME,arg1,arg2,...参数可以是二进制,取决于命令。通过CMD_NAME,您的服务器将区分您想要的内容(接受文件或提供文件)。

您遇到的问题是您只接受一种类型的请求。您需要一个命令机制来询问来自服务器的不同请求。服务器需要解析这些请求,而不是立即提供硬编码的答案。这将使其变得灵活。

http://www.javamex.com/tutorials/networking/simple_server_s_side.shtml我确信还有很多这样的例子。 Java套接字是可靠的,不会有问题。刚开始学习基础知识,如何在客户端和服务器之间传递不同的消息。但是,你的问题根本不是套接字相关的。想象一下,您通过文件进行通信:从一个读取请求并将响应写入另一个。那你写了哪些消息?这称为协议。你需要设计一个简单的。

答案 2 :(得分:0)

您是否尝试过创建数组,因此每个文件都有自己的索引...当客户端选择他想要的文件时,则返回某个数组索引上的文件。

〜顺便说一句,您可以序列化您的数组并将其发送给客户端。

答案 3 :(得分:0)

您可以使用ObjectOutputStream通过Object发送字符串或任何其他类型的writeObject