Java 套接字应用程序在尝试发送文件时发送额外的字节

标签 java sockets file-io stream java-io

我的程序是一个典型的服务器-客户端应用程序。问题是,当我尝试发送文件时,由于某种原因,客户端套接字接收的字节数多于服务器套接字发送的字节数。更奇怪的是,这些字节在开头,并且它们的数量根据文件大小而变化。当我尝试发送 1x1px 文件时,有 6 个字节的偏移量(6 个字节的添加数据,如果我跳过它们,会给出正确的图像),而 800x600 个字节有更大的一个(第二个输出文件总共比第二个输入大 56 个字节) .在互联网上搜索后,我发现仅有的 2 个建议是尝试事先清除缓冲区,我想我试过了,但它只是“吃掉”了我的第一个 inStream.read()。 第二个与发送 pacages 的方式有关,大小必须是某个数字的倍数?但这似乎很奇怪,因为他们不会在文件末尾而不是开头添加一些空格吗?

客户端类

public class Client{

import java.io.BufferedReader;

public class Client implements Runnable {
static Socket clientSocket = null;
static Socket iClientSocket = null;
static PrintWriter out = null;
static BufferedReader in = null;
static InputStream iin = null;
public static void main(String[] args) {
    int port = Integer.valueOf(args[1]);
    String host = args[0];

    try {
        clientSocket = new Socket(host, port);
        iClientSocket = new Socket(host, port);
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(
                clientSocket.getInputStream()));
        iin = iClientSocket.getInputStream();
    } catch (UnknownHostException e) {
        System.err.println("Don't know about host: " + host);
        System.exit(-1);
    } catch (IOException e) {
        System.err.println("Couldn't get I/O for " + "the connection to: "
                + host);
        System.exit(-1);
    }

    BufferedReader stdIn = new BufferedReader(new InputStreamReader(
            System.in));
    String userInput;

