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).
Related
I am learning about sockets in java, but when I was running a program that sends messages from the client side to server side it doesn't show a message. If I enter some text on the client side it doesn't show up on the server side, but if I type endProcess it stops running. Which means that the message is going through it's just not showing up.
My Client.java code is here:
import java.net.*;
import java.io.*;
public class Client{
Socket soc;
DataInputStream dis;
DataOutputStream dos;
public Client(){
try{
soc = new Socket("(Address)",5000);
System.out.println("Connection Established");
dis = new DataInputStream(System.in);
dos = new DataOutputStream(soc.getOutputStream());
System.out.println("Streams connected");
}catch(UnknownHostException u){
System.out.println(u);
}catch(IOException i){
System.out.println(i);
}
String line = "";
while(!line.equals("endConnection")){
try{
line = dis.readUTF();
dos.writeUTF(line);
}catch(IOException i){
System.out.println(i);
}
}
try {
soc.close();
dis.close();
dos.close();
} catch (Exception e) {
System.out.println(e)
}
}
public static void main(String[] args) {
new Client();
}
}
Here is my Server.java code:
import java.net.*;
import java.io.*;
public class Server {
ServerSocket serSoc;
Socket soc;
DataInputStream dis;
public Server(){
try {
serSoc = new ServerSocket(5000);
System.out.println("Server Online");
soc = serSoc.accept();
System.out.println("Client Connected");
dis = new DataInputStream(new BufferedInputStream(soc.getInputStream()));
String line = "";
System.out.println("Waiting for input...");
while(!line.equals("endConnection")){
line = dis.readUTF();
System.out.println(line);
}
System.out.println("Client disconnected");
soc.close();
dis.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new Server();
}
}
There are many problems here.
Duplex protocol issues
line = dis.readUTF();
dos.writeUTF(line);
This isn't going to work; The dis.readUTF() line is going to block (freeze) until a line is read. The problem is, sometimes you have nothing to send in which case you want to read, and something you have nothing to read in which case you want to send. In practice you need to redesign this entirely; you need 2 threads. At which point you get into the issues of multicore, needing synchronization primitives and/or java.util.concurrent classes for all data that is shared between the 2 threads.
Alternatively, adopt a model that is strictly push or pull (where at any given time both parties already know who can send, and if the other party wants to send they simply cannot. For example, every party sends a simply 'NOTHING TO DO' message every second, trading places every time. This is quite an inefficient algorithm, of course. But could be written without involving multiple threads.
Flush and close issues
dos.writeUTF(line);
This doesn't actually send anything, or at least, isn't guaranteed to. To send any data on the internet, it gets wrapped in a packet which has lots of overhead. So, things are buffered until there's a full packet to send. Which means that line doesn't do anything. It just fills a buffer, no packets go out. You first need to close or flush. dos.flush() would help maybe. This is a big problem, because later you do:
soc.close();
dis.close();
dos.close();
You first close the socket, which, well, closes the socket. You then close the streams, which will also send anything that's still stuck in a buffer, except, that will fail, because the socket is already closed. In other words, the line you .writeUTF()-ed? It never gets there. You first shove it in a buffer, then you close the socket, then you send the buffer which won't work as the socket is already closed.
Broken error handling
} catch (Exception e) {
System.out.println(e);
}
Horrible. Don't do this. Your code reacts to any problem by printing something and just keeping right on going. That means if anything goes wrong, the client will start spamming an endless cavalcade of exception traces and locking up the system with any luck. You want the code to stop running when problems occur. Easiest way, by far, is to just stick throws IOException on your constructor and main method, which is allowed. Distant second best option is to configure your 'eh whatever' catch blocks as throw new RuntimeException("unhandled", e); instead of e.printStackTrace().
What you do (System.out.println(e);) is even worse - you are tossing away extremely useful information such as the stack trace and causal chain.
package base;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPConnectionClosedException;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import com.ibm.jzos.ZFile;
public class FTPSVB {
public static void main(String[] args) {
BufferedInputStream binp=null;
BufferedOutputStream bout=null;
String server, username, password, fileTgt, fileSrc;
String protocol = "TLS"; // SSL/TLS
FTPSClient ftps = new FTPSClient(protocol);
FTPSClient ftps2 = new FTPSClient(protocol);
server="***";
username="***";
password="***";
fileSrc="ABC00T.SMP.SAVE.ULRL";
fileTgt="ABC00T.SMP.SAVE.OUT.ULRL";
try
{
int reply;
ftps.connect(server);
ftps2.connect(server);
reply = ftps.getReplyCode();
reply = ftps2.getReplyCode();
}
try
{
ftps.setBufferSize(200);
ftps.setFileType(FTP.BINARY_FILE_TYPE);
if (!ftps.login(username, password))
{
ftps.logout();
System.out.println("ERROR..");
System.exit(-1);
}
ftps.execPBSZ(0);
ftps.execPROT("P");
ftps.enterLocalPassiveMode();
ftps.setAutodetectUTF8(true);
ftps.site("QUOTE RDW");
ftps2.setBufferSize(200);
ftps2.setFileType(FTP.BINARY_FILE_TYPE);
ftps2.site("QUOTE RDW");
ftps2.site("QUOTE recfm=VB lrecl=106 blksize=27998");
if (!ftps2.login(username, password))
{
ftps2.logout();
System.out.println("ERROR..");
System.exit(-1);
}
ftps2.execPBSZ(0);
ftps2.execPROT("P");
ftps2.enterLocalPassiveMode();
ftps2.setAutodetectUTF8(true);
binp=new BufferedInputStream(ftps.retrieveFileStream(fileSrc));
bout=new BufferedOutputStream(ftps2.storeFileStream(fileTgt));
final byte []bufLen= new byte[4];
int readLen=binp.read(bufLen, 0, 4);// Read len
int recCounter=1;
while(readLen!=-1){
ByteArrayInputStream ba2=new ByteArrayInputStream (bufLen,0,4);
int z=ba2.read();
int reclen=0;
int li=0;
while(z!=-1){
if(li==0)
reclen+=z*256;
else if(li==1)
reclen+=z;
li++;
z=ba2.read();
}
ba2.close();
reclen-=4;
byte []buf=new byte[reclen];
readLen=binp.read(buf, 0, reclen);
boolean isEOF=false;
while(readLen<reclen) {
int nextLen=binp.read(buf, readLen, reclen-readLen);
if(nextLen==-1){// End of file is reached.
isEOF=true;
break;
}
readLen=readLen+nextLen;
}
String a=new String(buf, ZFile.DEFAULT_EBCDIC_CODE_PAGE);
StringBuilder str=new StringBuilder(a);
//str.append(System.getProperty("line.separator"));
System.out.println(""+str);
//appending extra space for record till its length matches file record length
if(str.length()<102) {
for (int i = str.length(); i < 102; i++) {
str.append(" ");
}
}
byte []outBytes=new byte[102];
outBytes=str.toString().getBytes(ZFile.DEFAULT_EBCDIC_CODE_PAGE);
bout.write(outBytes);
if(isEOF){
break;
}
readLen=binp.read(bufLen, 0, 4);// Read length- RDW
recCounter++;
}
bout.flush();
bout.close();
binp.close();
ftps.completePendingCommand();
ftps2.completePendingCommand();
ftps.logout();
}
catch (FTPConnectionClosedException e)
{
System.err.println("Server closed connection.");
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (ftps.isConnected())
{
try
{
ftps.disconnect();
}
catch (IOException f)
{
// do nothing
f.printStackTrace();
}
}
}
}
}
I am using the above code to read and write a VB file. I am able to read the variable block records. but while writing if I dont append the extra space to match the file record length, the data is getting jumbled. If I add extra space to it, it consumes a lot of memory. Am I missing something here? How can I solve this issue?..
I guess your issue is with ftps2.setFileType(FTP.BINARY_FILE_TYPE);.
Windows/Unix/Linux files don't know anything about "records", every file is just a stream of bytes. When working with text files that stream may contain end-of-line-characters (x0A,x0D or x0D0A in ASCII). These may be interpreted as end of a record and start of a new one, so most FTP-tools would start a new record on the z/OS side when they encounter one of these in text mode (and vice versa add one when starting a new record when transfering from z/OS).
With binary files things are a bit different, since x0D and x0A are not treated in any special way but are just two byte values among others.
So to get what you want you have these posibilities:
Transfer the file using text-mode, but this will likely result in some sort of codepage-conversion being done. If possible you might configure a custom translation-table doing no conversion at all.
Transfer the file in binary to some FB dataset and write a tool to split the continuous bytestream at the correct line-termination character and write the resulting records to a VB-dataset.
I am developing a tool to get client information, send to a server, and receive the information again (a proxy). I'm also trying to dump the data being received from the server. I can read the Integer representation of the inputStream, but I am not able to read the String format. I've tried the below example, but it hangs and never connects to the server. Also, System.out.println(inputStream.nextLine()) displays only one line and hangs.
public void run() {
try {
int i;
while ((i = inputStream.read()) != -1){
System.out.println(IOUtils.toString(inputStream));
outputStream.write(i);
}
} catch (IOException e) {
System.out.println("Lost connection to the client.");
}
}
My guess at this is that you're reading from the input stream, and then using the IOUtils library to read from the stream too. My suspicion is that your application is reading the first byte from the input stream, then reading the remainder of the inputstream with the IOUtils library, and then printing out the initial byte that was read.
It doesn't make any sense to call IOUtils.toString(inputstream) from within a loop. That method call will put all the data from the inputstream into a string. Why have the loop at all in this case?
You might want to try not using the IOUtils library for this. Just read a byte of data, push it into a StringBuilder, and then print that byte. In this approach, the loop would be necessary, and you'll probably get what you're looking for.
Try something like this, but modify it as necessary to print the data at the same time to your output stream:
public static String inputStreamToString(final InputStream is, final int bufferSize)
{
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try {
final Reader in = new InputStreamReader(is, "UTF-8");
try {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
}
finally {
in.close();
}
}
catch (UnsupportedEncodingException ex) {
/* ... */
}
catch (IOException ex) {
/* ... */
}
return out.toString();
}
The code you posted doesn't attempt to connect to the server, but if any of it executes you must already have connected.
If your program is hanging in this code, either the server hasn't sent any data yet, or the IOUtils.toString() method probably tries to read to EOS, so if the peer doesn't close the connection you will block here forever.
If your program hangs at a readLine() call it means the peer hasn't sent a line to read.
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 know that there is a good variant to use Scanner object when you need to get data from server during connetion. But I have question about the following code snippet:
public void sendMessage(String message) {
try {
OutputStream os = socket.getOutputStream();
try {
byte[] buffer;
buffer = message.getBytes();
os.write(buffer);
} finally {
os.close();
}
InputStream is = socket.getInputStream();
try {
StringBuffer data = new StringBuffer();
Scanner in = new Scanner(is);
while (in.hasNext()) {
data.append(in.next());
}
System.out.println(data.toString());
} finally {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
I'm confused by the snippet where Scanner gets data from InputStream, because it starts just after I send a message to the Server. Is it fair to suppose that data from the Server won't be in InputStream immediatelly after sending message to it?
Please, give me an advice, what is the best way to make reading data from InputStream in such case and what I should to take into consideration?
The InputStream.read() method called by Scanner blocks until there is some data available. So you don't have to worry about the response time of the server.
See: http://download.oracle.com/javase/6/docs/api/java/net/Socket.html#getInputStream()
The code is invalid. All it does is read as much input as can be read without blocking. There is no implication that what has been read is a complete message, or corresponds to a single write() invocation at the sender, etc. If you want messages in TCP/IP you must implement them yourself, with a length word prefix, a self-describing protocol such as Object Serialization or XML, etc. etc.