使用 ObjectStreams 通过套接字发送列表

Posted

技术标签:

【中文标题】使用 ObjectStreams 通过套接字发送列表【英文标题】:Using ObjectStreams to send Lists over sockets 【发布时间】:2022-01-15 22:26:26 【问题描述】:

我需要在节点之间传输一个 List 并将现有的 List 替换为新节点中的新 List 来实现这一点,我正在使用 Java 中的 Sockets。

我以某种方式设法传输了数据,但只有在我终止进程时。我需要它继续运行,该过程但同时传输数据,以防任何其他新节点加入列表。 我怎样才能做到这一点?我将不得不在下载过程中介绍线程。

我让它处理文件,但现在我需要将它更改为同步列表,仅此就足够了吗?

private static List<CloudByte> cloudByteList = Collections.synchronizedList(new ArrayList<>());

这是我当前的代码:

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static FileData.getCloudByteList;
import static FileData.getFile;

public class FileData 

    private static File file;
    private static String fileName;
    private static List<CloudByte> cloudByteList = Collections.synchronizedList(new ArrayList<>());

    public FileData(String fileName) throws IOException 
        if (fileName == null) 
            this.fileName = "data2.bin";
            this.file = new File(this.fileName);
            Download.downloadFile();
         else 
            this.file = new File(fileName);
            this.fileName = fileName;
            fillingList();
        
    

    public void fillingList() throws IOException 
        byte[] fileContents = Files.readAllBytes(file.toPath());
        for (int i = 0; i < fileContents.length - 1; i++) 
            cloudByteList.add(new CloudByte(fileContents[i]));
        
    

    public static List<CloudByte> getCloudByteList() 
        return cloudByteList;
    

    public static File getFile() 
        return file;
    

    public String getFileName() 
        return fileName;
    

    public static void setFile(File file) 
        FileData.file = file;
    

    /*--------------------------Download--------------------------*/