    try {
        new Thread(new Client()).start();
        while ((userInput = stdIn.readLine()) != null) {
            out.println(userInput);
        }
        System.out.println("Closing sockets, closing streams");

        out.close();
        in.close();
        stdIn.close();
        iClientSocket.close();
        clientSocket.close();

    } catch (IOException e) {
        System.exit(-1);
    }

}

@Override
public void run() {
    String a = null;

    try {
        while (true) {
            if((a = in.readLine()) == null)
                continue;
            //System.out.println("Tried to read");
            int n;
            try{
                n = Integer.valueOf(a);
            }catch(NumberFormatException e){
                System.out.println(a);
                n=1;
                //continue;
            }
            a = "";
            for (int i = 0; i < n; i++)
                a += in.readLine() + "\n";
            System.out.println(a);
            // if(a.contains("POST"),)
            if (a.compareToIgnoreCase("EXIT") == 0) {
                System.out.println("Exiting");
                break;
            }
            if (a.endsWith("Sending File\n")) {

                System.out.println("Recieving image.");
                a=in.readLine();
                a=in.readLine();
                FileOutputStream iout = new FileOutputStream(a);
                int fileSize=Integer.parseInt(in.readLine());
                int total=0;
                int step = 1500;
                int bufferSize = 0;
                // if(step>fileSize)
                // bufferSize=(int) fileSize;
                // else
                bufferSize = step;
                byte[] buffer = new byte[bufferSize];
                int read=0;

                while (fileSize-total>0 && (read = iin.read(buffer, 0, (int)Math.min(buffer.length, fileSize-total))) > 0) {
                    iout.write(buffer, 0, read);
                    //out.println("saved packet");
                    total+=read;

                }
                iout.flush();
                iout.close();
                System.out.println("Image recieved");

            }
        }
    } catch (IOException e) {
        System.exit(-1);
    }

}

Server类,负责发送

public class Server implements Runnable {

static ServerSocket serverSocket;
Socket tempSocket;
Socket tempSocket2;
static volatile List<User> usersList = new ArrayList<User>();
static boolean waitForNew = true;
PrintWriter tempOut;
volatile User[] tempUser;
volatile boolean isReadingN = false;

public Server(Socket _s, Socket _s2) {
    tempSocket = _s;
    tempSocket2 = _s2;
}

public Server(PrintWriter nOut, User[] user) {
    tempOut = nOut;
    tempUser = user;
    isReadingN = true;
}

@Override
public void run() {
    if (isReadingN) {
        while (true) {
            if (tempUser != null && tempUser.length > 0
                    && tempUser[0] != null)
                break;
        }
        User[] myUser = new User[1];
        myUser[0] = tempUser[0];
        // myUser[0]=usersList.
        while (true) {
            if (myUser[0].isCurrentlyLoggedIn() == false)
                break;
            String[] toSend = null;
            if (myUser[0].isNotificable())
                toSend = myUser[0].printNotifications().split("\n");
            else
                continue;
            //tempOut.println("");
            tempOut.println("1");
            tempOut.println(myUser[0].getName());
            int sendL=toSend.length;
            tempOut.println(String.valueOf(sendL));
            for (int i = 0; i < toSend.length; i++)
                tempOut.println(toSend[i]);
        }
        return;
    }
    Socket clientSocket = tempSocket;
    System.out.println("Initiating conversation with the client");
    String inputLine;
    try {
        System.out.print("creating server out...");
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
                true);
        Socket iClientSocket = tempSocket2;
        ObjectOutputStream iout = new ObjectOutputStream(
                iClientSocket.getOutputStream());
        System.out.println("OK!");
        System.out.print("creating server in...");
        BufferedReader in = new BufferedReader(new InputStreamReader(
                clientSocket.getInputStream()));
        System.out.println("OK!");
        System.out.print("creating server image streams...");
        System.out.println("OK!");
        System.out.println("Server initiating conversation");
        User[] currentUser = new User[1];
        new Thread(new Server(out, currentUser)).start();
        while ((inputLine = in.readLine()) != null) {
            System.out.println(inputLine);
            boolean[] downloadPicture = new boolean[1];
            downloadPicture[0] = false;
            String input = Command.call(inputLine, currentUser, usersList,
                    downloadPicture);
            String[] toSend;
            if (input != null) {
                toSend = input.split("\n");
            } else
                toSend = new String[0];
            out.println(String.valueOf(toSend.length));
            for (int i = 0; i < toSend.length; i++)
                out.println(toSend[i]);
            if (downloadPicture[0]) {
                out.println("1");
                out.println("Sending File");

                System.out.println("Sending File");
                String[] temp = inputLine.split(" ");
                String path = temp[temp.length - 1];
                path = path.replace("\\", "\\\\");
                File f = new File(path);
                temp=path.split("\\\\");
                String fileName=temp[temp.length-1];
                out.println("1");
                out.println(fileName);
                if (f.exists()) {
                    FileInputStream iin = new FileInputStream(path);

                    long fileSize = f.length();

                    out.println(fileSize);

                    int step = 1500;
                    int bufferSize = 0;
                    if (step > fileSize)
                        bufferSize = (int) fileSize;
                    else
                        bufferSize = step;
                    int bytesRead = 0;
                    byte[] buffer = new byte[bufferSize];
                    iout.flush();
                    while ((bytesRead = iin.read(buffer)) > 0) {
                        //iout.flush();
                        iout.write(buffer, 0, bytesRead);
                        // System.out.println(in.readLine());
                    }
                    // iout.write(buffer,0,0);
                    iout.flush();
                    System.out.println("File sent.");
                    iin.close();

                } else{
                    out.println("1");
                    out.println("Error: File does not exit.");}
            } else
                //out.println(" ");
            if (inputLine.equals("EXIT")) {
                waitForNew = false;
                break;
            }
        }
        // End communication graciously
        System.out.println("Closing sockets, closing streams");
        out.close();
        in.close();
        clientSocket.close();
        serverSocket.close();
    } catch (IIOException e) {
        System.out.println("Error: Could not find file");
        e.printStackTrace();
        System.exit(-1);
    } catch (IOException e) {
        System.out.println("Error");
        e.printStackTrace();
        System.exit(-1);
    }

}

public static void main(String[] args) {
    // Create socket on port given in argument, localhost
    if (args.length == 0) {
        System.out
                .println("Not enough arguments. Try Server <port number>");
        System.exit(-1);
    }
    int port = 0;
    try {
        port = Integer.valueOf(args[0]);
        System.out.println("Application start");

        serverSocket = new ServerSocket(port);
        System.out.println("Created socket on port " + port);
    } catch (NumberFormatException c) {
        System.out
                .println("Incorrect port number. Try Server <port number>");
        System.exit(-1);
    } catch (IOException e) {
        System.exit(-1);
    }

    // Waiting for client
    System.out.println("Waiting for client...");
    Socket clientSocket = null;
    Socket iClientSocket = null;
    while (waitForNew) {
        try {
            clientSocket = serverSocket.accept();
            iClientSocket = serverSocket.accept();
            new Thread(new Server(clientSocket, iClientSocket)).start();
        } catch (IOException e) {
            System.out.println("Accept failed: " + port);
            System.exit(-1);
        }
    }

}
 }

