I am trying to send a text file from a Java server to a C client. After I ran my code, the text file was received successfully but when i opened it, i found out that some random data had been inserted in the text file.
This is the server code for sending the file.
public void sendFile(Socket socket, String file) throws IOException
{
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[256];
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
fis.close();
dos.close();
}
And this is the client code for receiving the file.
int recv_file(int sock, char* file_name)
{
char send_str [MAX_SEND_BUF];
int fp;
int sent_bytes, rcvd_bytes, rcvd_file_size;
int recv_count;
unsigned int recv_str[MAX_RECV_BUF];
size_t send_strlen;
send_strlen = strlen(send_str);
if ( (fp = open(file_name, O_WRONLY|O_CREAT, 0644)) < 0 )
{
perror("error creating file");
return -1;
}
recv_count = 0;
rcvd_file_size = 0;
while ( (rcvd_bytes = recv(sock, recv_str, MAX_RECV_BUF/*256*/, 0)) > 0 )
{
recv_count++;
rcvd_file_size += rcvd_bytes;
if (write(fp, recv_str, rcvd_bytes) < 0 )
{
perror("error writing to file");
return -1;
}
printf("%dThe data received is %u\n", ++count, recv_str);
}
close(fp);
printf("Client Received: %d bytes in %d recv(s)\n", rcvd_file_size, recv_count);
return rcvd_file_size;
}
And this is the text file received at the client side.
Received text file
This gibberish is added to the text file, how do i resolve this issue?
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
Your copy loop is incorrect. You are writing junk at the end of the file, if not before. It should be:
int count;
while ((count = fis.read(buffer)) > 0) {
dos.write(buffer, 0, count);
}
You should not use a DataOutputStream because it provides no benefit here. Just use the plain OutputStream from the socket.
Then, you must make sure you only write as much data as there is in the file.
So instead of
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
use
OutputStream os = socket.getOutputStream();
int len;
while ( (len = fis.read(buffer)) > 0) {
os.write(buffer,0,len);
}
to make sure you only write as many bytes as there are in the file.
Related
I am learning sockets and now I want to write file transfer program. I have server part and client part. Server part contains 2 ports: 5000 (commands) and 5001 (files). Now I want to send a file via socket and when I did something is wrong because only 425B of data is sending.
Here is client send method:
private void sendFile(Socket socket) {
File file2 = new File("C:\\Users\\barte\\Desktop\\dos.png");
byte[] bytes = new byte[16 * 1024];
System.out.println(file2.exists());
try (InputStream inputStream = new FileInputStream(file2);
OutputStream outputStream = socket.getOutputStream();
OutputStream secondOutput = new FileOutputStream("C:\\Users\\barte\\Desktop\\received\\dos.png")) {
int count;
while ((count = inputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, count);
secondOutput.write(bytes, 0, count);
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
As you can see (image below) I am writing this file also locally and everything is ok, all of 73KB of data is writed.
Now, on server side I am trying to receive this file:
case SEND: {
new Thread(() -> {
printWriter.println("Server is receiving files right now...");
try (ServerSocket serverSocket = new ServerSocket(5001)) {
while (true) {
new FilesTransfer(serverSocket.accept()).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
break;
}
And inside FilesTransfer run method:
#Override
public void run() {
System.out.println("Hello there");
try {
InputStream inputStream = inSocket.getInputStream();
OutputStream outputStream = new FileOutputStream("C:\\Users\\barte\\Desktop\\received\\file");
byte[] bytes = new byte[16 * 1024];
int count;
while ((count = inputStream.read()) > 0) {
outputStream.write(bytes, 0, count);
}
outputStream.close();
inputStream.close();
inSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Where is a bug? Why only empty bytes are sending when locally everything it's fine?
The problem is:
while ((count = inputStream.read()) > 0) {
Your code uses InputStream.read(), which reads individual bytes (or -1 when end-of-stream). Right now, you are reading individual bytes, interpreting that as a length, and then writing that number of 0x00 bytes from bytes to the file. This stops when you read a 0x00 byte from the stream.
You need to change this to use InputStream.read(byte[]):
while ((count = inputStream.read(bytes)) != -1) {
That is, you need to pass bytes in, and check for the result being unequal to -1, not if it is greater than zero (0), although read(byte[]) will only return 0 if the passed in byte array has length zero, so that is not a real concern.
You could do it in this way:
#Override
public void run() {
System.out.println("Hello there");
try {
InputStream inputStream = inSocket.getInputStream();
OutputStream outputStream = new FileOutputStream("C:\\Users\\barte\\Desktop\\received\\file");
byte[] bytes = new byte[16 * 1024];
int byteRead= 1;
while (byteRead > -1) {
byteRead= inputStream.read();
outputStream.write(byteRead);
}
outputStream.close();
inputStream.close();
inSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Actually END OF FILE or EOF means -1 and you did > 0 so 0 was taken and it stopped the connection saving the file.
I also recommend to write a logic to transfer the filename as a command to the server so that the file is saved with the correct name and extension!
I'm making simple Client-Server application to make file copies on server.
There is clientside method for sending file to server:
private void makeCopy(Socket clientSock) throws IOException {
File file = new File("D:\\client\\toCopy.bmp");
File dest = new File("D:\\server\\copyFile.bmp");
boolean ifExists = dest.exists();
if(ifExists && !file.isDirectory()){
System.out.println("Copy is already made on server.");
}
else{
fis = new FileInputStream(file);
byte[] buffer = new byte[4096];
while (fis.read(buffer) > 0) {
oos.write(buffer);
}
//fis.close();
oos.close();
}
}
Also there is serverside method for receiving file from client:
public void saveFile(Socket s) throws IOException{
File copy = new File("D:\\server\\fileCopy.bmp");
fos = new FileOutputStream(copy);
File fromServer = new File("D:\\client\\toCopy.bmp");
if(copy.exists() && !copy.isDirectory()){
}
else{
byte[] buffer = new byte[4096];
int filesize = (int)fromServer.length();
int read = 0;
int totalRead = 0;
int remaining = filesize;
while((read = ois.read(buffer, 0, Math.min(buffer.length, remaining))) > 0) {
totalRead += read;
remaining -= read;
System.out.println("read " + totalRead + " bytes.");
fos.write(buffer, 0, read);
}
}
}
The problem is, even if i check file existance it still makes file which I can't open (it has 0 bytes written). Any ideas ?
FileOutputStream creates a file output stream and a file in a file system.
First you should check existence and then create FileOutputStream.
File copy = new File("D:\\server\\fileCopy.bmp");
if(copy.exists() && !copy.isDirectory()){ }
fos = new FileOutputStream(copy);
File fromServer = new File("D:\\client\\toCopy.bmp");
*i have have a folder in my pc in c:/ name share and in that i have 4 pictures after running my client and server code i got all 4 picture downloaded in my android emulator but only first image is correctly download other 3 are garbage
here is my code
SERVER SIDE
public class Multiplefilessending
{
public static void main(String[] args) throws IOException,EOFException
{
FileOutputStream fos;
BufferedOutputStream bos;
OutputStream output;
int len;
int smblen;
InputStream in;
boolean flag=true;
DataInputStream clientData;
BufferedInputStream clientBuff;
System.out.println("Waiting for Connection");
ServerSocket serverSocket = new ServerSocket(5991);
Socket clientSocket = null;
clientSocket = serverSocket.accept();
////////////////////////
File myFile = new File("C:/share");
File[] Files = myFile.listFiles();
OutputStream os = clientSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(Files.length);
for (int count=0;count<Files.length;count ++)
{
dos.writeUTF(Files[count].getName());
}
for (int count=0;count<Files.length;count ++)
{
int filesize = (int) Files[count].length();
dos.writeInt(filesize);
}
for (int count=0;count<Files.length;count ++)
{
int filesize = (int) Files[count].length();
byte [] buffer = new byte [filesize];
//FileInputStream fis = new FileInputStream(myFile);
FileInputStream fis = new FileInputStream(Files[count].toString());
BufferedInputStream bis = new BufferedInputStream(fis);
//Sending file name and file size to the server
bis.read(buffer, 0, buffer.length); //This line is important
dos.write(buffer, 0, buffer.length);
dos.flush();
//dos.close();
}
if (flag==false){
clientSocket = serverSocket.accept();
flag = true;
}
//Closing socket
//dos.close();
clientSocket.close();
}
}
And
CLIENT SIDE
Socket sock = new Socket("10.0.2.2", 5991);
System.out.println("Connecting.........");
FileOutputStream fos;
BufferedOutputStream bos;
OutputStream output;
DataOutputStream dos;
int len;
int smblen;
InputStream in;
boolean flag=true;
DataInputStream clientData;
BufferedInputStream clientBuff;
while (true)
{
//while(true && flag==true){
while(flag==true)
{
in = sock.getInputStream(); //used
clientData = new DataInputStream(in); //use
clientBuff = new BufferedInputStream(in); //use
int fileSize = clientData.read();
ArrayList<File>files=new ArrayList<File>(fileSize); ArrayList<Integer>sizes = new ArrayList<Integer>(fileSize); //store file size from client
//Start to accept those filename from server
for (int count=0;count < fileSize;count ++){
File ff=new File(clientData.readUTF());
files.add(ff);
}
for (int count=0;count < fileSize;count ++){
sizes.add(clientData.readInt());
}
for (int count =0;count < fileSize ;count ++)
{
if (fileSize - count == 1)
{
flag =false;
}
len=sizes.get(count);
//System.out.println("File Size ="+len);
output = new FileOutputStream("/mnt/sdcard/" + files.get(count));
dos=new DataOutputStream(output);
bos=new BufferedOutputStream(output);
byte[] buffer = new byte[1024];
bos.write(buffer, 0, buffer.length); //This line is important
while (len > 0 && (smblen = clientData.read(buffer)) > 0)
{
dos.write(buffer, 0, smblen);
len = len - smblen;
dos.flush();
}
dos.close(); //It should close to avoid continue deploy by resource under view
}
}
if (flag==false)
{
sock = new Socket("10.0.2.2", 5991);
flag = true;
}
} }
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
Your read loop is incorrect. You need to constrain the read length so you don't over-run into the next file:
while (len > 0 && (smblen = clientData,read(buffer, 0, len > buffer.length ? buffer.length : (int)len)) > 0)
{
bos.write(buffer, 0, smblen);
len -= smblen;
}
Other comments:
File lengths are longs, not ints.
Use a bigger buffer, at least 8192, and declare it once at the top of the method. You don't need a new one per file.
Don't flush inside the loop.
Don't keep recreating the streams. Use the same ones for the life of the socket, at both ends.
You should be writing to 'bos', not 'dos'. In fact you don't need the DataOutputStream to write to the file at all. Just the BufferedOutputStream and the FileOutputStream.
You should send one filename, one length, then one file, then the next filename, ... That way the sender can stop any time. That gets rid of the initial count, and it also gets rid of all that 'flag' nonsense. If you get EOFException reading the next name, the peer has closed the connection.
I have a Commons Net FTP file problem. I have an application which can transfer either a single file or a directory to a remote host, depending on what the user clicked on in a JTree. When I am transferring a particular directory, the transfer always fails on the same file, with a 'Software caused connection abort: socket write error'. When I select the same file and transfer it as a single file, it works fine. The relevant code for the directory transfer is:
BufferedOutputStream bos = new BufferedOutputStream(os,8*1024);
if (filelen > 500){
buffer = new byte[(int) (filelen/100)];
}else {
buffer = new byte[(int) filelen];
}
int len;
BufferedInputStream bis = new BufferedInputStream(is,8*1024);
int ba = bis.available();
while ((len = bis.read(buffer)) != -1 && ba != 0)
{
//os.write(buffer, 0, len);
System.out.println(ftp.getReplyString());
System.out.println("len is "+len);
System.out.println("ba is "+ba);
System.out.println("first two bytes are "+buffer[0]+buffer[1]);
System.out.println("last byte is "+buffer[buffer.length-1]);
System.out.println("buffer length is "+buffer.length);
int rc = ftp.getReplyCode();
if (rc == 550){
hftstatus.setText("Copy Error encountered, check log.");
return;
}
bos.write(buffer,0, len);
bos.flush();
System.out.println(ftp.getReplyString());
ba = bis.available();
if (filelen > 500){
if (len > 0){
left -=len;
totleft -=len;
}
}else{
left=0;
}
if (ba < buffer.length){
buffer = new byte[ba];
}
double ip = (left*100)/filelen;
int percomp = (int) (100-ip);
double ap = (totleft*100)/totlength;
int perallcomp = (int) (100-ap);
hftcurrfileprog.setValue(percomp);
hftallfileprog.setValue(perallcomp);
hftstatus.setText("Copying file "+f+" "+percomp+" percent completed.");
}
and the relevant code for a single file is:
BufferedOutputStream bos = new BufferedOutputStream(os,8*1024);
if (filelen > 500){
buffer = new byte[(int) (filelen/100)];
}else {
buffer = new byte[(int) filelen];
}
int len;
while ((len = bis.read(buffer)) != -1)
{
bos.write(buffer, 0, len);
int rc = ftp.getReplyCode();
if (rc == 550){hftstatus.setText("Copy Error encountered, check log.");}
bos.flush();
bytestran += len;
if (filelen > 100){
left = left-(filelen/100);
}else{
left=0;
}
double ip = (left*100)/filelen;
int percomp = (int) (100-ip);
hftcurrfileprog.setValue(percomp);
hftallfileprog.setValue(percomp);
if (bytestran == filelen){break;}
}
String outm = ftp.getReplyString();
System.out.println(outm);
bos.flush();
bos.close();
bis.close();
os.close();
is.close();
ftp.completePendingCommand();
System.out.println(ftp.getReplyString());
totleft = 0;
double ip = (left*100)/filelen;
int percomp = (int) (100-ip);
int perallcomp = 100;
hftcurrfileprog.setValue(percomp);
hftallfileprog.setValue(perallcomp);
hftstatus.setText("file "+fnode+" copied to directory "+remoteDirPath+nwd);
Any thoughts or clues would be much appreciated. I many hits somewhat close to this, but none where the only difference is in directory or single file transfer. Thank you for your help.
I am trying to write a server-client application for file transfer. The client is written in Java and the server is written in C++.
Unfortunately I have the following error:
java.net.SocketException: Connection reset by peer: socket write error"
Here is my code for client:
import java.io.*;
import java.net.Socket;
public class Proba_binar
{
public static void main(String[] args)
{
byte[] buffer = null;
byte[] auxByte = new byte[1000];
String fileName = "1.jpg";
File a_file = new File(fileName);
try
{
// Create a socket
Socket socket = new Socket("192.168.14.146", 8888);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Read file
FileInputStream fis = new FileInputStream(fileName);
int length = (int)a_file.length();
buffer = new byte[length];
fis.read(buffer);
fis.close();
// Send file length
System.out.println("length = " + Integer.toString(length));
out.write(Integer.toString(length) + "\n");
out.flush();
// Send file
int imageSize = buffer.length;
char[] auxChar = new char[1000];
int nr_transf = imageSize / 1000;
int rest_byte = imageSize % 1000;
System.out.println("nr_transf = " + nr_transf);
for(int j = 0; j < nr_transf; j++)
{
// send series of 1000 bytes
for(int i = 0; i < 1000; i++)
{
auxChar[i] = (char)buffer[j*1000+i];
auxByte[i] = buffer[j*1000+i];
}
out.write(auxChar);
out.flush();
}
// send last bytes
for(int i = 0; i < rest_byte; i++)
{
auxChar[i] = (char)buffer[1000*nr_transf+i];
auxByte[i] = buffer[1000*nr_transf+i];
}
out.write(auxChar, 0, rest_byte);
out.flush();
out.close();
in.close();
socket.close();
System.out.println("Transfer finished!");
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
And the code for server:
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s , new_socket;
struct sockaddr_in server , client;
int c, bytecount, nr_transf, rest_byte, i;
int recv_size, file_size;
char message[1000];
char buffer[1000];
int buffer_len = 1000;
FILE *f = fopen("out.jpg", "wb");
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
getch();
return 0;
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if(bind(s, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
getch();
return 0;
}
puts("Bind done");
//Listen to incoming connections
listen(s, 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(s, (struct sockaddr*)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d", WSAGetLastError());
getch();
return 0;
}
puts("Connection accepted");
//Receive FILE DIMENSION from client
if((recv_size = recv(new_socket, message, 1000, 0)) == SOCKET_ERROR)
{
puts("recv failed");
getch();
}
message[recv_size] = '\0';
file_size = atoi(message);
printf("\nfile_size = %d", file_size);
nr_transf = file_size / 1000;
rest_byte = file_size % 1000;
//Receive FILE from client
for(i = 0; i < nr_transf; i++)
{
// receive 1000 bytes
if((bytecount = recv(new_socket, buffer, buffer_len, 0)) == SOCKET_ERROR)
{
printf("Receive failed auxChar");
getch();
return 0;
}
fwrite(buffer, 1, buffer_len, f);
}
// receive last bytes
if((bytecount = recv(new_socket, buffer, rest_byte, 0)) == SOCKET_ERROR)
{
printf("Receive failed rest_byte");
getch();
return 0;
}
fwrite(buffer, 1, rest_byte, f);
fclose(f);
printf("Receive finished!");
closesocket(s);
WSACleanup();
getch();
return 0;
}
I made equivalent server in Java and works perfectly.
I do not know what the problem is in c + + version.
Thanks in advance!
recv() does not guarantee that it will read all bytes requested:
...calling recv will return as much data as is currently available—up to the size of the buffer specified...
This means that the for/recv loop is incorrectly structured and it is probably the case that the server believes it has read all the data but it has not. This results in the server closing the socket before the client has sent all the data, resulting in the error reported by the Java client.
Example (untested) restructuring of the recv loop:
int totalBytesRead = 0;
int bytesRead;
while (totalBytesRead < file_size)
{
if((bytesRead = recv(new_socket, buffer, buffer_len, 0)) == SOCKET_ERROR)
{
/* Handle failure. */
break;
}
if (bytesRead != fwrite(buffer, 1, bytesRead, f))
{
/* Handle failure. */
break;
}
totalBytesRead += file_size;
}
Remember that connected sockets are stream based, using mutilple send()s does not imply that the matching recv()s will read the data in the same "chunks" as they were sent. In addition to the data content retrieval error already mentioned, this equally applies to the reading of the file size. There is no guarantee that entire file size will be read.
I would recommend designing a simple protocol to ensure the different types of data are correctly read. For example, client sends:
<file_size>\n<file_content>
the server reads all data up to the newline character and converts it into the file size. The server then knows for certain it has the correct file size. The server then reads file_size bytes from the socket. Finally, server responds to indicate success or failure:
success\n
the client reads up to the newline character to obtain the response.