Java server receiving large data over TCP slower than expected - java

I'm writing a simple TCP server in java to receive image data from a client and then process it. The client is connected to the server over a 25Gbit network but the data transfer speed is limited around 4.5Gbit/s.
The client (winserv 2016) is recording data from an sCMOS camera at 100fps (8MB each frame) and then write the data directly to the TCP socket. The server (Centos7) then read the data and write it out. The server read data image by image. The downstream disk writing throughput is not the issue since I tried without writing the data out and see the same kind of performance. Using iperf between the windows client and linux server gives the expected bandwidth (20+ Gbit/s). Is this normal to have such a bit network speed difference between iperf and TCP traffic ?
private void writefile(int zsize,int ysize,int xsize,String filename,int port) throws IOException{
InetAddress add = InetAddress.getByName(config.ipadd);
ServerSocket socket = new ServerSocket(port, 10, add);
Socket clientsocket;
clientsocket = socket.accept();
FileOutputStream fos = new FileOutputStream(filename);
DataInputStream in = new DataInputStream(new BufferedInputStream(clientsocket.getInputStream()));
int chunksize = 2*xsize*ysize;
byte[] frame = new byte[chunksize];
long t0 = System.currentTimeMillis();
for (int i=0;i<zsize;i++){
int pos = 0;
while (pos<chunksize-1){
int len = in.read(frame,pos,chunksize-pos);
pos+= len;
}
fos.write(frame);
}
fos.close();
long t1 = System.currentTimeMillis();
printlock.lock();
System.out.println((long)zsize*(long)xsize*(long)ysize*2d/(double)(t1-t0));
System.out.printf("Data transfer speed: %f MB/s\n", (long)zsize*(long)xsize*(long)ysize*2d/((double)(t1-t0)/1000d)/1024d/1024d);
printlock.unlock();
in.close();
socket.close();
clientsocket.close();
try{
ports.put(port);
}
catch (InterruptedException it){
it.printStackTrace();
}
return;
}
I have also tried to use the nio approach (following the example from https://pzemtsov.github.io/2015/01/19/on-the-benefits-of-stream-buffering-in-Java.html). However the performance is rather similar.
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class datagetter {
private static ByteBuffer buf;
private String hostname = null;
private int port = 0;
private int framesize = 2048*2048;
private int numframe = 500;
private static void ensure (int len, ByteChannel chan) throws IOException
{
if (buf.remaining () < len) {
buf.compact ();
buf.flip ();
do {
buf.position (buf.limit ());
buf.limit (buf.capacity ());
chan.read (buf);
buf.flip ();
} while (buf.remaining () < len && buf.limit()!=buf.capacity());
}
}
public datagetter(String hostname, int port,int framesize,int numframe){
this.hostname = hostname;
this.port = port;
this.framesize = framesize;
this.numframe = numframe;
}
public void receiveandwrite(String filename) throws IOException{
buf = ByteBuffer.allocateDirect(framesize);
FileOutputStream fos = new FileOutputStream(filename);
ServerSocketChannel chanserv = ServerSocketChannel.open();
chanserv.socket().bind(new InetSocketAddress(hostname,this.port));
SocketChannel chan = chanserv.accept();
buf.limit(0);
byte[] msg = new byte[framesize];
for (int i=0;i<numframe;i++){
ensure(framesize,chan);
buf.get(msg,0,framesize);
fos.write(msg);
}
chanserv.close();
fos.close();
}
}
I understand that there would be network protocol overhead when comparing iperf to real data transfer but I'm not sure why the throughput discrepancy is so large. Is this normal to expect such a big network speed difference?

Related

UDP Broadcasting Issue

I was trying a simple problem of sending some random numbers from server to client by UDP Broadcasting. As far as I know, if I broadcast to a specific ip address and port number, all the users who are connected to that channel will be able to listen. I have looked for sample codes in the internet and developed my code based on that. But whenever I try to run the codes, my server closes the socket before client can get anything.
The server code is:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.security.SecureRandom;
public class Server {
public static void main(String[] args) throws IOException {
DatagramPacket packet;
InetAddress address;
DatagramSocket socket;
System.out.println("Sending Numbers!");
socket = new DatagramSocket();
try {
int n = 10;
SecureRandom rand = new SecureRandom();
address = InetAddress.getByName("233.0.0.1");
for(int i = 0; i < n; i++)
{
int num = rand.nextInt(100);
byte[] tmp = Integer.toString(num).getBytes();
packet = new DatagramPacket (tmp, 0, address, 1502);
socket.send(packet);
System.out.println("Number has been sent!");
}
} catch (Exception e) {
System.out.println("Error: " + e);
} finally {
try {
socket.close();
} catch (Exception e) {
System.out.println("Error2: " + e);
}
}
}
}
The client code is:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;
public class Client {
public static void main(String[] args) throws IOException {
// Initialization
int n = 10;
// Create the socket
int port = 1502;
DatagramSocket socket;
DatagramPacket packet = null;
socket = new DatagramSocket(port);
for (int i = 0; i < n; i++)
{
socket.receive (packet);
byte[] numb = packet.getData();
int num = ByteBuffer.wrap(numb).getInt();
System.out.println(Integer.toString(num));
}
}
}
Then, I tried to compile each code using javac and java.
javac Server.java
java package_name.Server
I am running the Server first using the above method, then Client. I get NullPointerException for client. It would be really helpful if I understand what am I doing wrong here.
I am running them in command window. For server, I get this
Server
And for Client: Client
Edit: I was able to communicate between Server and Client. However, I just keep getting the first number only. Moreover, if I initialize Datagram for size >2, I get NumberFormatException. This is the improved code.
Server Code:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.security.SecureRandom;
public class Server {
public static void main(String[] args) throws IOException {
DatagramPacket packet;
InetAddress address;
DatagramSocket socket;
System.out.println("Sending Numbers!");
socket = new DatagramSocket();
try {
int n = 10;
SecureRandom rand = new SecureRandom();
address = InetAddress.getByName("127.0.0.1");
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintStream pout = new PrintStream( bout );
for(int i = 0; i < n; i++)
{
int num = rand.nextInt(100);
pout.print(num);
byte[] barray = bout.toByteArray();
packet = new DatagramPacket (barray, barray.length, address, 1502);
socket.send(packet);
System.out.println("Number has been sent!");
System.out.println(num);
}
} catch (Exception e) {
System.out.println("Error: " + e);
} finally {
try {
socket.close();
} catch (Exception e) {
System.out.println("Error2: " + e);
}
}
}
}
Client Code:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Client {
public static void main(String[] args) throws IOException {
// Initialization
int n = 10;
// Create the socket
int port = 1502;
DatagramSocket socket;
byte[] buf = new byte[2];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket = new DatagramSocket(port);
for (int i = 0; i < n; i++)
{
socket.receive (packet);
int num = Integer.parseInt(new String(packet.getData()));
System.out.println(num);
}
}
}
What can be the issue now?
Edit 2: Finally, I have made it work. Just put bout and pout inside the for loop and it should work!
you need to initialize your DatagramPacket in your client - it can not be null
int n = 10;
// Create the socket
int port = 1502;
DatagramSocket socket;
byte[] buf = new byte[1000];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket = new DatagramSocket(port);
for (int i = 0; i < n; i++)
{
socket.receive (packet);
byte[] numb = packet.getData();
int num = ByteBuffer.wrap(numb).getInt();
System.out.println(Integer.toString(num));
}
Also this code needs to be running before your Server

java: Transfer a file to the server and get the file from the server in upper case

i want to send a .txt file from the client to server and get it back in upper case.
But this code do nothing.can anyone tell what is wrong here..?
SERVER : getting file from client and sending it back in upper case to the client.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
public class Assignment4_Server {
public static void main(String[] args) throws IOException {
byte[] bytearray = new byte[4096];
try (ServerSocket ss = new ServerSocket(4444)) {
Socket s = ss.accept();
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
int count;
String data = null ;
while((count = is.read(bytearray))>0){
data = Arrays.toString(bytearray).toUpperCase();
byte[] bytearrayout = data.getBytes();
os.write(bytearrayout);
}
s.close();
}
}
}
CLIENT : sending text.txt file to the server and getting file back after converted in upper case.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Assignment4_client {
public static void main(String[] args) throws IOException {
File file = new File("test.txt");
byte[] bytearray = new byte[4096];
Socket sc = new Socket("localhost",4444);
//send file
int countS , countR;
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = sc.getOutputStream();
while((countS = bis.read(bytearray))>0){
os.write(bytearray);
}
//recieve file in uppercase from server
InputStream is = sc.getInputStream();
byte[] bytearray2 = new byte[4096];
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
while((countR = is.read(bytearray2))>0){
bos.write(bytearray2);
}
}
}
Here is a code that should help you. But before reading it you should be aware of what is happening:
Your client is not sending a 'stop reading' information to the server (read the client code below). That's why the server is stuck in the while loop when it is trying to read the data sent by the client. That is probably why you have tried to send the data back directly to the client. Shut down the socket output from the client side to respect the Socket contract and correctly free the socket (see TCP/IP).
The solution given doesn't take in account that the server should stay up after it has done its duty. Then, the server will not be able to serve more than one client at a time. This server is offering a one time service, which is pointless. To overcome this issue you should put everything in a while loop and bind every new server process into a new thread (I let you do that, its quite a joy).
The server doesn't take in account the whole size of the data an it could possibly run into an out of memory error if the data is too heavy. You should find a way to avoid this problem in a real implementation.
Both program should catch the exception and log it somewhere so you could be aware of any errors.
Writing a server is not so simple. You should normally write some kind of protocol with headers and other stuff like that. To avoid that, use objects like ObjectOutputStream and ObjectInputStream but it has some limitation like constraining your server in the Java world.
CLIENT
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.Socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
public class Client {
public void send(File file)
{
Socket sc = null;
try
{
byte[] bytearray = new byte[4096];
sc = new Socket("localhost", 4444);
// 1. Read the file, send its content, close it.
int count;
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = sc.getOutputStream();
while((count = bis.read(bytearray))>0)
{
os.write(bytearray);
}
fis.close();
sc.shutdownOutput();
// 2. Delete old file, receive data, write it to new File.
InputStream is = sc.getInputStream();
bytearray = new byte[4096];
// Eventually do what you want with the file: new one, append, etc.
file.delete();
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
count = 0;
while((count = is.read(bytearray)) > 0)
{
bos.write(bytearray, 0, count);
}
fos.close();
bos.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (sc != null)
{
try
{
sc.close();
} catch (IOException e) {}
}
}
}
}
SERVER
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server
{
Server()
{
Socket s = null;
byte[] bytearray = new byte[4096];
try (ServerSocket ss = new ServerSocket(4444))
{
s = ss.accept();
InputStream is = s.getInputStream();
// 1. Recieve data and put it to UpperCase.
String data = "";
int count;
while((count = is.read(bytearray)) > 0)
{
data += new String(bytearray, 0, count);
}
data = data.toUpperCase();
System.out.println(data);
// 2. Send back data.
OutputStream os = s.getOutputStream();
os.write(data.getBytes());
os.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
TEST PROGRAM
This one should help you to test your both programs in the same project in an IDE.
import java.io.File;
public class Test
{
public static void main(String[] args)
{
Client c = new Client();
(new Thread()
{
public void run()
{
Server s = new Server();
}
}).start();
c.send(new File("test.txt"));
}
}
What is wrong here is two simple things.
The server is reading until end of stream, on a socket that must be used for the reply. The client therefore cannot close it after sending the request to provide the EOS, so it must shutdown the socket for output after sending the request.
Your copy loops are wrong. The general form is:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
You are ignoring the read count when writing, so you will write junk at end of stream, or any other time that read() doesn't fill buffer, which can be any time at all.

Eliminate Half Strings when receiving from Server socket Buffer in JAVA

I have written a simple NIO Server and Inner-Client (Inside the same program)in a single program such that Server receives data from outside and the Inner-Client sends the data received by the server to out side Server. I am running both the processes continuously in two parallel threads using While() loops. Now the problem is, I will be receiving data at a very high speed to the Inside server and everything I receive, I will send them to the outer server using the Inside client. Some times, the retrieval of the data from the Buffer resulting in half the size of the total string. That means I am receiving "HELLO", but the total string is "HELLO SERVER". This is just an example. I will receive very long strings. Similarly, after sending the data to Outer-server through Inner client I will be listening for data and I am receiving the same half-strings.Is there any way I can eliminate these Half-strings and get the full-length string. I have to get the full string without any fail.
I am using while loops for the process. This is making the CPU utilization go high like 50%. Is there any way I can reduce the CPU utilization without using Thread.sleep method? Because I need to continuously listen to data from the Outer parties. They may send 2-4 strings for one single request. I tried using Executor service thread for running the processes continuously but it requires some sleep to be included. If I include some sleep I am not able to get the String and if I don't include the sleep my CPU-Utilization is going very high (50-60%). Can anyone help me with these two issues?
Here is my code:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
static SocketChannel channel;
public static void main(String[] args) throws IOException {
System.out.println("Listening for connections on : 8888"); //8888
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
channel = serverChannel.accept();
System.out.println("Connected...");
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
channel.configureBlocking(false);
ReceiveFromOMS receivefromOMS;
SendToExchange sendExchange;
receivefromOMS = new ReceiveFromOMS();
sendExchange = new SendToExchange();
Thread t1 = new Thread(receivefromOMS);
Thread t2 = new Thread(sendExchange);
t1.start();
t2.start();
}
}
class ReceiveFromOMS extends Thread{
public static SocketChannel channel;
static ByteBuffer buffer = ByteBuffer.allocate(1024);
static ServerSocketChannel serverChannel ;
public static int ReceiveFromOMSPort;
BlockingQueue<String> fromOMSqueue = new LinkedBlockingQueue<>(30);
#Override
public void run(){
while(true){
try {
receiveFromOMS();
} catch (InterruptedException ex) {
System.err.println(ex.getMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex1) { }
}
}
}
public void receiveFromOMS() throws InterruptedException{
try {
int numRead = -1;
numRead = channel.read(buffer);
while(numRead==0){
numRead = channel.read(buffer);
}
if (numRead == -1) {
Socket socket = channel.socket();
SocketAddress remoteAddr = socket.getRemoteSocketAddress();
System.out.println("Connection closed by client: " + remoteAddr);
channel.close();
return;
}
byte[] data = new byte[numRead];
System.arraycopy(buffer.array(), 0, data, 0, numRead);
fromOMSqueue.add(new String(data));
String msg = fromOMSqueue.poll();
System.out.println("OutGoing To Exchange>> " + msg);
SendToExchange.sendToEchange(msg);
buffer.flip();
buffer.clear();
} catch (IOException ex) {
System.err.println(ex.getMessage());
Thread.sleep(5000);
}
}
}
class SendToExchange extends Thread{
static SocketChannel channel;
static ByteBuffer bb = ByteBuffer.allocateDirect(1024);
static Charset charset = Charset.forName("UTF-8");
public byte[] data;
public static String message;
#Override
public void run(){
try {
while(true){
receive();
Thread.sleep(100);
}
} catch (IOException | InterruptedException ex) {
System.err.println(ex.getMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex1) {}
}
}
public static void sendToEchange(String msg){
try {
bb = stringToByteBuffer(msg, charset);
channel.write(bb);
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
public void receive() throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
int numRead = -1;
numRead = channel.read(buffer);
while (numRead == 0) {
numRead = channel.read(buffer);
}
if (numRead == -1) {
Socket socket = channel.socket();
SocketAddress remoteAddr = socket.getRemoteSocketAddress();
System.out.println("Connection closed by Exchange: " + remoteAddr);
channel.close();
return;
}
buffer.flip();
data = new byte[numRead];
buffer.get(data);
message = new String(data);
System.out.println("Incoming from Exchange>> " + message);
buffer.clear();
}
public static ByteBuffer stringToByteBuffer(String msg, Charset charset){
return ByteBuffer.wrap(msg.getBytes(charset));
}
}
Lets assume that your server is appending to each string an End of message marker string, e.g. "<EOM>", then the following modification of your code (treat it as a sketch since I did not verified it completely) can be used to wait for the full string:
String end = "<EOM>";
StringBuilder curStr = new StringBuilder();
int numRead = 0;
while(-1 != (numRead = channel.read(buffer))){
curStr.append(new String(buffer.array(), 0, numRead, Charset.forName("UTF-8")));
int endIdx = curStr.indexOf(end);
if (endIdx != -1) {
fromOMSqueue.add(curStr.substring(0, endIdx + end.length()));
break;
}
}
if (numRead == -1) {
Socket socket = channel.socket();
SocketAddress remoteAddr = socket.getRemoteSocketAddress();
System.out.println("Connection closed by client: " + remoteAddr);
channel.close();
return;
}
String msg = fromOMSqueue.poll();

Client-Server Based Audio Live Streaming in java using Socket

Given code is intended to do live audio streaming between client and server using java socket, but problem is that when I run this project, the client starts recording the sound and send it to receiver(server) side. Then Server buffers the received the sound but does not play it simultaneously.But when the client is closed, the server starts playing the sound.Please help me. I need that server must play received sound simultaneously.
\client
import java.io.*;
import java.net.*;
import java.sound.sampled.*;
import org.apache.commons.io.IOUtils;
public class ClientStream{
public ClientStream() throws IOException{
isl.runListener();
}
private IncomingSoundListener isl = new IncomingSoundListener();
AudioFormat format = getAudioFormat();
InputStream is;
Socket client;
String serverName = "192.168.2.8";
int port=3000;
boolean inVoice = true;
private AudioFormat getAudioFormat(){
float sampleRate = 16000.0F;
int sampleSizeBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = false;
return new AudioFormat(sampleRate, sampleSizeBits, channels, signed, bigEndian);
}
class IncomingSoundListener {
public void runListener(){
try{
System.out.println("Connecting to server:"+serverName+" Port:"+port);
client = new Socket(serverName,port);
System.out.println("Connected to: "+client.getRemoteSocketAddress());
System.out.println("Listening for incoming audio.");
DataLine.Info speakerInfo = new DataLine.Info(SourceDataLine.class,format);
SourceDataLine speaker = (SourceDataLine) AudioSystem.getLine(speakerInfo);
speaker.open(format);
speaker.start();
while(inVoice){
is = client.getInputStream();
byte[] data = IOUtils.toByteArray(is);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
AudioInputStream ais = new AudioInputStream(bais,format,data.length);
int bytesRead = 0;
if((bytesRead = ais.read(data)) != -1){
System.out.println("Writing to audio output.");
speaker.write(data,0,bytesRead);
// bais.reset();
}
ais.close();
bais.close();
}
speaker.drain();
speaker.close();
System.out.println("Stopped listening to incoming audio.");
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void main(String [] args) throws IOException{
new ClientStream();
}
}
\server
import java.io.*;
import java.net.*;
import java.sound.sampled.*;
public class ServerStream {
private OutgoingSoudnListener osl = new OutgoingSoudnListener();
boolean outVoice = true;
AudioFormat format = getAudioFormat();
private ServerSocket serverSocket;
Socket server;
private AudioFormat getAudioFormat() {
float sampleRate = 16000.0F;
int sampleSizeBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = false;
return new AudioFormat(sampleRate, sampleSizeBits, channels, signed, bigEndian);
}
public ServerStream() throws IOException{
try{
System.out.println("Creating Socket...");
serverSocket = new ServerSocket(3000);
osl.runSender();
}catch(Exception e){
e.printStackTrace();
}
}
class OutgoingSoudnListener{
public void runSender(){
try{
server = serverSocket.accept();
System.out.println("Listening from mic.");
DataOutputStream out = new DataOutputStream(server.getOutputStream());
DataLine.Info micInfo = new DataLine.Info(TargetDataLine.class,format);
TargetDataLine mic = (TargetDataLine) AudioSystem.getLine(micInfo);
mic.open(format);
System.out.println("Mic open.");
byte tmpBuff[] = new byte[mic.getBufferSize()/5];
mic.start();
while(outVoice) {
System.out.println("Reading from mic.");
int count = mic.read(tmpBuff,0,tmpBuff.length);
if (count > 0){
System.out.println("Writing buffer to server.");
out.write(tmpBuff, 0, count);
}
}
mic.drain();
mic.close();
System.out.println("Stopped listening from mic.");
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void main (String args[]) throws IOException{
new ServerStream();
}
}
Client-server connection and subsequently Socket is based on the TCP protocol model.
As you can confirm in their docs.
What you seek is DatagramSocket based on UDP, you might suffer the loss of packages but that's the way things work. That's how streaming video works, you get some, you lose some.
Now, you question per se, one of the problems you have while implementing with a TCP protocol is that TCP is based on acknowledgements in order to keep the communications synchronized, if either your server or client fails to acknowledge then you might experience the stream to get stuck, because of that.

Wrong file transfer over java Socket

this afternoon I wrote this class whose aim is give a easy way to exchange send a file over TCP Socket.
The problem it that, despite the final file size is correct, the content in wrong: precisely the destination file is made of various copies of the first buffer sent over Socket.
My class is simple: it calculates Q and R based on buffer size and sends this number together original filename to the client. I used a byte array to send data over Socket.
package it.s4sytems.java;
import java.io.*;
import java.net.*;
public class FileOverObjectStream
{
private File file;
private int bufferSize = 4*1024*1024; //4MB default, comunque รจ stabilito dal sender
private static class Info implements Serializable
{
public String fileName;
public long q;
public int r;
public int bufferSize;
}
public FileOverObjectStream(File file)
{
this.file = file;
}
public FileOverObjectStream(File file, int bufferSize)
{
this(file);
this.bufferSize = bufferSize;
}
public void sendFile(Socket socket) throws IOException
{
socket.getInputStream();
sendFile( socket.getOutputStream() );
}
public void sendFile(OutputStream outStream)throws IOException
{
sendFile( new ObjectOutputStream(outStream) );
}
public void sendFile(ObjectOutputStream objOutStream) throws IOException
{
BufferedInputStream in = new BufferedInputStream( new FileInputStream(file) );
byte[] buffer = new byte[bufferSize];
Info info = new Info();
info.fileName = file.getName();
info.bufferSize = bufferSize;
info.q = file.length() / bufferSize;
info.r = (int) file.length() % bufferSize;
objOutStream.writeObject(info);
for(long i=0; i<info.q; i++)
{
in.read(buffer);
objOutStream.writeObject(buffer);
objOutStream.flush();
}
in.read( buffer = new byte[info.r]);
objOutStream.writeObject(buffer);
objOutStream.flush();
in.close();
}
public String receiveFile(Socket socket) throws IOException, ClassNotFoundException
{
socket.getOutputStream();
return receiveFile( socket.getInputStream() );
}
public String receiveFile(InputStream inStream) throws IOException, ClassNotFoundException
{
return receiveFile( new ObjectInputStream(inStream) );
}
public String receiveFile(ObjectInputStream objInStream) throws IOException, ClassNotFoundException
{
BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(file) );
Info info = (Info) objInStream.readObject();
for(long i=0; i<info.q+1; i++)
{
byte[] buffer = (byte[]) objInStream.readObject();
out.write( buffer );
}
out.close();
return info.fileName;
}
}
I created two classes to make some try...
import it.s4sytems.java.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server
{
public static void main(String arg[]) throws IOException
{
ServerSocket ss = new ServerSocket(18000);
while(true)
{
Socket s = ss.accept();
File file = new File("G:\\HCHCK_72_5.38.part04.rar");
FileOverObjectStream sender = new FileOverObjectStream(file);
sender.sendFile(s);
s.close();
}
}
}
and client...
import it.s4sytems.java.*;
import java.io.*;
import java.net.*;
public class Client
{
public static void main(String arg[]) throws IOException, ClassNotFoundException
{
Socket s = new Socket("localhost", 18000);
String matricola = "616002424";
File directory = new File(System.getProperty("user.dir") + "\\" + matricola);
directory.mkdir();
File file = File.createTempFile("7897_", null, directory);
String originalName = new FileOverObjectStream(file).receiveFile(s);
System.out.println(originalName);
s.close();
File file2 = new File(directory, originalName);
System.out.println( file.renameTo( file2 ) );
System.out.println( file.getAbsoluteFile());
System.out.println( file2.getAbsoluteFile());
}
}
Probably it's a stupid thing, but I can't see it, so I need your help, please.
Thank you
I don't think ObjectOutputStream is suitable in your use case. Unless I missed something. In general, try to use some good library for IO such as Apache Commons IO. It has methods that would always do the right thing. Look at IOUtils for example.
Some errors to highlight (they would not happen with good library)
in.read(buffer) is not guaranteed to read exact number of bytes. You must check its result and only write correct number.
You write buffer object to ObjectOutputStream with writeObject. That writes serialized byte buffer not raw sequence of bytes.
Your ObjectInput/OutputStream code is flawed in all the ways Alex noted. I wouldn't use it at all, I would just use raw I/O. The canonical way to copy a stream in Java is as follows:
int count;
byte[] buffer = new byte[8192]; // or more, but megabytes is pointless as the network will packetize anyway
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use that same code when both sending and receiving the file. If you want to send > 1 file per connection, you need to prefix all that by sending the file name and length, which you can do with DataOutputStream.writeUTF()/writeLong(), and DataInputStream.readUTF()/readLong() at the receiver, and modify the loop control to read exactly that many bytes:
long remaining = size; // the file size read from the network
while ((count = in.read(buffer, 0, remaining > buffer.length ? buffer.length : (int)remaining)) > 0)
{
out.write(buffer, 0, count);
remaining -= count;
}

Categories

Resources