我正在尝试使用两端的BufferedOutputStream和BufferedInputStream将文件从“server”发送到“client”。问题是虽然我在每次写入(右侧)上刷新()服务器上的BufferedOutputStream,但每次刷新(左侧)时数据都会到达客户端套接字。
正如你可以看到上面的文件发送得很好,但如果我使用不同的文件或不同的缓冲区大小如下...
......它“打破”。客户端上的读取被阻止,因为流中没有任何内容,应该有。 整件事让我感到困惑,显然我遗失了一些东西。这是我的代码:
客户端
PBOX00354: Setting security roles ThreadLocal: null
每个线程(连接的客户端)CLIENT_HANDLER
import java.io.*;
import java.net.*;
import java.util.Scanner;
import java.lang.Math.*;
/**
* Client application which allows the user to connect with server
* and execute simple file transfers.
*
*/
public class Client
{
private BufferedReader textFromSocket;
private PrintWriter textToSocket;
private BufferedInputStream fileFromSocket;
private BufferedOutputStream fileToSocket;
private Socket connection;
private static final int port = 8888;
private static final String host = "localhost";
private static final String filesFolder = "client/clientFiles/";
/**
* Initializes all the streams and the socket
*
* @throws IOException
*/
public Client() throws IOException {
// Try to open up a connection with cslin152, port number 4242. If cslin152 is unavailable,
// run the this on the same machine as the client, and use the hostname host.
connection = new Socket( host, port);
// Buffer the reading stream for performance.
textFromSocket = new BufferedReader( new InputStreamReader( connection.getInputStream()));
// Writing stream
textToSocket = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(connection.getOutputStream())), true);
// Data input (incoming) stream
fileFromSocket = new BufferedInputStream( new DataInputStream(connection.getInputStream()),8*1024);
// Data output (outgoing) stream
fileToSocket = new BufferedOutputStream( new DataOutputStream(connection.getOutputStream()));
}
/**
* Sends a request to server
*
* @param cmd request to send
* @throws IOException
*/
public void askServer(String cmd) throws IOException {
if (cmd != null) {
// write to this
textToSocket.println(cmd);
}
String[] command = cmd.split(" ");
switch (command[0]) {
case "list":
this.readList();
break;
case "get":
if (command.length < 2){
System.out.println("Filename not specified");
}else{
this.getFile(command[1]);
}
break;
case "put":
if (command.length < 2){
System.out.println("Filename not specified");
}else{
this.putFile(command[1]);
}
break;
case "bye":
this.byeBye();
break;
default:
System.out.println(textFromSocket.readLine());
break;
}
}
/**
* Executes client-side commands for "list" command
* "list" command, lists all files available on the server
*/
public void readList(){
try {
String line;
while ( !(line = textFromSocket.readLine()).equals("")) {
System.out.println(line);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Executes client-side commands for "get" command
* "get" command, downloads a file from server
*
* @param filename the name of the file where data will be saved
*/
public void getFile(String fileName) throws IOException {
File downloadFile = new File(filesFolder, fileName);
try (FileOutputStream fos = new FileOutputStream(downloadFile)) {
copy(fileFromSocket, fos);
fos.flush();
}
}
public long copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[8 * 1024];
long total = 0L;
while (true) {
int read = in.read(buffer);
if (read < 0) {
break;
}
out.write(buffer, 0, read);
total += read;
}
return total;
}
/**
* Executes client-side commands for "put" command
* "put" command, uploads a file to server
*
* @param filename the name of the file to upload
*/
public void putFile(String filename){
File sendFile = new File(filesFolder + filename);
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sendFile));
int fileSize = (int)sendFile.length();
if (sendFile.exists()) {
textToSocket.println(fileSize);
byte[] myBuffer = new byte[fileSize];
bis.read(myBuffer, 0, fileSize);
fileToSocket.write(myBuffer);
fileToSocket.flush();
bis.close();
}else {
System.out.println("Error: File not found");
}
}
catch (FileNotFoundException e) {
System.out.println("Error: File doesn't exist");
}
catch (IOException e){
System.out.println("Error: Couldn't read the file");
}
}
/**
* Closes all the streams, connection and terminates the client
*/
public void byeBye(){
try {
connection.close();
fileFromSocket.close();
fileToSocket.close();
textToSocket.close();
textFromSocket.close();
}
catch (IOException e) {
e.printStackTrace();
}
System.exit(0);
}
/**
* Connects with the server and continuously scans for user input
*
*/
public static void main(String[] args)
{
Client client = null;
Scanner keyboardInput = new Scanner(System.in);
while (client == null){
try {
client = new Client();
System.out.println("Connected to server at : "+ host +":"+ port);
}
catch (IOException e) {
System.out.println("ERROR: Couldn't connect to server, press ENTER to try again");
// Wait for ENTER
keyboardInput.nextLine();
}
}
while (true) {
System.out.printf("client>");
String cmd = keyboardInput.nextLine();
try {
client.askServer(cmd);
}
catch (IOException e) {
System.out.println("Error: Server didn't reply");
}
}
}
}
服务器
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Client handler application which is run as a separate thread for each connected client
*
*/
public class ClientHandler extends Thread
{
private BufferedReader textFromSocket;
private PrintWriter textToSocket;
private BufferedInputStream fileFromSocket;
private BufferedOutputStream fileToSocket;
private Socket connection;
private static final String filesFolder = "server/serverFiles/";
private static final String logFile = "server/log.txt";
/**
* Initializes all the streams and the socket
*
* @throws IOException
*/
public ClientHandler(Socket client){
try {
connection = client;
// Buffer the reading stream for performance.
textFromSocket = new BufferedReader( new InputStreamReader( connection.getInputStream()));
// Writing stream
textToSocket = new PrintWriter( new BufferedWriter( new OutputStreamWriter(connection.getOutputStream())), true);
// Data input (incoming) stream
fileFromSocket = new BufferedInputStream( new DataInputStream(connection.getInputStream()));
// Data output (outgoing) stream
fileToSocket = new BufferedOutputStream( new DataOutputStream(connection.getOutputStream()),8*1024);
}
catch( IOException e )
{
System.out.println( e );
}
}
/**
* Reads a request from client
*
* @return client request
*/
public String getLine(){
try {
return textFromSocket.readLine();
}
catch (IOException e) {
System.out.println("error: Couldn't read from client (Connection Lost)");
return null;
}
}
/**
* Executes server-side commands for "list" command
* "list" command, lists all files available on the server
*/
public void list(){
File serverDir = new File(filesFolder);
File[] fileList = serverDir.listFiles();
for (int i=0;i<fileList.length;i++){
textToSocket.println(fileList[i].getName());
}
textToSocket.println("");
textToSocket.flush();
}
/**
* Executes server-side commands for "get" command
* "get" command, downloads a file from server
*
* @param filename the name of the file to be sent to client
*/
public void get(String filename) throws IOException {
File fileToSend = new File(filesFolder, filename);
try (FileInputStream in = new FileInputStream(fileToSend)) {
copy(in, fileToSocket);
fileToSocket.flush();
}
}
public long copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[8 * 1024];
long total = 0L;
while (true) {
int read = in.read(buffer);
if (read < 0) {
break;
}
out.write(buffer, 0, read);
total += read;
}
return total;
}
/**
* Executes client-side commands for "put" command
* "put" command, uploads a file to server
*
* @param filename the name of the file to be received from client
*/
public void put(String filename){
try{
String text = textFromSocket.readLine();
if (text.indexOf("ERROR") == -1) {
int fileSize = Integer.parseInt(text);
File downloadFile = new File(filesFolder + filename);
FileOutputStream fos = new FileOutputStream(downloadFile);
byte[] myBuffer = new byte[16 * 1024];
int readBytes = 0;
int currentBytes = 0;
while (readBytes < fileSize) {
currentBytes = fileFromSocket.read(myBuffer, 0, myBuffer.length);
readBytes += currentBytes;
fos.write(myBuffer, 0, currentBytes);
}
fos.close();
System.out.println("File downloaded");
}else{
System.out.println(text);
}
}
catch (IOException e) {
System.out.println("ERROR: Couldn't download\\save the file");
}
}
/**
* Closes all the streams and connection
*/
public void byeBye(){
try {
connection.close();
fileFromSocket.close();
fileToSocket.close();
textToSocket.close();
textFromSocket.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* Stores a request from client in a log.txt file
* each request is stored in a form: date:time:client IP address:request
*
* @param request the request made by client
*/
public void logRequest(String request){
File file = new File (logFile);
try {
PrintWriter log = new PrintWriter(new BufferedWriter(new FileWriter(file,true)));
// Get all the details
Date today = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy:hh:mm:ss");
String date = dateFormatter.format(today);
String address = connection.getInetAddress().toString();
System.out.println("log: " + date+":"+address+":"+request);
// Save request with details to file
log.println(date + ":" + address + ":" + request);
}
catch (FileNotFoundException e) {
System.out.println("error: log.txt couldn't be created");
}
catch (IOException e){
System.out.println("File writer");
}
}
/**
* Sends an error message to a client
*
* @param text content of the message
*/
public void error(String text){
textToSocket.println("ERROR Server: "+text);
textToSocket.flush();
}
/**
* Continuously reads requests from clients and executes them
*/
public void run() {
String read;
while (( read = (this.getLine())) != null) {
// log the request
this.logRequest(read);
// split command for potential arguments
String[] command = read.split(" ");
if (command.length > 2) {
this.error("Too many arguments");
} else {
switch (command[0]) {
case "list":
this.list();
break;
case "get":
if (command.length < 2){
System.out.printf("Filename not provided");
}else {
try {
this.get(command[1]);
} catch (IOException e) {
e.printStackTrace();
}
}
break;
case "put":
if (command.length < 2){
System.out.printf("Filename not provided");
}else {
this.put(command[1]);
}
break;
case "bye":
this.byeBye();
break;
default:
this.error("illegal command");
break;
}
}
}
}
}
答案 0 :(得分:1)
在客户端代码中,您需要在关闭之前调用fos.flush()
。
作为旁注,客户端的最小逻辑并不是必需的。有更简单的方法来实现这些。
答案 1 :(得分:1)
Jags在他的断言中都是正确的,但他们没有写下如何使你的代码更简单。所以就是这样。这可能是你经常使用的一种方法,所以要把它放在一个方便的地方。
public long copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[8 * 1024];
long total = 0L;
while (true) {
int read = in.read(buffer);
if (read < 0) {
break;
}
out.write(buffer, 0, read);
total += read;
}
return total;
}
然后你的客户端和服务器变得非常小:
<强>客户端强>
public void getFile(String filename) throws IOException {
String text = textFromSocket.readLine(); // Don't
if (text.contains("ERROR")) { // know
return; // why
} // it's
int fileSize = Integer.parseInt(text); // needed.
File downloadFile = new File(filesFolder, fileName);
try (FileOutputStream fos = new FileOutputStream(downloadFile)) {
copy(fileFromSocket, fos);
fos.flush();
}
}
服务器强>
public void get(String filename) throws IOException {
File fileToSend = new File(filesFolder, filename);
try (FileInputStream in = new FileInputStream(fileToSend)) {
textToSocket.println(fileToSend.length()); // Not really needed
copy(in, fileToSocket);
fileToSocket.flush();
}
}