Java套接字:如何根据事件从客户端向服务器发送多个文件

时间:2019-04-06 21:09:59

标签: java sockets

我正在编写一个程序,其中客户端需要监视特定文件夹中文件的创建并将其在创建时发送到服务器。服务器应始终处于侦听模式,并将这些文件以相同的名称保存在指定的文件中服务器上的文件夹。目前,我正在尝试在同一m / c上实现此目标。如何通过套接字实现此目标?

我能够监视客户端文件夹中文件的创建并将其发送。在接收者处,我只能接收一个文件。此后,我在服务器上收到FileNotFoundException。

客户代码

Socket sock = new Socket("localhost", 5991);  
        System.out.println("Connecting.........");

        Path faxFolder = Paths.get("C:\\Users\\Tushar Yadav\\Music\\src\\");
        WatchService watchService = FileSystems.getDefault().newWatchService();
        faxFolder.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

        boolean valid = true;
        do {

            WatchKey watchKey = watchService.take();

            for (WatchEvent event : watchKey.pollEvents()) {
                WatchEvent.Kind kind = event.kind();
                if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
                    String fileName = event.context().toString();
                    System.out.println("File Created:" + fileName);

                    File myFile = new File("C:\\Users\\Tushar Yadav\\Music\\src\\"+fileName);

                    OutputStream os = sock.getOutputStream();  
                    DataOutputStream dos = new DataOutputStream(os);

                    dos.writeUTF(fileName);

                    dos.writeInt((int) myFile.length());

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

                    Thread.sleep(10000);
                    FileInputStream fis = new FileInputStream(myFile.toString());  
                    BufferedInputStream bis = new BufferedInputStream(fis);  

                    int count; 
                    while ((count = fis.read(buffer)) > 0) {
                        dos.write(buffer, 0, count);
                    }   

                    dos.flush(); 

                }
            }
            valid = watchKey.reset();

        }while (valid);

服务器代码

ServerSocket serverSocket = new ServerSocket(5991);
        Socket clientSocket = null;
        clientSocket = serverSocket.accept();

        in = clientSocket.getInputStream();  
        clientData = new DataInputStream(in); 
        clientBuff = new BufferedInputStream(in); 

        while(true){

            System.out.println("Starting...");  

            String fileName = clientData.readUTF();     

            System.out.println("filename : "+fileName);

            int fileSize = clientData.read();

            System.out.println("filesize is "+fileSize);

            len=fileSize;

            System.out.println("C:\\Users\\Tushar Yadav\\Music\\dest\\"+fileName);

            output = new FileOutputStream("C:\\Users\\Tushar Yadav\\Music\\dest\\"+fileName);

            dos=new DataOutputStream(output);
            bos=new BufferedOutputStream(output);

            byte[] buffer = new byte[1024];  

            bos.write(buffer, 0, buffer.length); 

            while (len > 0 && (smblen = clientData.read(buffer)) > 0) { 
                dos.write(buffer, 0, smblen); 
                len = len - smblen;
                dos.flush();
            }  
            dos.close();  

        }

我希望服务器在客户端创建后立即等待客户端发送另一个文件,但是在接收者接收并保存第一个文件后不久,我将收到一个filenotfound异常。

此外,有一个观察结果是,在服务器端,我看到这行System.out.println("filename : "+fileName);和随后的行被执行两次,直到弹出异常,尽管只在客户端创建(并固有地发送)一个文件。

以下是服务器代码的日志:-

Starting...
filename : New Text Document.txt
filesize is 0
C:\Users\Tushar Yadav\Music\dest\New Text Document.txt
Starting...
filename : 
filesize is 0
C:\Users\Tushar Yadav\Music\dest\
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Tushar Yadav\Music\dest (Access is denied)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(Unknown Source)
    at java.io.FileOutputStream.<init>(Unknown Source)
    at java.io.FileOutputStream.<init>(Unknown Source)
    at test.Server.main(Server.java:55)

1 个答案:

答案 0 :(得分:0)

在客户端中,您使用writeInt()写入文件大小,但是在服务器中,您使用read()读取文件大小。您应该使用readInt()。因为read()仅读取4字节整数长度的第一个字节,所以这一切都会丢掉。那么您不会读取任何数据,因为您认为长度为0;那么当您尝试读取第二个文件的名称时,您就位置不对并读取了一个空字符串,这将导致您看到的错误。顺便说一句,使用writeLong()readLong()可能更合适,因为这是File.length()的返回类型,但这取决于您,特别是如果您只使用较小的文件。

您使用DataOutputStream dosBufferedOutputStream bos的方式似乎也有些不足,它们都包裹了相同的FileOutputStream output。首先,您要通过bos将完整的未初始化缓冲区写入文件(由于其中的一部分已经被缓冲,因此实际上可能只写入其中一部分);然后您将再次通过dos读取和写入实际文件数据,该数据将追加到先前写入output的内容之后。也许您的意思是类似dos = new DataOutputStream(new BufferedOutputStream(output))的东西,这将给您两者带来的好处。但是,您仍然不想像您那样在读取循环之前写入整个未初始化的缓冲区。

此外,由于您仅使用write(),因此可能不需要花哨的DataOutputStream就可以直接使用output.write()。如果您希望避免对磁盘进行频繁的小写操作,则BufferedOutputStream可以用作优化,但这不是必需的,特别是因为在读取/写入1Kb块的方式中存在一些固有的缓冲。