I need some help.
I have server socket side wrote in java and client socket side in C++.
I'm trying to send prepared XML file from server to client, seems it works but after all received file is broken at client side (only nulls in this file).
Where is the problem?
Server side sending code:
public void SendBytes() throws IOException {
File myFile = new File(XML.prepareFile());
int fileSize = (int) myFile.length();
byte[] mybytearray = new byte[fileSize];
FileInputStream fis = null;
BufferedInputStream bis = null;
fis = new FileInputStream(myFile);
bis = new BufferedInputStream(fis);
try {
output.write(mybytearray, 0, mybytearray.length);
output.flush();
} catch (Exception e) {
System.out.println("sendBytes(); output error");
}
fis.close();
bis.close();
output.close();
}
and the Client C++ side receiving method code:
int Client::RecvBytes2() {
char buffer[4096];
int iNumBytes = 0;
iNumBytes = recv(m_iSock, buffer, 4096, 0);
char tmp[iNumBytes];
for (int i = 0; i < iNumBytes; i++) {
tmp[i] = buffer[i];
}
std::ofstream fout("receivedFile.xml", std::ios::out | std::ios::binary);
fout.write(tmp, iNumBytes);
return iNumBytes;
}
Related
I have two problems with my java server-client file communication,
I have the CLIENT sends files over to the server and the SERVER receives the files.
My 2 issues are:
1) whenever i send a file, it is 8 bytes less (i do not know why)
2) the file transfer is not complete (with 8 bytes less) unless i close the socket, which i do not want. i want my connection to be persistent, so how can i send a EOF from the client to the server.
here is my client who sends files
public void sendFiles(String file) {
try {
File myFile = new File(file);
long length = myFile.length();
byte[] buffer = new byte[8192];
System.out.println(length);
FileInputStream in = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(in);
BufferedOutputStream outF = new BufferedOutputStream(sock.getOutputStream());
out.print("%SF%" + length + "$" + myFile.getName() + "#");
out.flush();
int count;
while ((count = in.read(buffer)) > 0) {
outF.write(buffer, 0, count);
}
outF.flush();
in.close();
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
SERVER who receives files.
I'm passing the name and the length of the file but only using the name of the file. however, i don't know if i need to use the length of the file or not, in case of EOF or something. Please advice
Also, The code hangs in
while ((count = this.sock.getInputStream().read(buffer)) > 0) {
due to no EOF which i do not know how to implement
public void recvFile(String fileName, int length) {
try {
byte[] buffer = new byte[8192];
FileOutputStream outF = new FileOutputStream("/Users/Documents" +fileName);
BufferedOutputStream bos = new BufferedOutputStream(outF);
int count = length;
while ((count = this.sock.getInputStream().read(buffer)) > 0) {
bos.write(buffer, 0, count);
}
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
UPDATE: I have removed the flush() as advised that it is not needed. Also, i have tested this code in a different class and it worked but it doesn't work here with client-server chat. Could anyone tell me why?
Any help or hints would be appreciated.
Thank you.
I would suggest to you send the file size first and/or properties of the file... You can try HTTP which is wide use for this task...
Another suggestion would be for you to open another connection on other TCP port just to send the file (this is actually how FTP sends files)
I suspect the problem you have is in code you haven't shown.
In this example you can send multiple messages or files over the same stream.
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SocketChannel;
/**
* Created by peter on 1/25/15.
*/
public class DataSocket implements Closeable {
private final Socket socket;
private final DataOutputStream out;
private final DataInputStream in;
public DataSocket(Socket socket) throws IOException {
this.socket = socket;
this.out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
this.in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
}
#Override
public void close() throws IOException {
out.flush();
socket.close();
}
// message format is length as UTF-8 encoded name, 32-bit int followed by data.
public void writeMessage(String description, byte[] bytes) throws IOException {
out.writeUTF(description);
out.writeInt(bytes.length);
out.write(bytes);
out.flush();
}
public byte[] readMessage(String[] description) throws IOException {
description[0] = in.readUTF();
int length = in.readInt();
byte[] bytes = new byte[length];
in.readFully(bytes);
return bytes;
}
public void writeFile(File file) throws IOException {
long length = file.length();
if (length > Integer.MAX_VALUE) throw new IllegalArgumentException("length=" + length);
out.writeUTF(file.toString());
out.writeInt((int) length);
byte[] buffer = new byte[(int) Math.min(length, 32 * 1024)];
try (FileInputStream fis = new FileInputStream(file)) {
for (int len; (len = fis.read(buffer)) > 0; ) {
out.write(buffer, 0, len);
}
}
out.flush();
}
public void readFile(File dir) throws IOException {
String fileName = in.readUTF();
int length = in.readInt();
byte[] buffer = new byte[(int) Math.min(length, 32 * 1024)];
try (FileOutputStream fos = new FileOutputStream(new File(dir, fileName))) {
while (length > 0) {
int len = in.read(buffer);
fos.write(buffer, 0, len);
length -= len;
}
}
}
// todo convert to a unit test
public static void main(String[] args) throws IOException {
// port 0 opens on a random free port.
ServerSocket sc = new ServerSocket(0);
DataSocket ds1 = new DataSocket(new Socket("localhost", sc.getLocalPort()));
DataSocket ds2 = new DataSocket(sc.accept());
sc.close();
// now ds1 and ds2 are connected.
File f = File.createTempFile("deleteme","");
f.deleteOnExit();
try (FileOutputStream fos = new FileOutputStream(f)) {
fos.write(new byte[10001]);
}
// send a request
ds1.writeMessage("Send me the file", new byte[0]);
String[] desc = { null };
byte[] data = ds2.readMessage(desc);
if (!desc[0].equals("Send me the file")) throw new AssertionError();
// return a response
ds2.writeFile(f);
f.delete();
if (f.exists()) throw new AssertionError();
ds1.readFile(new File(""));
if (f.length() != 10001) throw new AssertionError("length="+f.length());
ds1.close();
ds2.close();
System.out.println("Copied a "+f.length()+" file over TCP");
}
}
I am having trouble with my client/server program. The server is supposed to get a file from the client then convert it to xml, and then stream the xml file back to the client.
As of now everything works up to the point of streaming the xml file back to the client. I can successfully send my file to the server and convert it to XML.
The server does not send anything to the client. The client is stuck in the area of reading bytes in from the InputStream. On line 57 in the Client class.
public class Server {
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public static void main(String[] args) {
int port = 8081;
Server srv = new Server(port);
}
public Server(int portNumber) {
try {
serverSocket = new ServerSocket(portNumber);
clientSocket = serverSocket.accept();
out = new PrintWriter(clientSocket.getOutputStream(), true);
//in = new BufferedReader(
//new InputStreamReader(clientSocket.getInputStream()));
byte[] myArray = new byte[22000]; // should be file size
InputStream is = clientSocket.getInputStream();
FileOutputStream fos = new FileOutputStream("file.csv");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead;
int current = 0;
bytesRead = is.read(myArray, 0, myArray.length);
current = bytesRead;
do {
bytesRead = is.read(myArray, current, (myArray.length - current) );
if (bytesRead >= 0)
current += bytesRead;
} while (bytesRead > -1);
bos.write(myArray, 0, myArray.length);
bos.flush();
boolean flag = false;
System.out.println("Server: finished receiving file");
XMLWriter xmlWrite = new XMLWriter();
xmlWrite.createXmlDocument("file_copy.csv");
sendXML("server_file.XML");
clientSocket.close();
System.out.println("Server: disconnected with client");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void sendXML(String fileName) {
System.out.println("Sending file");
File file = new File(fileName);
BufferedInputStream bis;
try {
FileInputStream fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
DataInputStream dataIn = new DataInputStream( bis );
OutputStream outStream = clientSocket.getOutputStream();
int length;
try {
length = dataIn.readInt();
System.out.println("S: " + dataIn.readInt());
byte[] data = new byte[ length ];
dataIn.readFully(data, 0, data.length);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public class Client {
private Socket mainSocket;
public static void main(String[] args) {
int port = 8081;
Client cli = new Client(port);
}
public Client(int portNumber) {
try {
mainSocket = new Socket("localhost", portNumber);
// send file to server
File file = new File("Passengers.csv");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream outStream = mainSocket.getOutputStream();
byte[] myBytes = new byte[(int) file.length()];
bis.read(myBytes, 0, myBytes.length);
outStream.write(myBytes, 0, myBytes.length);
outStream.flush();
System.out.println("Client: Done sending file");
byte[] fileData = new byte[30000];
InputStream is = mainSocket.getInputStream();
FileOutputStream fos = new FileOutputStream("client_file.XML");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dataOut = new DataOutputStream( bos );
dataOut.writeInt( fileData.length );
dataOut.write( fileData );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This loop will run until the stream is closed, not until the client finishes sending data.
do {
bytesRead = is.read(myArray, current, (myArray.length - current) );
if (bytesRead >= 0)
current += bytesRead;
} while (bytesRead > -1);
This is because InputStream.read will block until at least one byte of data is available or the stream is closed, causing a -1 to be returned. Since the client is done sending data but the stream is still open it will block forever.
A solution is to first send the length of the file in the first 4 bytes using something like DataOutputStream/DataInputStream, and then have the client send exactly that many bytes and the server read exactly that many bytes before moving on.
Client:
// Connect to the server and read in file data
byte[] fileData = ...;
DataOutputStream dataOut = new DataOutputStream( outStream );
dataOut.writeInt( fileData.length );
dataOut.write( fileData );
// Get reply from server
Server:
// Create ServerSocket and get Client connection
DataInputStream dataIn = new DataInputStream( is );
int length = dataIn.readInt();
byte[] data = new byte[ length ];
dataIn.readFully( data );
// Continue to process client connection
The general idea behind this kind of network communication is that every block of data, or packet, is prefixed with it's length before being send. This means that the recipient of the data can read in that number and know exactly how many bytes remain to form the complete block or packet. Communication goes along something like this for both sides of the connection. The only difference is in how you process the data.
public byte[] readPacket( DataInputStream dataIn ) throws IOException {
int length = dataIn.readInt();
byte[] packet = new byte[ length ];
dataIn.readFully( packet );
return packet;
}
public void writePacket( DataOutputStream dataOut, byte[] packet ) throws IOException {
dataOut.writeInt( packet.length );
dataOut.write( packet );
}
Only you would call these from some sort of loop preferably on background threads but it's not required for what you want to do. For your case you want to read in the file on the client side into a byte[] and then use writePacket to send it to the server. On the server side you would use readPacket to read in the file from the client. The same thing takes place when sending data back to the client but with the roles switched.
I'm trying to send my image from android client to Java server. Size of image that i'm sending is about 99kb, but server always reads a few kb less, sometimes 98, sometimes 96 and so on. I'd like to know why that data is lost and how can I send image in a proper way. Please help :)
Code:
Client(sending image):
public void sendImage(File file){
try {
out = new PrintWriter(socket.getOutputStream(),true);
out.println("Image");
out.println(file.length());
byte[] byteArray = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(byteArray,0,byteArray.length);
OutputStream os = socket.getOutputStream();
FilterOutputStream bos = new FilterOutputStream(os);
bos.write(byteArray,0,byteArray.length);
bos.flush();
os.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server(receiving image):
if(input.equals("Image")){
input = in.readLine();
int fileSize = Integer.parseInt(input);
System.out.println("FILESIZE:" +fileSize);
byte[] byteArray = new byte[fileSize];
FileOutputStream fileOutputStream =
new FileOutputStream("filename.jpg");
BufferedOutputStream bos =
new BufferedOutputStream(fileOutputStream);
BufferedInputStream bis = new BufferedInputStream(in_);
int bytesRead = bis.read(byteArray, 0, byteArray.length);
int current = bytesRead;
do {
bytesRead = bis.read(byteArray, current,
(byteArray.length - current));
if (bytesRead >= 0) {
current += bytesRead;
System.out.println(current);
}
} while (bytesRead != -1);
bos.write(byteArray, 0, current);
bos.flush();
bos.close();
}
EDIT
Problem solved, working code is as follows:
Client side:
public void sendImage(File file){
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I');
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server side:
if(input =='I'){
DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
long length = dis.readLong();
File to = new File("filename.jpg");
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len, current = 0;
System.out.println(length);
while ( current != length) {
len = dis.read(buffer);
dos.write(buffer, 0, len);
current += len;
System.out.println(current);
}
dis.close();
dos.close();
}
From my personal experience PrintWriter and Buffers dont work well together..
As buffers trying to read data before you tell it to it can "steal" data that it should not do. For example if you use any kind of buffered reader to read the input on the server side that buffer will steal some parts at the "start" of the incomming image becuase it think's it's just another line. You could always try using DataInputStream and DataOutputStream instead..
Client:
public void sendImage(File file) {
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I'); // as image,
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server:
// assuming folder structure exists.
public void readImage(Socket s, File to) throws IOException {
DataInputStream dis = new DataInputStream(s.getInputStream());
char c = dis.readChar();
if (c == 'I') {
long length = dis.readLong();
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len;
while ((len = dis.read(buffer)) != -1) {
dos.write(buffer, 0, len);
}
dis.close();
dos.close();
}
}
As a starting point, in the client side, you will also need a loop for reading the local image, because are you sure that...
bis.read(byteArray,0,byteArray.length);
... is really reading the whole image? So you will also need a loop as in the server side.
*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 am using java sockets for communication. On the client side I have some processing and at this point I send an object to the cient. The code is as follows:
while (true) {
try {
Socket server = new Socket("localhost", 3000);
OutputStream os = server.getOutputStream();
InputStream is = server.getInputStream();
CommMessage commMessage = new CommMessageImpl();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(commMessage);
os.write(bos.toByteArray());
os.flush();
byte[] buff = new byte[512];
int bytesRead = 0;
ByteArrayOutputStream receivedObject = new ByteArrayOutputStream();
while ((bytesRead = is.read(buff)) > -1) {
receivedObject.write(buff, 0, bytesRead);
System.out.println(receivedObject);
}
os.close();
Thread.sleep(10000);
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
Next on the server side I have the following code to read the object and write the response (Which is just an echo message)
public void startServer() {
Socket client = null;
try {
server = new ServerSocket(3000);
logger.log(Level.INFO, "Waiting for connections.");
client = server.accept();
logger.log(Level.INFO, "Accepted a connection from: " + client.getInetAddress());
os = new ObjectOutputStream(client.getOutputStream());
is = new ObjectInputStream(client.getInputStream());
// Read contents of the stream and store it into a byte array.
byte[] buff = new byte[512];
int bytesRead = 0;
ByteArrayOutputStream receivedObject = new ByteArrayOutputStream();
while ((bytesRead = is.read(buff)) > -1) {
receivedObject.write(buff, 0, bytesRead);
}
// Check if received stream is CommMessage or not contents.
CommMessage commMessage = getCommMessage(receivedObject);
if (commMessage != null) {
commMessage.setSessionState(this.sessionManager.getState().getState());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(commMessage);
os.write(bos.toByteArray());
System.out.println(commMessage.getCommMessageType());
} else {
processData(receivedObject, this.sessionManager);
}
os.flush();
} catch (IOException e) {
} finally {
try {
is.close();
os.close();
client.close();
server.close();
} catch (IOException e) {
}
}
}
The above code works ok if I do not try to read data on the client side (If i exclude the code related to reading). But if I have that code, for some reason, I get some kind of deadlock when accessing input streams. Any ideas what I might have done wrong? Thanks in advance.
Both client and server are attempting to read the whole input stream (i.e. everything up to EOF) but neither is sending an EOF (by calling shutdownOutput() on the socket.)
Why do you need to store the object data temporarily in a ByteArrayOutputStream? This would probably be easier to fix if you read directly from the socket input stream.