class Download extends Thread 
    static ConnectingDirectory connectingDirectory;

    @Override
    public void run() 
        try 
            downloadFile();
         catch (IOException e) 
            e.printStackTrace();
        
    

    public static void downloadFile() throws IOException 

        var nodes = ConnectingDirectory.getNodes();

        Socket socket = null;

        if (getFile().exists()) 
            System.out.println("File: " + getFile() + " exists.");
            new Upload().uploadFile();
        

        FileOutputStream fos = new FileOutputStream(FileData.getFile());
        //ObjectOutputStream oos = new ObjectOutputStream(fos);


        for (int i = 0; i < nodes.size() - 1; i++) 
            if (!(nodes.get(i).getHostPort() == ConnectingDirectory.getHostIP())) 
                System.out.println("test33123");

                ServerSocket serverSocket = new ServerSocket(nodes.get(i).getHostPort());
                System.out.println(serverSocket);
                socket = serverSocket.accept();
                System.out.println("now socket");
                System.out.println(socket);
                //socket = new Socket(nodes.get(i).getName(), nodes.get(i).getHostPort());
                //System.out.println(socket);
                int bytes = 0;
                DataInputStream ois = new DataInputStream(socket.getInputStream());
                long size = ois.readLong();
                System.out.println(size);
                byte[] buffer = new byte[100 * 10000];
                while (size > 0 && (bytes = ois.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) 
                    System.out.println("test3333");
                    fos.write(buffer, 0, bytes);
                    size -= bytes;
                
            
        
    


/*--------------------------Upload--------------------------*/

class Upload 

    public void uploadFile() throws IOException 
        int bytes = 0;
        var nodes = ConnectingDirectory.getNodes();

        FileInputStream fileInputStream = new FileInputStream("data.bin");
        DataInputStream ois = new DataInputStream(fileInputStream);

        if (!getFile().exists()) 
            System.out.println("File doesn't exist." + "\nDownloading the file!");
            new Download().downloadFile();
        
        System.out.println("hello");
        for (int i = 0; i < nodes.size() - 1; i++) 
            System.out.println("hello2");
            Socket socket = new Socket(nodes.get(i).getName(), nodes.get(i).getHostPort());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            dos.writeLong(new File("data.bin").length());
            byte[] buffer = new byte[100 * 10000];
            while ((bytes = ois.read(buffer)) != -1) 
                dos.write(buffer, 0, bytes);
                dos.flush();
            
        
    

如您所见,我使用 DataInput 是因为如果我尝试使用 ObjectInputStream,则会收到损坏的标头异常。我有更多的课程要添加。正如我所说,我的目标是将“data.bin”中的数据传输到“data2.bin”文件中。我可以创建和删除它,但同时没有数据被写入/发送给它。 如何修复 CorruptedHeaderException 并让它发送内容? 感谢所有帮助。

StorageNode 类:

import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Pattern;

import static FileData.*;

public class StorageNode extends Thread 

private static int serverPort = 8080;
private static int clientPort = 8082;
private static String fileName = null;
private static String addressName = "localhost";


private static ConnectingDirectory connectingDirectory;
private static FileData fileData;
static ErrorInjection errorInjection;

public static void main(String[] args) throws IOException, InterruptedException 

   /* if (args.length > 3) 
        addressName = args[0];
        serverPort = Integer.parseInt(args[1]);
        clientPort = Integer.parseInt(args[2]);
        fileData = new FileData(args[3]);
     else 
        fileName = null;
        fileData = new FileData(fileName);
    */
    connectingDirectory = new ConnectingDirectory(addressName, clientPort, serverPort);
    fileData = new FileData(fileName);
    errorInjection = new ErrorInjection();
    errorInjection.start();
    if(fileData.getFile().exists())
        new Upload().uploadFile();
    else 
        new Download().downloadFile();
    

连接目录类

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class ConnectingDirectory 

    private String hostName;
    private static int hostIP;
    private int directoryIP;
    private InetAddress address;
    private InputStream in;
    private OutputStream out;
    private static List<Nodes> nodes = new ArrayList<>();
    List<String> nodess = new ArrayList<>();
    private Socket socket;
    private String sign = "INSC ";


    public ConnectingDirectory(String hostName, int hostIP, int directoryIP) throws IOException 
        this.hostName = hostName;
        this.hostIP = hostIP;
        this.directoryIP = directoryIP;
        this.address = InetAddress.getByName(hostName);
        this.socket = new Socket(address, directoryIP);
        signUp();
        askConnectedNodes();
    

    public void signUp() throws IOException 
        System.out.println("You are connecting to the following address: " + hostIP + "\n");
        System.out.println("The port you are connected to: " + socket.getPort() + "\n");
        in = socket.getInputStream();
        out = socket.getOutputStream();
        out.write(generateSignUp(address, hostIP).getBytes());
        out.flush();
    

    public String generateSignUp(InetAddress address, int hostIP) 
        String signUpString = sign + address + " " + hostIP + "\n";
        return signUpString;
    

    public void askConnectedNodes() throws IOException 
        String directoryNodesAvailable;
        String a = "nodes\n";
        out.write(a.getBytes());
        out.flush();
        Scanner scan = new Scanner(in);

        while (true) 
            directoryNodesAvailable = scan.nextLine();
            addExistingNodes(directoryNodesAvailable);
            //System.out.println("Eco: " + directoryNodesAvailable);
            if (directoryNodesAvailable.equals("end")) 
                out.flush();
                printNodes();
                break;
            
        
    

    public void addExistingNodes(String sta) throws IOException 
        if (sta.equals("end")) return;
        if (!(nodess.contains(sta))) 
            nodess.add(sta);
            nodes.add(new Nodes(nodess.get(nodess.size() - 1)));
        
        return;
    

    public static List<Nodes> getNodes() 
        return nodes;
    

    public void printNodes() 
        System.out.println("Checking for available nodes: \n");
        nodes.forEach((z) -> System.out.println(z.getNode()));
    

    public Socket getSocket() 
        return socket;
    

    public static int getHostIP() 
        return hostIP;
    

    public InetAddress getAddress() 
        return address;
    

【问题讨论】:

请将解决方案发布为答案。不要改变问题 【参考方案1】:

对于所有未来需要帮助的人:

发送方:

Socket socket = new Socket("localhost", hostPort);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ByteBlockRequest bbr = new ByteBlockRequest(getStoredData());
objectOutputStream.writeObject(bbr.blocksToSend(j));

接收方:

Socket = StorageNode.getServerSocket().accept();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
byte[] bit = (byte[]) ois.readObject();

在我的情况下,我需要使用 byte[],所以我必须在后面做一些额外的函数,将 Cloudbyte[] 更改为 byte[]。一旦我这样做了,我就能够使用 ObjectInput/ObjectOutput 发送数据。

【讨论】:

以上是关于使用 ObjectStreams 通过套接字发送列表的主要内容,如果未能解决你的问题,请参考以下文章

使用 gen_tcp:send/2 通过套接字发送消息

通过套接字流发送对象

通过 Unix 域套接字发送结构

使用 C 中的套接字通过 TCP 发送音频文件

如何让 libcurl 不监听套接字只是通过它发送一个 url 请求?

使用 Qt 通过 TCP 套接字部分发送 xml 消息