命令类,在服务器端操作命令,返回输出。

 public class Command {
static volatile List<Status> statusList = new ArrayList<Status>();
static Object block_statusList = new Object();

public static String call(String arg, User[] user, List<User> userlist,
        boolean[] downloadPicture) {

    String command[] = arg.split(" ");
    if (command.length == 0)
        return "";
    else if (command[0].compareTo("LOGIN") == 0)
        return login(command, user, userlist);
    else if (command[0].compareTo("EXIT") == 0)
        return exit(command, user, userlist);
    else if (user == null || user.length != 1 || user[0] == null
            || !user[0].isCurrentlyLoggedIn())
        return "You need to login first. Try LOGIN <username>";
    else if (command[0].compareTo("LOGOUT") == 0)
        return logout(command, user, userlist);
    else if (command[0].compareTo("POST") == 0)
        return post(command, user, userlist, downloadPicture);
    else if (command[0].compareTo("TIMELINE") == 0)
        return timeline(command, user, userlist);
    else if (command[0].compareTo("FOLLOW") == 0)
        return follow(command, user, userlist);
    else if (command[0].compareTo("UNFOLLOW") == 0)
        return unfollow(command, user, userlist);
    else if (command[0].compareTo("VIEWSTATUS") == 0)
        return viewstatus(command, user, userlist);
    else if (command[0].compareTo("LISTUSER") == 0)
        return listuser(command, user, userlist);
    else if (command[0].compareTo("VIEWUSER") == 0)
        return viewuser(command, user, userlist);
    else if (command[0].compareTo("COMMENT") == 0)
        return comment(command, user, userlist);

    else
        return "Command not recognized";
}

private static String logout(String[] arg, User[] user, List<User> userlist) {
    if (arg.length != 1)
        return "Wrong number of parameters. LOGOUT does not take any parameters";
    user[0].setCurrentlyLoggedIn(false);
    return "Logged out.";
}

private static String[] parseArg(String[] arg) {
    int startCommas = 0;
    int endCommas = 0;
    for (int i = 0; i < arg.length; i++) {
        if (startCommas == 0 && arg[i].startsWith("\""))
            startCommas = i;
        if (startCommas != 0 && arg[i].endsWith("\""))
            endCommas = i;
    }
    if (startCommas != endCommas) {
        String[] newArg = new String[arg.length + startCommas - endCommas];
        for (int i = 0; i < startCommas; i++)
            newArg[i] = arg[i];
        newArg[startCommas] = "";
        for (int i = startCommas; i < endCommas; i++)
            newArg[startCommas] += arg[i] + " ";
        newArg[startCommas] += arg[endCommas];
        for (int i = endCommas + 1; i < arg.length; i++)
            newArg[i - endCommas] = arg[i];
        return newArg;
    }
    return arg;
}

private static String comment(String[] arg, User[] user, List<User> userlist) {
    synchronized (block_statusList) {
        arg = parseArg(arg);
        int SID;
        if (arg.length != 3)
            return "Wrong number of parameters. Try COMMENT <Status ID> \"Comment text\"";
        if (arg[2].charAt(0) != '"'
                || arg[2].charAt(arg[1].length() - 1) != '"')
            return "Text of message has to be in quotation marks. Try  POST \"post text\"";
        String temp = arg[2].substring(1, arg[2].length() - 1);
        try {
            SID = Integer.valueOf(arg[1]);
        } catch (NumberFormatException e) {
            return "Status ID has to be a number. Try COMMENT <Status ID> \"Comment text\"";
        }
        Comment c = new Comment(temp, user);
        statusList.get(SID).addComment(c);
        return "Comment succeeded";
    }
}

private static String viewuser(String[] arg, User[] user,
        List<User> userlist) {
    synchronized (block_statusList) {
        if (arg.length != 2)
            return "Wrong number of parameters. Try VIEWUSER <user>";
        String r = "";
        for (User u : userlist)
            if (u.getName().compareTo(arg[1]) == 0)
                r = u.printUser();
        return r;
    }
}

private static String listuser(String[] arg, User[] user,
        List<User> userlist) {
    if (arg.length != 1)
        return "Wrong number of parameters. LISTUSER doesn't take any parameters";
    String r = "";
    for (User u : userlist)
        r += u.getName() + "\n";
    return r;
}

private static String viewstatus(String[] arg, User[] user,
        List<User> userlist) {
    synchronized (block_statusList) {
        int SID;
        if (arg.length != 2)
            return "Wrong number of parameters. Try VIEWSTATUS <Status ID>";
        try {
            SID = Integer.valueOf(arg[1]);
        } catch (NumberFormatException e) {
            return "Status ID has to be a number. Try  VIEWSTATUS <Status ID>";
        }
        if (SID >= statusList.size())
            return "Status ID too big.";
        return statusList.get(SID).printWithComments();
    }
}

private static String unfollow(String[] arg, User[] user,
        List<User> userlist) {
    if (arg.length != 2)
        return "Wrong number of parameters. Try UNFOLLOW <username>";
    boolean removed = false;
    for (User u : userlist) {
        if (u.getName().compareTo(arg[1]) == 0) {
            user[0].removeFriend(arg[1]);
            u.removeFollower(user[0].getName());
            removed = true;
        }
    }
    if (!removed)
        return "User not found.";
    return "Follow succeded. " + user[0].printFriends();
}

private static String follow(String[] arg, User[] user, List<User> userlist) {
    if (arg.length != 2)
        return "Wrong number of parameters. Try FOLLOW <username>";
    if(user[0]!=null && user.length!=0 && user[0]!=null && user[0].getName().compareTo(arg[1])==0)
        return "You cannot follow yourself. Try FOLLOW <username>";
    User[] followed = null;
    for (User u : userlist) {
        if (u.getName().compareTo(arg[1]) == 0) {
            followed = new User[1];
            followed[0] = u;
            user[0].addFriend(followed);
            followed[0].addFollower(user);
        }
    }
    if (followed == null)
        return "User not found.";
    return "Follow succeded. Current " + user[0].printFriends();
}

public static String login(String[] arg, User[] user, List<User> userslist) {
    if (arg.length != 2)
        return "Wrong number of parameters. Try LOGIN <username>";
    if (user.length > 0 && user[0] != null) {
        if (user[0].isCurrentlyLoggedIn())
            return "User already logged in. Try logging out first";
    }
    for (User l : userslist) {
        if (l.getName().compareTo(arg[1]) == 0) {
            if (l.isCurrentlyLoggedIn())
                return "That user is already logged in.";
            user[0] = l;
            user[0].setCurrentlyLoggedIn(true);
            return "Login succeeded";
        }
    }

    User newUser = new User(arg[1]);
    userslist.add(newUser);
    user[0] = newUser;
    user[0].setCurrentlyLoggedIn(true);
    return "Login succeeded. Created new user.";
}

public static String post(String[] arg, User[] user, List<User> userslist,
        boolean[] downloadPicture) {
    arg = parseArg(arg);
    if (arg.length != 2 && arg.length != 3)
        return "Wrong number of parameters. Try POST \"post text\"";
    if (arg[1].charAt(0) != '"'
            || arg[1].charAt(arg[1].length() - 1) != '"')
        return "Text of message has to be in quotation marks. Try  POST \"post text\"";
    String temp = arg[1].substring(1, arg[1].length() - 1);
    Status s;
    try {
        s = new Status(temp, statusList.size(), user);
    } catch (Exception e) {
        System.out.println("Error: Could not create Status");
        e.printStackTrace();
        return "Error";
    }
    if(arg.length==3)
    s.hasImage(arg[2]);
    user[0].addStatus(s);
    statusList.add(s);
    if (arg.length == 3)
        downloadPicture[0] = true;

    return "Successfully added status";

}

public static String timeline(String[] arg, User[] user,
        List<User> userslist) {
    if (arg.length != 1)
        return "Wrong number of parameters. TIMELINE doesn't take any parameters";
    List<Status> Timeline = new ArrayList<Status>();
    Timeline.addAll(user[0].getStats());
    for (User l : user[0].getFriends())
        Timeline.addAll(l.getStats());
    Collections.sort(Timeline);
    String result = "";
    for (Status s : Timeline)
        result += s.print() + "\n" + "Comments[" + s.getComments().size()
                + "]\n\n";
    return result;
}

public static String exit(String[] arg, User[] user, List<User> userslist) {
    if (arg.length != 1)
        return "Wrong number of parameters. EXIT doesn't take any parameters";
    if (user[0] != null)
        user[0].setCurrentlyLoggedIn(false);
    return "EXIT";
}

 }

