I use ServerSocket to get data from client in a while loop, it works at the first run, but fails after second round.
I did some search but still can't figure out what happened.
Server side code
package com.gorilla.main;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server2 {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(44444);
while(true){
System.out.println("another round");
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
System.out.println("available: "+ inputStream.available());
byte[] b = new byte[inputStream.available()];
inputStream.read(b);
System.out.println(new String(b));
System.out.println("=======================");
socket.close();
}
}
}
Clent side code
package com.gorilla.main;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client2 {
public static void main(String [] args) throws Exception{
Socket socket = new Socket("127.0.0.1", 44444);
String s = "Hello World";
byte [] b = s.getBytes();
socket.getOutputStream().write(b);;
socket.close();
}
}
and the output at Server side console after I ran client 3 times.
another round
available: 11
Hello World
=======================
another round
available: 0
=======================
another round
available: 0
=======================
another round
Any suggestion would be appreciated. Thanks.
You use InputStream.available() to size your buffer and that's not how one reads from a socket. You should allocate a buffer (usually sized statically, or maybe configurable) and read in a loop
// server code
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) > -1) {
// do something
}
The Javadoc of InputStream.available():
Returns an estimate of the number of bytes that can be read (or
skipped over) from this input stream without blocking by the next
invocation of a method for this input stream. The next invocation
might be the same thread or another thread. A single read or skip of
this many bytes will not block, but may read or skip fewer bytes.
If your protocol is text-based, you can wrap the socket's input stream inside a Scanner and thus the loop becomes
while (scanner.hasNextLine()) {
String line = scanner.next();
}
Related
I have written a program to transfer a file from client side to server side. The program runs without any errors. Also the file is created on the destination path. But when i try to open the file the gedit crashes. The program should transfer audio,video,text file.I know UDP should not be used to transfer file as it may be corrupted but i have to do it as assignment. Following code is for text file transfer.
Server.java
import java.net.*;
import java.io.*;
public class server
{
public static void main(String args[])throws IOException
{
DatagramSocket dsoc=new DatagramSocket(8008);
byte b[]=new byte[787734];
byte c[];
String pac ;
File file = new File("/home/san_16398/ip2.java");
FileOutputStream f = new FileOutputStream(file);
while(true)
{
DatagramPacket dp=new DatagramPacket(b,b.length);
dsoc.receive(dp);
pac =new String(dp.getData(),0,dp.getLength());
System.out.println(pac);
}
pac.getBytes();
f.write(b);
f.flush();
f.close();
}
}
Client.java
import java.net.*;
import java.io.*;
public class client
{
private static final int BUFFER_SIZE = 4096;
public static void main(String args[])throws Exception
{
byte b[]=new byte[787734];
FileInputStream f=new FileInputStream("/home/san_16398/ip.java");
DatagramSocket dsoc=new DatagramSocket(2000);
int i=0;
byte[] buffer = new byte[BUFFER_SIZE];
while(f.read(buffer) != -1)
{
b[i]=(byte)f.read();
i++;
}
f.close();
dsoc.send(new DatagramPacket(b,i,InetAddress.getLocalHost(),8008));
}
}
byte b[]=new byte[787734];
// ...
while(f.read(buffer) != -1){
b[i]=(byte)f.read();
i++;
}
dsoc.send(new DatagramPacket(b,i,InetAddress.getLocalHost(),8008));
This is complete and utter nonsense. You're reading up to 787734 bytes and throwing them away, and then reading one byte, if there is one, and then apparently attempting to send a datagram of size up to 787734, which is impossible. It should be:
byte b[]=new byte[534];
// ...
int count;
while((count = f.read(b)) != -1){
dsoc.send(new DatagramPacket(b,count,InetAddress.getLocalHost(),8008));
}
and then you have to take care of duplicate datagrams, datagrams not received, datagrams received out of order, ...
And calling File.exists() and File.createNewFile() when you're using a FileOutputStream is a complete waste of time at best, but when you call them after creating the FileOutputStream you are liable to clobber the file that is being written to, depending on the platform. Remove.
Here:
while(f.read(buffer) != -1){
b[i]=(byte)f.read();
first you are reading into your buffer object - to then never make use of the buffer array
and then you read a single byte again
to then read into the buffer again
Long story short: either use the read(buffer) or use the single byte read() consistently.
And beyond that: you also forgot to check that the file you intend to read fits into the buffer that you want to transmit to the server!
Finally: you are also trying to do *too many** things at once. Instead: focus on the different parts of this work, like:
first write code that reads a file
then enhance that to create a local copy of that file
and then, when that works, instead of creating a local copy, send to a remote server.
I try to make a little Server-Client connection.
They both have a Scanner and a PrintWriter, and they are writing to each other using a Socket's input and output stream.
Client.java:
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
static ServerSocket serverSocket;
static Socket socket;
static PrintWriter printWriter;
static Scanner scanner;
public static void main(String[] args) throws UnknownHostException, IOException {
socket = new Socket("localhost", 13344);
scanner = new Scanner(socket.getInputStream());
printWriter = new PrintWriter(socket.getOutputStream());
printWriter.println("dataline 1");
printWriter.println("dataline 2");
printWriter.println("dataline 3");
printWriter.flush();
//Error!? => I never got the echo from server in output
while (scanner.hasNextLine()) {
String lineRead = scanner.nextLine();
System.out.println("From server" + lineRead);
}
socket.close();
scanner.close();
printWriter.close();
System.out.println("Client has quit.");
}
}
Server.java
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Server {
static ServerSocket serverSocket;
static Socket socket;
static PrintWriter printWriter;
static Scanner scanner;
public static void main(String[] args) throws IOException {
serverSocket = new ServerSocket(13344);
System.out.println("Waiting for Client to connect");
socket = serverSocket.accept();
scanner = new Scanner(socket.getInputStream());
printWriter = new PrintWriter(socket.getOutputStream());
System.out.println("Client has connected!!");
while (scanner.hasNextLine()) {
String lineRead = scanner.nextLine();
System.out.println("From Client: " + lineRead);
}
//Error!? => This line never runs
System.out.println("Now sending echo to Client");
printWriter.println("Echo from server1");
printWriter.println("Echo from server2");
printWriter.flush();
socket.close();
printWriter.close();
scanner.close();
System.out.println("Server has quit.");
}
}
I start the server: java Server.java
I start the client: java Client.java
Server's output:
Waiting for client to connect
Client has connected!!
From Client: dataline 1
From Client: dataline 3
From Client: dataline 3
Client's output is empty, not a word on it.
As you can see Server's code termination stops AFTER it is read from Client's output stream, and Client's code termination stops BEFORE it could read from Server's output stream.
My question is:
How this Scanner-PrintWrier communication works, how do i know if a printWriter printed BEFORE a scanner could read in a server-client connection like this? What i did wrong and why? How to use properly a scanner?
E D I T:
#T.C Do you mean like this? Now i got full output, both Server and Client are quit after they are sent and received data.
I modified like this:
String line = "";
while (!line.equals("#")) {
line = scanner.nextLine();
if (!line.equals("#")) {
System.out.println("From server" + line);
}
}
The Scanner.hasNext*() methods will block to wait for input to scan, so you can't use it to detect when the client has finished sending.
Simplest way to solve this problem would be to have the client send a special string telling the server it's done sending.
I have already posted some samples on client-server communication with detailed description.
Please have a look at below post that might help you to understand it better.
Multiple clients access the server concurrently
Java Server with Multiclient communication.
Try with BufferedReader that contains ready() that tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready.
You can try with InputStream#available() but it doesn't have read line method.
Go with the solution suggested by #T.C. but he is not provided any sample code on it. You can find in it my post.
Had almost the exact same problem, after banging my head in the keyboard for a couple of hours, this is what saved me:
printWriter = new PrintWriter(socket.getOutputStream(), true);
The second parameter sets auto-flushing to true.
I am trying to send file from one client 1 to another Client 2 using an intermediate server. Both Client 1 and Client 2 are connected to server through network.For this, I have given IP-address of server to both clients.
But I am unable to transfer the file properly due to some mistake in my code. I am using the following code and its not working and at the Client 2 (receiver's) end, the file which is created is empty.
Kindly find the possible error in my code.
Server code
`
import java.net.*;
import java.io.*;
public class S1 {
public static void main(String[] args) {
try{
ServerSocket sc1=new ServerSocket(6988);
Socket c1=sc1.accept();
Socket c2=sc1.accept();
DataInputStream dis=new DataInputStream(c1.getInputStream());
int m=c1.getInputStream().available();
byte b2[]=new byte[m];
dis.read(b2);
DataOutputStream dos=new DataOutputStream(c2.getOutputStream());
dos.write(b2);
dos.flush();
dos.close();
}
catch(Exception e){}
}
}
Client 1 (Sender)
import java.io.*;
import java.net.*;
public class C11 {
public static void main(String[] args) {
try{
Socket c2=new Socket("127.0.0.1",6988);
FileInputStream fis=new FileInputStream("f:/abc.jpg");
File f1=new File("f:/abc.jpg");
long l1=f1.length();
int a=(int)l1;
byte b1[]=new byte[a];
DataInputStream dis=new DataInputStream(fis);
dis.read(b1);
DataOutputStream dout=new DataOutputStream(c2.getOutputStream());
dout.write(b1);
}
catch(Exception e){}
}
}
Client 2 (Receiver)
import java.io.*;
import java.net.*;
public class C22 {
public static void main(String[] args) {
try{
Socket c2=new Socket("127.0.0.1",6988);
DataInputStream dis=new DataInputStream(c2.getInputStream());
int m=c2.getInputStream().available();
byte b2[]=new byte[m];
dis.read(b2);
FileOutputStream fout=new FileOutputStream("E:\\PRACTICE\\xyz.txt");
DataOutputStream dos=new DataOutputStream(fout);
dos.write(b2);
dos.close();
}
catch(Exception e){}
}
}
Usual problems.
nt m=c1.getInputStream().available();
byte b2[]=new byte[m];
From the Javadoc: "It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream."
dis.read(b2);
The read() method returns a value. You are ignoring it. The value can be -1, or a postive number between 1 and the buffer size. You're assuming the read filled the buffer. It isn't obliged to do that.
dout.write(b1);
That should be
dout.write(b1, 0, count);
where count was the length returned by read(), and it should be in a loop:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use this at both ends, with any buffer size greater than zero. I usually use 8192.
The most obvious mistake is here:
int m=c2.getInputStream().available();
The available method only tells you how much data can be read without blocking, not how much data could potentially be read from the socket. To read all of the data that was sent you need to write a loop that reads from the socket until read returns -1.
I'm trying to write an upload system for a fairly complex java server. I have reproduced the error in the two small programs listed below. Basically, I am using an ObjectOutputStream/ObjectInputStream to communicate via the client/server. This is a requirement; I have thousands of lines of code working perfectly fine around this ObjectOutputStream/ObjectInputStream setup, so I must be able to still use these streams after an upload is complete.
To access the files(the one being read on the client and the one being written on the server), FileInputStream and FileOutputStream is used. My client appears to be functioning perfectly; it reads in the file and sends a different byte array each iteration(it reads in 1MB at a time, so large files can be handled without overflowing the heap). However, on the server it appears as though the byte array is ALWAYS just the first array sent(the first 1MB of the file). This does not conform to my understanding of ObjectInputStream/ObjectOutputStream. I am seeking either a working solution to this issue or enough education on the matter to form my own solution.
Below is the client code:
import java.net.*;
import java.io.*;
public class stupidClient
{
public static void main(String[] args)
{
new stupidClient();
}
public stupidClient()
{
try
{
Socket s = new Socket("127.0.0.1",2013);//connect
ObjectOutputStream output = new ObjectOutputStream(s.getOutputStream());//init stream
//file to be uploaded
File file = new File("C:\\Work\\radio\\upload\\(Op. 9) Nocturne No. 1 in Bb Minor.mp3");
long fileSize = file.length();
output.writeObject(file.getName() + "|" + fileSize);//send name and size to server
FileInputStream fis = new FileInputStream(file);//open file
byte[] buffer = new byte[1024*1024];//prepare 1MB buffer
int retVal = fis.read(buffer);//grab first MB of file
int counter = 0;//used to track progress through upload
while (retVal!=-1)//until EOF is reached
{
System.out.println(Math.round(100*counter/fileSize)+"%");//show current progress to system.out
counter += retVal;//track progress
output.writeObject("UPACK "+retVal);//alert server upload packet is incoming, with size of packet read
System.out.println(""+buffer[0]+" "+buffer[1]+" "+buffer[2]);//preview first 3 bytes being sent
output.writeObject(buffer);//send bytes
output.flush();//make sure all bytes read are gone
retVal = fis.read(buffer);//get next MB of file
}
System.out.println(Math.round(100*counter/fileSize)+"%");//show progress at end of file
output.writeObject("UPLOAD_COMPLETE");//let server know protocol is finished
output.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
The following is my server code:
import java.net.*;
import java.io.*;
public class stupidServer
{
Socket s;
ServerSocket server;
public static void main(String[] args)
{
new stupidServer();
}
public stupidServer()
{
try
{
//establish connection and stream
server = new ServerSocket(2013);
s = server.accept();
ObjectInputStream input = new ObjectInputStream(s.getInputStream());
String[] args = ((String)input.readObject()).split("\\|");//args[0] will be file name, args[1] will be file size
String fileName = args[0];
long filesize = Long.parseLong(args[1]);
String upack = (String)input.readObject();//get upload packet(string reading UPACK [bytes read])
FileOutputStream outStream = new FileOutputStream("C:\\"+fileName.trim());
while (!upack.equalsIgnoreCase("UPLOAD_COMPLETE"))//until protocol is complete
{
int bytes = Integer.parseInt(upack.split(" ")[1]);//get number of bytes being written
byte[] buffer = new byte[bytes];
buffer = (byte[])input.readObject();//get bytes sent from client
outStream.write(buffer,0,bytes);//go ahead and write them bad boys to file
System.out.println(buffer[0]+" "+buffer[1]+" "+buffer[2]);//peek at first 3 bytes received
upack = (String)input.readObject();//get next 'packet' - either another UPACK or a UPLOAD_COMPLETE
}
outStream.flush();
outStream.close();//make sure all bytes are in file
input.close();//sign off
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
As always, many thanks for your time!
Your immediate problem is that ObjectOutputStream uses an ID mechanism to avoid sending the same object over the stream multiple times. The client will send this ID for the second and subsequent writes of buffer, and the server will use its cached value.
The solution to this immediate problem is to add a call to reset():
output.writeObject(buffer);//send bytes
output.reset(); // force buffer to be fully written on next pass through loop
That aside, you're misusing object streams by layering your own protocol on top of them. For example, writing the filename and filesize as a single string delimited by "|"; just write them as two separate values. Ditto for the number of bytes on each write.
I am trying to open a socket and listen. Clients written in PHP will then send XML requests. At the moment I am just send the string "test" to it and I am getting a Memory Heap Error.
Here is my java code for the server:
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class main {
/**
* #param args
*/
public static void main(String[] args) {
server();
}
public static void server() {
ServerSocket MyService = null;
try {
MyService = new ServerSocket(3030);
}
catch (IOException e) {
System.out.println(e);
}
Socket serviceSocket = null;
try {
serviceSocket = MyService.accept();
}
catch (IOException e) {
System.out.println(e);
}
DataInputStream in;
try {
in = new DataInputStream(serviceSocket.getInputStream());
System.out.println("DEV STEP 1");
int len = in.readInt();
System.out.println(len);
byte[] xml = new byte[len];
in.read(xml, 0, len);
//System.out.print(xml.toString());
//Document doc = builder.parse(new ByteArrayInputStream(xml));
}
catch (IOException e) {
System.out.println(e);
}
}
}
The error I am getting is:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at main.server(main.java:39)
at main.main(main.java:12)
I have done a search and there are plenty of explanations of this error on here, however I can not work out why when I am sending a 4 letter String len is 1952805748.
Well you are getting the out of memory error because the len is so huge. If you are sending the data as characters and then doing a readInt() on it, then that's what's causing your problem. You need to read the data as characters.
Your numeric valid is probably the binary for the string "test". You should just read a string from the InputStream, not sure why you need a DataInputStream as that's something that supports reading binary, etc, which is not what you are doing. Just use a BufferedInputStream and then do a normal read on it.
To expand on Francis Upton's answer, you are getting a heap exception because you are trying to read n bytes from the incoming socket stream, where n represents the totally arbitrary integer you read at the beginning of your processing loop. And the reason I call it totally arbitrary is because you never actually sent a separate int in your client code. So your code is simply reading an int from whatever is in the first 4 bytes of the input stream, which could be anything at all.
Take a look at IOUtils in Apache Commons IO, it contains nice methods for reading an entire data stream in one shot (toByteArray, toString, etc).