通过套接字传输多个文件问题

时间:2014-05-11 11:52:56

标签: java

服务器端:

public class Server 
{
public static final String ALGORITHM = "RSA";
public static final String PRIVATE_KEY_FILE = "C:/Users/mrarsenal10/Desktop/server/key/private.key";
public static final String PUBLIC_KEY_FILE = "C:/Users/mrarsenal10/Desktop/server/key/public.key";
public static void generateKey() 
{
    try 
    {
        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
        keyGen.initialize(1024);
        final KeyPair key = keyGen.generateKeyPair();

        File privateKeyFile = new File(PRIVATE_KEY_FILE);
        File publicKeyFile = new File(PUBLIC_KEY_FILE);

    // Create files to store public and private key
        if (privateKeyFile.getParentFile() != null) {
            privateKeyFile.getParentFile().mkdirs();
        }
        privateKeyFile.createNewFile();

        if (publicKeyFile.getParentFile() != null) {
           publicKeyFile.getParentFile().mkdirs();
        }
        publicKeyFile.createNewFile();

        // Saving the Public key in a file
        ObjectOutputStream publicKeyOS = new ObjectOutputStream(
        new FileOutputStream(publicKeyFile));
        publicKeyOS.writeObject(key.getPublic());
        publicKeyOS.close();

        // Saving the Private key in a file
        ObjectOutputStream privateKeyOS = new ObjectOutputStream(
        new FileOutputStream(privateKeyFile));
        privateKeyOS.writeObject(key.getPrivate());
        privateKeyOS.close();
    }catch (Exception e) 
    {
        e.printStackTrace();
    }
}
public static boolean areKeysPresent() 
{
    File privateKey = new File(PRIVATE_KEY_FILE);
    File publicKey = new File(PUBLIC_KEY_FILE);

    if (privateKey.exists() && publicKey.exists())
    {
      return true;
    }
    return false;
}
public static String decrypt(byte[] text, PrivateKey key) { // giải mã
    byte[] dectyptedText = null;
    try {
    // get an RSA cipher object and print the provider
    final Cipher cipher = Cipher.getInstance(ALGORITHM);

    // decrypt the text using the private key
    cipher.init(Cipher.DECRYPT_MODE, key);
    dectyptedText = cipher.doFinal(text);

    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return new String(dectyptedText);
}
static void sendFile(Socket sock, String fName) throws FileNotFoundException, IOException
{
    File transferFile = new File (fName);
    byte [] bytearray = new byte [(int)transferFile.length()]; 
    FileInputStream fin = new FileInputStream(transferFile); 
    BufferedInputStream bin = new BufferedInputStream(fin); 
    bin.read(bytearray,0,bytearray.length); // luu  vao bytearray
    OutputStream os = sock.getOutputStream(); // goi outputstream de
    System.out.println("Sending Files..."); 
    os.write(bytearray,0,bytearray.length); 
    os.flush();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
    if (!areKeysPresent()) {
        generateKey();
    }
    ServerSocket serverSocket = new ServerSocket(15124); 
    Socket sock = serverSocket.accept();   
    sendFile(sock, PUBLIC_KEY_FILE);
    sendFile(sock, "lich.txt");
    sock.close();
}
}

客户方:

public class Client
{
public static final String ALGORITHM = "RSA";
public static final String PUBLIC_KEY_FILE = "C:/Users/mrarsenal10/Desktop/Client/public.key";
static void recvFile(Socket sock, String fName) throws FileNotFoundException, IOException
{
    int filesize=1022386; 
    int bytesRead;
    int currentTot = 0;
    byte [] bytearray = new byte [filesize];
    InputStream is = sock.getInputStream(); 
    FileOutputStream fos = new FileOutputStream(fName); 
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    bytesRead = is.read(bytearray,0,bytearray.length); 
    currentTot = bytesRead; 
    do {
        bytesRead = is.read(bytearray, currentTot, (bytearray.length-currentTot));
        if(bytesRead >= 0) currentTot += bytesRead; } 
    while(bytesRead > -1);
    bos.write(bytearray, 0 , currentTot);
    bos.flush(); 
    bos.close();  
}
public static byte[] encrypt(String text, PublicKey key) {
    byte[] cipherText = null;
    try {
    // get an RSA cipher object and print the provider
    final Cipher cipher = Cipher.getInstance(ALGORITHM);
    // encrypt the plain text using the public key
    cipher.init(Cipher.ENCRYPT_MODE, key);
    cipherText = cipher.doFinal(text.getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return cipherText;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
    Socket sock = new Socket("127.0.0.1",15124);
    recvFile(sock, "public.key");
    recvFile(sock, "lich.txt");
    sock.close();
}
}

我的问题就在这里,我可以发送" public.key"或" lich.txt"从服务器到客户端,现在我想发送" public.key"和" lich.txt"。谢谢你的帮助。

1 个答案:

答案 0 :(得分:0)

问题在于服务器和客户端的整体设计。在服务器端,它发送两个不同的文件,但在客户端,它只是一个数据流。表示一个文件与下一个文件的数据的一个字节之间没有区别。所以可能发生的是你正在调用recvFile,它接收服务器发送的BOTH文件中的所有数据。发送数据后,服务器关闭连接。 (你明确地这样做。)所以现在,在客户端,你有一个无效的套接字。但是,您尝试再次使用代表第二个文件的套接字调用recvFile。这将导致SocketException或更可能出现的OutOfBoundsException。

要解决此问题,您需要在服务器和客户端之间添加更多握手。最简单的是表示文件结尾的分隔符。更好的方法是在发送任何允许客户端知道文件大小的数据之前,在每个“消息”(也称为文件)的前面附加一个已知大小的标头。然后,一旦客户端收到标头,它就知道要读取多少字节。

目前,为防止崩溃,您需要使用recvFile方法:

byte[] bytearray = new byte[4096];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream(fName);

int bytesRead;
while ((bytesRead = is.read(bytearray)) >= 0) {
    if (bytesRead > 0) {
        fos.write(bytearray, 0, bytesRead);
    }
}

fos.flush();
fos.close();