I want to send files as well as some other information through sockets. I am using the following code
public void receiveFile(Socket socket,int filesize,String filename) throws IOException
{
//after receiving file send ack
System.out.println("waiting ");
// int filesize=70; // filesize temporary hardcoded
long start = System.currentTimeMillis();
int bytesRead;
int current = 0;
// localhost for testing
System.out.println("Connecting...");
// receive file
byte [] mybytearray = new byte [filesize];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(filename);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
System.out.println("recv..."+mybytearray.length);
do {
bytesRead =
is.read(mybytearray, current, (mybytearray.length-current));
System.out.println(bytesRead);
if(bytesRead > 0) current += bytesRead;
} while(bytesRead > 0);
bos.write(mybytearray, 0 , current);
bos.flush();
long end = System.currentTimeMillis();
System.out.println(end-start);
bos.close();
System.out.println(" File received");
}
After receiving the file, I have to receive some other strings. But when I try to read the input stream, I am getting the contents of the file. How to flush the contents of the file from the inputstream.
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(
webServerSocket.getInputStream()));
receiveFile(webServerSocket,filesize,filename);
while(true)
{
msg = inFromServer.readLine(); //here i receive the contents of the file again
System.out.println(msg);
}
Pass the socket's inputstream to the receivefile-method, instead of the socket itself:
InputStream is = webServerSocket.getInputStream();
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(is));
receiveFile(webServerSocket,filesize,filename);
The problem lies, I believe, in the fact that you have two inputstreams from the same socket made at the same point in time (before any data has actually been read). They point to the same stream but reading from one does not move the other as well, thus after reading from inputstreamBA that one is marked in position 15 (for example) while inpustream A is still in poisition 0, at the beginning of the stream.
(EDIT:)
Ofcourse, you have to use the inputstream in the receiveFile method instead of getting one from the socket. Another solution would be to get the inputstream from the socket after the call to receive file, as in
receiveFile(webServerSocket,filesize,filename);
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(webServerSocket.getInputStream()));
By reading the file to completion, you will have read the whole file. If you are still getting the contents of the file, you haven't read the whole file.
Related
I have an inputStream object that comes from a socket.
This stream could be all plain text, or it could contain binary data. It has a plain text "prefix" that tells me which type of data it has. I use BufferedReader to read that prefix. Then, if the data type is plain text, I continue to use BufferedReader to read the rest which works just fine.
The problem is when I switch back to using InputStream if the prefix indicates non-text data. The stream seems to be lost somewhere, and I get a java.net.SocketTimeoutException: Read timed out instead.
Code goes something like this:
InputStream instream = mysocket.getInputStream();
BufferedReader br = (new InputStreamReader(instream, "UTF-8")));
byte[] prefixArray = new byte[4];
br.read(prefixArray, 0, 4);
String prefix = new String(prefixArray);
if("text".equals(prefix)) {
// continue to use br.read() here, which works fine...
}else{
byte[] barray = new byte[arraysize]
instream.read(barray, 0, arraysize); // THROWS "Read timed out" exception
}
Is this simply not allowed? Once instream is wrapped in a BufferedReader, it can't be used directly any longer?
A BufferedReader reads from a Reader and stores the data in a buffer for subsequent reads to use. It reads as much as it can at one time, and each time the buffer is emptied, it reads more into the buffer.
Your binary reads time out because the BufferedReader has already read the bytes you are trying to read.
It takes only 4 bytes for you to detect the stream type. Using a Reader for those 4 bytes is overkill. Read the bytes directly from the InputStream first, then create a Reader only for the text data, eg:
InputStream instream = mysocket.getInputStream();
byte[] prefixArray = new byte[4];
int offset = 0;
int numread;
do
{
numread = instream.read(prefixArray, offset, 4-offset);
if (numread == -1) return;
offset += numread;
}
while (offset < 4);
String prefix = new String(prefixArray);
if ("text".equals(prefix))
{
BufferedReader br = new BufferedReader(new InputStreamReader(instream, "UTF-8"));
//...
}
else
{
byte[] barray = new byte[arraysize];
// consider using BufferedInputStream here ...
do
{
numread = instream.read(barray, 0, arraysize);
if (numread == -1) break;
//...
}
while (true);
}
Alternatively, consider using BufferedInputStream for the socket reading, and add other classes on top of it as needed, eg:
InputStream instream = mysocket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(instream);
byte[] prefixArray = new byte[4];
DataInputStream dis = new DataInputStream(bis);
dis.readFully(prefixArray);
String prefix = new String(prefixArray);
if ("text".equals(prefix))
{
InputStreamReader isr = new InputStreamReader(bis, "UTF-8"));
//...
}
else
{
byte[] barray = new byte[arraysize];
do
{
numread = bis.read(barray, 0, arraysize);
if (numread == -1) break;
//...
}
while (true);
}
I am writing a program wherein client needs to monitor the creation of files in a specific folder and send them as they are created to the server.Server should always be in listening mode and save these files with the same name in the specified folder on the server.For now,i am trying to achieve this on the same m/c.How do i achieve this via socket?
I was able to monitor the creation of files in the folder at the client and send them.At the receiver,i was only able to receive one file.After that i was getting a FileNotFoundException at the server.
Client code
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);
Server code
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();
}
I expect the server to wait for client to send another file as soon as it is created at the client side but i am getting a filenotfound exception soon after the receiver has received and saved the first file.
Also,one observation is that at the server side,i was seeing this line System.out.println("filename : "+fileName); and subsequent lines getting executed twice until the exception pops up inspite of only creating(and inherently sending) one file at the client.
Following are the logs for the server code:-
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)
In the client, you are writing the file size with writeInt(), but in the server you are reading it with read(). You should be using readInt(). This would throw everything off, since read() is only reading the first byte of the 4-byte integer length; then you don't read any data because you think the length is 0; then when you try to read the 2nd file's name, you're out of position and reading an empty string, which causes the error you're seeing. BTW it's probably more proper to use writeLong() and readLong(), since that's the return type of File.length(), but that's up to you especially if you're only using smaller files.
There also seems to be something off with how you're using the DataOutputStream dos and BufferedOutputStream bos, both of which wrap the same FileOutputStream output. You are first writing the full uninitialized buffer to the file via bos (only some of which might actually be written, since it's buffered); then you are again reading and writing the actual file data via dos, which will append to what was previously written to output. Maybe you meant something like dos = new DataOutputStream(new BufferedOutputStream(output)), which would give you the benefits of both. But you still don't want to write the whole uninitialized buffer before the read loop like you've done.
Also, since you're only using write(), you could probably directly use output.write() without the fancy DataOutputStream. The BufferedOutputStream is useful as an optimization if you want to avoid frequent small writes to the disk, but it's not necessary, especially since there's some inherent buffering in the way you're reading/writing 1Kb chunks.
When I run my client server - which is connecting and I try to send a file it doesn't won't send the whole file which is pulling errors else where, it gets about halfway through and constantly stops at the same part. This set up works when running the server-client on the same machine so I am completely confused
Server --->
// output (a DataOutputstream) is set up elsewhere and messages are sent and received properly
output.writeInt((int)file.length());
// send file
byte [] mybytearray = new byte [(int)file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
System.out.println("Sending " + file + "(" + mybytearray.length + " bytes)");
output.write(mybytearray,0,mybytearray.length);
output.flush();
System.out.println("Done.");
Client --->
// input (a DataInputstream) is set up elsewhere and messages are sent and received properly
String FILE_TO_RECEIVED = "Load_From.xml";
File file = new File(FILE_TO_RECEIVED);
int FILE_SIZE = input.readInt();
if(FILE_SIZE!=0){
// receive file
System.out.println("received file size : " + FILE_SIZE);
byte [] mybytearray = new byte [FILE_SIZE];
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = input.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
You are only reading part of the data, both when reading the file and when reading the socket. The read method returns the number of bytes read, and you need a loop to read everything. For example,
int read = 0, offset = 0;
while ((read = bis.read(mybytearray, offset, mybytearray.length - offset) != -1) {
offset += read;
}
Or you can use classes from the standard library, for example DataInputStream has a readFully method.
DataInputStream dis = new DataInputStream(fis);
dis.readFully(mybytearray);
Please see the documentation of read() at: http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read(byte[],%20int,%20int).
In particular:
An attempt is made to read as many as len bytes, but a smaller number may be read. The number of bytes actually read is returned as an integer.
This means that if the length returned is not what you expect and you haven't encountered the end of file yet, you should call read() again (in a loop).
I am trying to write a program to transfer a file between client and server using java tcp sockets I am using buffer size of 64K but The problem I am facing is that when when the tcp sometimes fail to send the whole 64K it sends the remaing part for example 32K in anther go
There for A garbage data of some Spaces or so is being taken by the buffer at reading side to make 64K complete and thus unnecessary data is making the file useless at receiving side.
Is there any solution to overcome this problem ???
I am using TCP protocol this code is using to send data to client
Server-side code
File transferFile = new File ("Document.txt");
byte [] bytearray = new byte [1024];
int byRead=0;
FileInputStream fin = new FileInputStream(transferFile);
BufferedInputStream bin = new BufferedInputStream(fin);
OutputStream os = socket.getOutputStream();
while(byRead>-1) {
byRead=bin.read(bytearray,0,bytearray.length);
os.write(bytearray,0,bytearray.length);
os.flush();
}
Client-side code
byte [] bytearray = new byte [1024];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("C:\\Users\\NetBeansProjects\\"+filename);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray,0,bytearray.length);
currentTot = bytesRead; System.out.println("Data is being read ...");
do {
bytesRead = is.read(bytearray, 0, (bytearray.length));
if(bytesRead == 0) continue;
if(bytesRead >= 0) currentTot += bytesRead;
bos.write(bytearray,0,bytearray.length);
} while(bytesRead > -1);
here I tried to skip the loop if the byte is empty by continue; statement but it is not
working.
bos.write(bytearray,0,bytearray.length);
This should be
bos.write(bytearray,0,bytesRead);
The region after 'bytesRead' in the buffer is undisturbed by the read. It isn't 'garbage'. It's just whatever was there before.
use CLIENT Side Code as below to get the total write bytes without garbage
int availableByte = socket.available();
if (availableByte > 0) {
byte[] buffer = new byte[availableByte];
int bytesRead = socketInputStream.read(buffer);
FileOutputStream fileOutputStream = new FileOutputStream(FilePath, true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write(buffer.toString());
bufferedWriter.close();
}
I want to create small client-server TCP file transfer program. And I have problem with one thing. When I send file from Client to Server, for example a txt file: omg.txt, I want the Server to read the incoming file name.
So - Client send omg.txt, Server says "New file recived: omg.txt". I tried to use BufferedReader (Server) and DataOutputStream (Client, because you have to write name of the file to send it) but it didnt work.
EDIT:
Client:
Socket sock = new Socket("localhost",13267);
System.out.println("Wait...");
Scanner input = new Scanner(System.in);
while(true){
// wysylanie
System.out.println("Filename");
String p = input.nextLine();
File myFile = new File (p);
boolean exists = (new File(p)).exists();
if (exists) {
byte [] mybytearray = new byte [(int)myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
bis.read(mybytearray,0,mybytearray.length);
OutputStream os = sock.getOutputStream();
System.out.println("Wait...");
os.write(mybytearray,0,mybytearray.length);
os.flush();
System.out.println("Done");
sock.close();
}
Server:
int filesize=6022386;
int bytesRead;
int current = 0;
ServerSocket servsock = new ServerSocket(13267);
Scanner input = new Scanner(System.in);
while (true) {
System.out.println("Wait...");
Socket sock = servsock.accept();
System.out.println("OK : " + sock);
// odbior pliku
byte [] mybytearray = new byte [filesize];
InputStream is = sock.getInputStream();
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead =
is.read(mybytearray, current, (mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
System.out.println("New filename");
String p = input.nextLine();
File plik = new File(p);
FileOutputStream fos = new FileOutputStream(plik);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(mybytearray, 0 , current);
bos.flush();
System.out.println("File saved");
bos.close();
sock.close();
And I tried to do something like that:
Client addon:
DataOutputStream outToServer = new DataOutputStream(sock.getOutputStream());
sentence = input.nextLine();
outToServer.writeBytes(sentence);
Server addon:
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(sock.getInputStream()));
clientSentence = inFromClient.readLine();
System.out.println(clientSentence);
...but unfortunetly I have "Wait.." all the time for Client
TCP just transfers raw data. If you want to send files with a filename, you may want to use a higher level protocol, such as FTP or TFTP.
If you really want to use plain TCP, you'll need to encode the filename in your message somehow. You could, for example, send the filename as the first line of the message, and then have the other end turn the rest of the message into a file with that name.
This may be helpful to you: http://www.adp-gmbh.ch/blog/2004/november/15.html