添加通知

最佳答案

您没有发送额外的字节,也没有接收额外的字节,但您肯定会在接收端向文件写入额外的字节。

您的发送密码是正确的,您的接收密码是错误的。查看 write() 调用之间的区别。一个使用接收计数:一个不使用。前者是正确的。 Java中复制流的方式如下:

int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}
out.close();
in.close();

在两端。然而,在这种情况下,当您保持套接字打开以接收更多命令时,您需要在图像之前发送图像大小,并且您需要一种发送和接收命令的方式,不会干扰图像,BufferedReader 无法完成。所以你需要使用 DataOutputStreamDataInputStream,像这样:

// At the sender
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeUTF(command);
// ...
out.writeLong(imageSize);
// then the copy loop, reading from the image file.

// At the receiver
DataInputStream in = new DataInputStream(socket.getInputStream());
String command = in.readUTF();
// ...
// image reading code
long imageSize = in.readLong();
long total = 0;
int count;
byte[] buffer = new byte[8192];
while (total < imageSize && (count = in.read(buffer, 0, (int)Math.MIN(buffer.length, imageSize-total))) > 0)
{
  out.write(buffer, 0, count);
  total += count;
}
out.close();

模数错误。

关于Java 套接字应用程序在尝试发送文件时发送额外的字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15608075/

相关文章:

java - 如何在没有sqlite数据库的情况下使用代号一和eclipse保存/加载表内容

java - 如何将Weld集成到maven项目中?

java - Java中使用Socket时强制转换为接口(interface)

sockets - 使用 TcpStream 强制非阻塞读取

c# - 使用 C# 从 RLM 读取许可文件(C++ 到 C# 的翻译)

java - 源代码管理中的 Eclipse 保存操作

java - 将 JSON 反序列化为类实例

c - C 套接字上的 ioctl() 的 FIONREAD 可靠吗?

php - 允许在 Ubuntu Server 中的 apache2 上创建文件夹

C Socket Server,内存随文件写入而增加