I just realized that DataInputStream and DataOutputStream in writing reading socket
could be used to differentiate the input that was coming over.
Check this code:
Server Side. (receiving string or file)
Socket bSock = serverSocket.accept();
DataInputStream inp = new DataInputStream(bSock.getInputStream());
int iCode = inp.readInt();
switch (iCode) {
case Request.STATE_FILESHARING:
byte bp[] = new byte[iCode];
FileOutputStream fos = new FileOutputStream("s.pdf");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = inp.read(bp, 0, bp.length);
bos.write(bp, 0, bytesRead);
bos.close();
break;
case Request.STATE_CONVERSATION:
requestFound = new Request(inp.readUTF());
sendToUI(requestFound);
break;
}
Client Side. (sending string or file)
Socket socket = new Socket(myServerAddress, SocketServerPORT);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
if (isThisFileMode()) {
File myFile = new File(sLocationFile);
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray, 0, mybytearray.length);
out.writeInt(Request.STATE_FILESHARING);
out.write(mybytearray, 0, mybytearray.length);
out.flush();
} else {
out.writeInt(Request.STATE_CONVERSATION);
out.write(obReq.toString().getBytes());
out.flush();
}
But I ended up with Error. System crashed!
Anything that I forgot to add?
You're using readUTF() but not writeUTF(). Nearly all the methods of DataInputStream and DataOutputStream are symmetrical: if you call readXXX() you must call writeXXX() at the other end.
You're making the usual mistake of assuming that read() fills the buffer. It is only contracted to transfer at least one byte. You must loop:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
You need to close the socket at both server and client.
Related
I try to send a java application file to a .Net application (c #) using a socket. Here is what I did Java (server side)
ServerSocket serverSocket = new ServerSocket(1592);
Socket socket = serverSocket.accept();
System.out.println("Connection accepted from " + socket);
PrintWriter out = new PrintWriter(socket.getOutputStream());
File file = new File("C:\\test.txt");
Thread.sleep(2000);
out.println(file.length());
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[(int) file.length()];
bis.read(bytes, 0, bytes.length);
os.write(bytes, 0, bytes.length);
C#(client)
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(ip, 1592);
using (var stream = tcpClient.GetStream())
using (var output = File.Create("result.txt"))
{
Console.WriteLine("Client connected. Starting to receive the file");
// read the file in chunks of 1KB
var buffer = new byte[1024];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)//(Exception caught here)
{
output.Write(buffer, 0, bytesRead);
}
I had an exception in the specified line containing the following problem
Additional information: Unable to read data from the transport connection: Une connexion existante a dû être fermée par l’hôte distant.
Please any help , i've been facing the issue since few days , and i could not figure it out .
Thank you in advance
The Client is running, but the service is not available. (stopped, crashed..). Perhaps, the Firewall block the connection
Verify that the firwall not blocking your server
You must debug you code and verify its behavior (exception, etc..)
regards
I have my client server chat
Client sends files and server receives them. But, the problem is that, i don't think that files are received properly because when i check the size of the files i see the difference is halfed for some reasons!
I am using GUI to browse for files in the client side, and then i'm sending a command to the server to know that the client is sending a file. But it is not working
Here is the client and server
public void sendFiles(String file) {
try {
BufferedOutputStream outToClient = null;
outToClient = new BufferedOutputStream(sock.getOutputStream());
System.out.println("Sending file...");
if (outToClient != null) {
File myFile = new File( file );
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = null;
fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
this.out.println("SF");
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
this.out.flush();
outToClient.flush();
outToClient.close();
System.out.println("File sent!");
return;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server
public void recvFile() {
try {
byte[] aByte = new byte[1];
int bytesRead;
InputStream is = null;
is = sock.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (is != null) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream("/Users/Documents/Received.png");
bos = new BufferedOutputStream(fos);
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
bos.write(baos.toByteArray());
bos.flush();
bos.close();
// clientSocket.close();
} catch (IOException ex) {
// Do exception handling
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Can someone help me with this issue? As i don't know how to properly send and receive files
Thank you
You are using two copy techniques, and they are both wrong.
First:
byte[] mybytearray = new byte[(int) myFile.length()];
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
Here you are assuming:
That the file fits into memory.
That the file length fits into an int.
That read() fills the buffer.
None of these assumptions is valid.
Second:
byte[] aByte = new byte[1];
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
Here you are:
Using a ridiculously small buffer of one byte.
Writing an extra byte if the file length is zero.
Using a do/while where the situation naturally calls for a while (as 99.99% of situations do), and therefore:
Using two read() calls, and only correctly checking the result of one of them.
Pointlessly using a ByteArrayOutputStream, which, as above, assumes the file fits into memory and that its size fits into an int. It also pointlessly adds latency.
Throw them both away and use this, at both ends:
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
where:
in is a FileInputStream in the case of sending the file, or the socket input stream in the case of receiving the file.
out is a FileOutputStream in the case of receiving the file, or the socket output stream in the case of sending the file
I'm writing a program to download/upload a file between a client and server using socket programming. The code i've written till now works in the sense that i can sucesfully transfer files. However , if a connection fails due to problem in the network/client/server while a download / upload is occuring.. i need to RESUME the download/upload from the original point(Do not want the originally sent data to be resent). I'm not sure how to go about this. I'm reading the file into a byte array and sending it across the network. My initial idea is that everytime i'm downloading.. i should check if the file already exists and read the data into a byte array --> send the data to the server for comparison and then return the remaining data from the server file by comparing the two byte arrays. But this seems inefficient and takes away the point of resuming a download(since i'm sending the data again).
Note: The file name is an unique identifier.
I would really appreciate it if anybody could give me suggestions as to how i should implement the file resume functionality?
Server side code:
package servers;
import java.io.*;
import java.net.*;
import java.util.Arrays;
public class tcpserver1 extends Thread
{
public static void main(String args[]) throws Exception
{
ServerSocket welcomeSocket = null;
try
{
welcomeSocket = new ServerSocket(5555);
while(true)
{
Socket socketConnection = welcomeSocket.accept();
System.out.println("Server passing off to thread");
tcprunnable tcprunthread = new tcprunnable(socketConnection);
Thread thrd = new Thread(tcprunthread);
thrd.start();
System.out.println(thrd.getName());
}
}
catch(IOException e){
welcomeSocket.close();
System.out.println("Could not connect...");
}
}
}
class tcprunnable implements Runnable
{
Socket socke;
public tcprunnable(Socket sc){
socke = sc;
}
public void download_server(String file_name)
{
System.out.println("Inside server download method");
try
{
System.out.println("Socket port:" + socke.getPort());
//System.out.println("Inside download method of thread:clientsentence is:"+clientSentence);
// Create & attach output stream to new socket
OutputStream outToClient = socke.getOutputStream();
// The file name needs to come from the client which will be put in here below
File myfile = new File("D:\\ "+file_name);
byte[] mybytearray = new byte[(int) myfile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myfile));
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
System.out.println("Arrays on server:"+Arrays.toString(mybytearray));
outToClient.flush();
bis.close();
}
catch(FileNotFoundException f){f.printStackTrace();}
catch(IOException ie){
ie.printStackTrace();
}
}
public void upload_server(String file_name){
try{
byte[] mybytearray = new byte[1024];
InputStream is = socke.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fos = new FileOutputStream("D:\\ "+file_name);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
do {
baos.write(mybytearray);
bytesRead = is.read(mybytearray);
}
while (bytesRead != -1);
bos.write(baos.toByteArray());
System.out.println("Array on server while downloading:"+Arrays.toString(baos.toByteArray()));
bos.close();
}
catch(FileNotFoundException fe){fe.printStackTrace();}
catch(IOException ie){ie.printStackTrace();}
}
#Override
public void run()
{
try
{
System.out.println("Server1 up and running" + socke.getPort());
// Create & attach input stream to new socket
BufferedReader inFromClient = new BufferedReader
(new InputStreamReader(socke.getInputStream()));
// Read from socket
String clientSentence = inFromClient.readLine();
String file_name = inFromClient.readLine();
System.out.println("Sever side filename:" + file_name);
try{
if(clientSentence.equals("download"))
{
download_server(file_name);
}
else if(clientSentence.equals("upload"))
{
upload_server(file_name);
System.out.println("Sever side filename:" + file_name);
}
else
{
System.out.println("Invalid input");
}
}
catch(NullPointerException npe){
System.out.println("Invalid input!");
}
socke.close();
}
catch(IOException e)
{
e.printStackTrace();
System.out.println("Exception caught");
}
}
}
Client side code:
package clients;
import java.io.*;
import java.net.*;
import java.util.Arrays;
public class tcpclient1
{
public static void main (String args[]) throws Exception
{
// Create input stream to send sentence to server
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = null;
while(true){
System.out.println("Please enter the server you want to use");
System.out.println("Enter 1 for Server 1 and 2 for Server2");
String server_choice = inFromUser.readLine();
if(server_choice.equals("1")){
// Create client socket to connect to server
// The server to use will be specified by the user
clientSocket = new Socket("localhost",5555);
break;
}
else if(server_choice.equals("2"))
{
clientSocket = new Socket("localhost",5556);
break;
}
else
{
System.out.println("Invalid entry");
}
}
System.out.println("Please enter download for dowloading");
System.out.println("Please enter upload for uploading");
// sentence is what'll be received from input jsp
String sentence = inFromUser.readLine();
if(sentence.equals("download"))
{
download_client(clientSocket,sentence);
}
else if(sentence.equals("upload"))
{
upload_client(clientSocket,sentence);
}
else
{
System.out.println("Invalid input");
}
clientSocket.close();
}
public static void download_client(Socket clientSocket , String sentence)
{
try{
// Create output stream attached to socket
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
// Send line to server
outToServer.writeBytes(sentence+'\n');
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the name of file to download:");
String file_to_download = inFromUser.readLine();
if(searching(file_to_download))
{
// Read local file and send that to the server for comparison
// DONT THINK THIS IS THE RIGHT WAY TO GO ABOUT THINGS SINCE IT BEATS THE PURPOSE OF RESUMING A DOWNLOAD/UPLOAD
}
// Send filetodownload to server
outToServer.writeBytes(file_to_download+'\n');
byte[] mybytearray = new byte[1024];
InputStream is = clientSocket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fos = new FileOutputStream("E:\\ "+file_to_download);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
do {
baos.write(mybytearray);
bytesRead = is.read(mybytearray);
}
while (bytesRead != -1);
bos.write(baos.toByteArray());
System.out.println("Array on client while downloading:"+Arrays.toString(baos.toByteArray()));
bos.close();
}
catch(FileNotFoundException fe){fe.printStackTrace();}
catch(IOException ie){ie.printStackTrace();}
}
public static void upload_client(Socket clientSocket, String sentence)
{
try{
// Create output stream attached to socket
DataOutputStream outToServer1 = new DataOutputStream(clientSocket.getOutputStream());
// Send line to server
outToServer1.writeBytes(sentence+'\n');
System.out.println("In the client upload method");
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the name of file to upload:");
String file_to_upload = inFromUser.readLine();
//System.out.println("Cline side file name:"+file_to_upload);
outToServer1.writeBytes(file_to_upload+'\n');
System.out.println(file_to_upload);
OutputStream outtoserver = clientSocket.getOutputStream();
File myfile = new File("E:\\ "+file_to_upload);
byte[] mybytearray = new byte[(int) myfile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myfile));
bis.read(mybytearray, 0, mybytearray.length);
outtoserver.write(mybytearray, 0, mybytearray.length);
System.out.println("filename:"+file_to_upload+"Arrays on client while uploading:"+Arrays.toString(mybytearray));
outtoserver.flush();
bis.close();
}
catch(FileNotFoundException fe){fe.printStackTrace();}
catch(IOException ie){ie.printStackTrace();}
}
public static boolean searching(String file_name)
{
String file_path = "E:\\ "+file_name;
File f = new File(file_path);
if(f.exists() && !f.isDirectory()) { return true; }
else
return false;
}
}
The above code runs fine for transferring files between the client and server.
Again , would really appreciate any help!
There are many ways which you can do this, I suggest you to create a separate type of request to the server that accepts the file's name and file position which is the position where in the file where the connection failed.
That's how you will get the file from the server in the client's side:
int filePosition = 0;
InputStream is = clientSocket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
do {
baos.write(mybytearray);
bytesRead = is.read(mybytearray);
if(bytesRead != -1)
filePosition += bytesRead;
}
while (bytesRead != -1);
Now if the connection got interrupted for some reason you can send a request again to the server with the same file name and the filePosition, and the server will send the file back like this:
OutputStream outToClient = socke.getOutputStream();
// The file name needs to come from the client which will be put in here below
File myfile = new File("D:\\ "+file_name);
byte[] mybytearray = new byte[(int) myfile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myfile));
bis.skip(filePosition) //Advance the stream to the desired location in the file
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
System.out.println("Arrays on server:"+Arrays.toString(mybytearray));
outToClient.flush();
bis.close();
And in the client you can open the file stream and specify append = true in the constructor like this:
FileOutputStream fos = new FileOutputStream("D:\\ "+file_name, true);
This could be one way to do this, there are a lot more options. And I also suggest verify the files after the transfer using some hash function like MD5 for example, it creates unique stamp for a given input and it always outputs same result for the same input, which means, you can create the stamp from the same file both in the server and in the client and if the file is truly the same, it will generate the same stamp. Since the stamp's size is very small relative to the file it self and it is also fixed, it can be send between the client/server without much overhead.
You can generate an MD5 hash with this code:
MessageDigest md = MessageDigest.getInstance("MD5");
try (InputStream is = Files.newInputStream(Paths.get("file.txt"))) {
DigestInputStream dis = new DigestInputStream(is, md);
/* Read stream to EOF as normal... */
}
byte[] digest = md.digest();
(taken from: Getting a File's MD5 Checksum in Java)
Basically, when requesting a download You should attach information about how many bytes need to be skipped (0 on new download). You should get this information from part of the file that you have downloaded (read it's size). Server should skip given count of bytes and send back the remainder of file. Client should append this to the existing file. For sanity check, You could add some file hash checking in the end, to ensure You got the file correctly.
I am trying to send Files with JAVA. My problem is that the client never knows if the end of the file is reached or not. So the while loop of the Client never ends. Please help me.
Server (sends Data to Client)
File myFile = new File("C://LEGORacers.exe");
byte[] mybytearray = new byte[(int) myFile.length()];
BufferedInputStream bis = null;
OutputStream os = null;
bis = new BufferedInputStream(new FileInputStream(myFile));
bis.read(mybytearray, 0, mybytearray.length);
os = socket.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
os.flush();
bis.close();
Client (gets Data from Server)
byte[] buf = new byte[1024];
InputStream is = null;
int bytesRead = 0;
is = client.getInputStream();
FileOutputStream fos = null;
fos = new FileOutputStream("C://copy.exe");
BufferedOutputStream bos = new BufferedOutputStream(fos);
try {
while (-1 != (bytesRead = is.read(buf, 0, buf.length))) {
// This while loop never ends because is.read never returns -1 and I don't know why...
bos.write(buf, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
is.close();
bos.flush();
bos.close();
fos.close();
}
Did you close your OutputStream on your Server? If not, your loop might be perpetually setting bytesRead to 0, so you may need to close that stream.
If you need the Server's OutputStream to still be open after sending data, you could also send the size of the data in bytes at the beginning of the stream, and loop until you have all of the bytes the Server indicates it will send.
Close the socket output stream on the server. Flushing doesn't terminate the stream, which is what you need to do to send the signal that the server is done writing. From what you posted, I don't see where you close the output stream on the server side.
I have a Java server class like this:
ServerSocket servsock = new ServerSocket(63456);
boolean read = false;
while (!read) {
Socket sock = servsock.accept();
int length = 1024;
byte[] mybytearray = new byte[length];
OutputStream os = sock.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
while (true) {
int i = bis.read(mybytearray, 0, mybytearray.length);
if (i == 1) {
break;
}
os.write(mybytearray, 0, mybytearray.length);
os.flush();
}
sock.close();
read = true;
}
`
And the client is like this:
Socket sock = new Socket("127.0.0.1", 63456);
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("C:/tmp/NEWtmp.rar");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
while(bytesRead != -1 ) {
bos.write(mybytearray, 0, bytesRead);
bytesRead = is.read(mybytearray, 0, mybytearray.length);
}
bos.close();
sock.close();
One question is: Why the loop does not stop at the end of the file?
A second question would be, why is also so slow?
It does not stop because
if (i == 1) {
in your server source should be
if (i == -1) {
Or, if you want to be really safe:
if (i <= 0) {
Also, you risk data corruption with this line:
os.write(mybytearray, 0, mybytearray.length);
You should change this to:
os.write(mybytearray, 0, i);
On performance -- move the os.flush(); call to outside the while loop. When you flush a network stream, you are forcing it to dispatch any buffered data to the network. This is forcing the network layer to send and acknowledge 1024-byte TCP payloads (larger Ethernet payloads, of course) which is probably significantly smaller than your PMTU. You only need to flush when you are done sending data, or when you want the client to receive the buffered data now. Removing the flush call from each iteration will allow the OS-level network buffer to do its job, and segment the data into as few packets as possible.
Second question - your client reads bytes directly from the raw socket stream. Use the BufferedInputStream/BufferedOutputStream decorators, this should increase performance:
Server Side
BufferedOutputStream os = new BufferedOutputStream(sock.getOutputStream());
Client side
BufferedInputStream is = new BufferedInputStream(sock.getInputStream());
The raw streams are not buffered (AFAIK) so you have to add the buffering manually, if needed.