Java Image Server: socket write error - java

A couple of days ago I thought about programming my own image client to transfer images directly via the HTTP. I googled and researched quite some time and wrote my server:
public class SConnection extends Thread {
Socket client;
/* ... */
#Override
public void run() {
while(true) {
try {
//Get some image paths
File folder = new File(new java.net.URI("file:///C:/images/"));
File[] images = folder.listFiles();
//Load the image
BufferedImage bi = ImageIO.read(images[0]);
//Write the image
ImageIO.write(bi, "JPEG", client.getOutputStream());
} catch (Exception ex) {
ex.printStackTrace();
return;
}
}
}
The main class is a Thread waiting to accept many connections, storing them in an ArrayList, creating instances of SConnection and starting them.
The client looks like this:
URL target = new URL("http://127.0.0.1:82"); //The server - so far, so good
URLConnection conn = target.openConnection();
BufferedImage in = ImageIO.read(conn.getInputStream()); //And as I try to receive the image: boom, exception
File save = new File(new java.net.URI("file:///C:/images/result.jpeg"));
ImageIO.write(in, "JPEG", save);
Server and client both send Exceptions located at the ImageIO.write / ImageIO.read - lines.
The server says:
java.net.SocketException: Connection reset by peer: socket write error
The client says:
java.io.IOException: Invalid Http response
I get, that the image is not transferred correctly, but what should I change? Any clues?
Thanks you guys, in advance!

You don't appear to be writing HTTP headers, so the client URLConnection won't understand the reply and will close the connection, causing 'connection reset by peer' at the sender.
You don't need to construct a URI to open a file.
You don't need to use ImageIO at all. This just wastes time and space. Just copy the bytes, like any other file type.
In short you don't really need this code at all. The default servlet will do it for you.

Related

How to receive PDF from HTTP Post in Citrus and write it to a file?

I am developing a test for a service.
I make a first HTTP Post, send an xml file, and receive a PDF.
Then I make a second call with this PDF, and the service sends me back a .png file corresponding to this PDF.
But I get stuck at the first step when I have to retrieve the PDF file. I use the Citrus framework, and here is how I make my call and I receive the answer
runner.http(httpActionBuilder -> httpActionBuilder
.client(vdeClient)
.send()
.post(PDF_GEN_URI)
.contentType(MediaType.APPLICATION_XML_VALUE)
.payload(xml)
);
runner.http(httpActionBuilder -> httpActionBuilder
.client(vdeClient)
.receive()
.response(HttpStatus.OK)
.contentType(MediaType.APPLICATION_PDF_VALUE)
);
And then I access the payload of the answer (= The PDF)
Object pdfPayload = context.getMessageStore().getMessage("nameOfTheMessage").getPayload();
The payload seems to be correct, but when I convert it to a byte[] and write it to a new file, it is empty and does not contain what it should.
Is this a character encoding problem or something like that? Thanks
Here is how I do the conversion
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
byte[] pdfBytes;
try {
out = new ObjectOutputStream(bos);
out.writeObject(pdfPayload);
out.flush();
pdfBytes = bos.toByteArray();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
If you managed to get PDF file content as bytes than you don't need to use ObjectOutputStream. Just write your byte array as it is into a file named .pdf and you should be OK. As for downloading and uploading files though Http requests I actually wrote my own Http client that is very simple in use. My Http client doesn't provide all the width of functionality that other well known Http clients (such as Apache Http client or OK Http client) provide but the simplicity of use is the key. Here is a working example that download and saves excutable file as file named kubectl
public static void downloadFile() {
HttpClient httpClient = new HttpClient();
httpClient.setRequestHeader("Accept", "application/octet-stream");
httpClient.setConnectionUrl("https://dl.k8s.io/release/v1.20.0//bin/linux/amd64/kubectl");
ByteBuffer buffer = null;
try {
buffer = httpClient.sendHttpRequestForBinaryResponse(HttpClient.HttpMethod.GET);
System.out.println(httpClient.getLastResponseCode() + " " + httpClient.getLastResponseMessage());
} catch (IOException ioe) {
System.out.println(httpClient.getLastResponseCode() + " " + httpClient.getLastResponseMessage());
System.out.println(TextUtils.getStacktrace(ioe, "com.mgnt.stam."));
}
try {
Files.write(Paths.get("C:\\Michael\\work\\Installations\\Kubernetes\\kubectl"), buffer.array());
} catch (IOException e) {
System.out.println(TextUtils.getStacktrace(e, "com.mgnt.stam."));
}
}
Here is Javadoc for HttpClient class. In particular note methods sendHttpRequest and sendHttpRequestForBinaryResponse using those methods you can send textual or binary info as part of request body and get back textual or binary content. This Http client is part of MgntUtils library (written and maintained by me). You can get the library as Maven artifacts or on the Github (including source code and Javadoc). BTW class TextUtils used in my example is also part of MgntUtils library

Qt server / Java Client communication problems

I am currently trying to get a little network communication going between a qt server and a java client.
In my example, the client wants to send an image to the Server. My problem is now, that the server never sees the data, so bytesAvailable() returns 0.
I already tried QDataStream, QTextStream and readAll(), still no data.
Server:
QTcpServer* tcpServer;
QTcpSocket* client;
tcpServer = new QTcpServer();
if(!tcpServer->listen(QHostAddress::Any, 7005)){
tcpServer->close();
return;
}
...
tcpServer->waitforNewConnection();
client = tcpServer->nextPendingConnection();
client->waitForConencted();
while(client->state()==connected){
// Syntax here might be iffy, did it from my phone
if(client->bytesAvailable()>0){
//do stuff here, but the program doesnt get here, since bytesAvailable returns 0;
}
}
CLient:
public SendPackage() {
try {
socket = new Socket(ServerIP, Port);
socket.setSoTimeout(60000);
output = new BufferedOutputStream(socket.getOutputStream());
outwriter = new OutputStreamWriter(output);
} catch (ConnectException e) {
System.out.println("Server error, no connection established.");
} catch (Exception e) {
e.printStackTrace();
}
}
public void Send(BufferedImage img) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, GUI.imageType, baos);
baos.flush();
byte[] imgbyte = baos.toByteArray();
System.out.println(imgbyte.length);
System.out.println("sending");
outwriter.write(imgbyte.length);
outwriter.flush();
// here i'd send the image, if i had a connection ...
output.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
The connection and everything builds up fine, the code even tells me when the socket was disconnected when trying to send, so I guess connection isn't a problem.
I just started using Qt, so if you guys have any idea to why this wouldn't work, I'd be pleased to try it.
client->waitForConencted();
// At this point the client is connected, but it is likely that no data were received yet
client->waitForReadyRead(-1); // <- Add this
// Now there should be at least 1 byte available, unless waitForConencted or waitForReadyRead failed (you should check that)
if(client->bytesAvailable() > 0) {
// ...
}
Note that you can not expect all the data to arrive at once. The TCP stream can get fragmented in any way and the data will be received in randomly sized pieces. You must repeat waiting and reading until you receive everything. This also means that you must somehow know when you did receive everything. So you need to know how much data is coming, or somehow recognize the end of it. You can for example disconnect right after the data transfer, or send the data length first. Depends on your application.
Also have a look at QIDevice::readyRead signal which would allow you to handle reading asynchronously.

TCP detect disconnected server from client

I'm writing a simple TCP client/server program pair in Java, and the server must disconnect if the client hasn't sent anything in 10 seconds. socket.setSoTimeout() gets me that, and the server disconnects just fine. The problem is - how can I get the client to determine if the server is closed? Currently I'm using DataOutputStream for writing to the server, and some answers here on SO suggest that writing to a closed socket will throw an IOException, but that doesn't happen.
What kind of writer object should I use to send arbitrary byte blocks to the server, that would throw an exception or otherwise indicate that the connection has been closed remotely?
Edit: here's the client code. This is a test function that reads one file from the file system and sends it to the server. It sends it in chunks, and pauses for some time between each chunk.
public static void sendFileWithTimeout(String file, String address, int dataPacketSize, int timeout) {
Socket connectionToServer = null;
DataOutputStream outStream = null;
FileInputStream inStream = null;
try {
connectionToServer = new Socket(address, 2233);
outStream = new DataOutputStream(connectionToServer.getOutputStream());
Path fileObject = Paths.get(file);
outStream.writeUTF(fileObject.getFileName().toString());
byte[] data = new byte[dataPacketSize];
inStream = new FileInputStream(fileObject.toFile());
boolean fileFinished = false;
while (!fileFinished) {
int bytesRead = inStream.read(data);
if (bytesRead == -1) {
fileFinished = true;
} else {
outStream.write(data, 0, bytesRead);
System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + bytesRead + " bytes.");
Thread.sleep(timeout);
}
}
} catch (IOException | InterruptedException e) {
System.out.println("Something something.");
throw new RuntimeException("Problem sending data to server.", e);
} finally {
TCPUtil.silentCloseObject(inStream);
TCPUtil.silentCloseObject(outStream);
TCPUtil.silentCloseObject(connectionToServer);
}
}
I'd expect the outStream.write to throw an IOException when it tries to write to a closed server, but nothing.
I'd expect the outStream.write to throw an IOException when it tries to write to a closed server, but nothing.
It won't do that the first time, because of the socket send buffer. If you keep writing, it will eventually throw an IOException: 'connection reset'. If you don't have data to get to that point, you will never find out that the peer has closed.
I think you need to flush and close your stream after written like outStream.flush(); outStream.close(); inStream.close();
Remember ServerSocket.setSoTimeout() is different from client's function with same name.
For server, this function only throws SocketTimeoutException for you to catch it if timeout is expired, but the server socket still remains.
For client, setSoTimeout() relates to 'read timeout' for stream reading.
In your case, you must show your server code of closing the connected socket after catching SocketTimeoutException => ensure server closed the associated socket with a specified client. If done, at client side, your code line:
throw new RuntimeException("Problem sending data to server.", e);
will be called.
[Update]
I noticed that you stated to set timeout for the accepted socket at server side to 10 secs (=10,000 milliseconds); for that period, did your client complete all the file sending? if it did, never the exception occurs.
[Suggest]
for probing, just comment out your code of reading file content to send to server, and try replacing with several lines of writing to output stream:
outStream.writeUTF("ONE");
outStream.writeUTF("TWO");
outStream.writeUTF("TREE");
Then you can come to the conclusion.

Sending a databse via ftp - Getting a different file

I'm currently using this code to send a database over ftp (Using apache commons)
File file = getDatabasePath("database");
FTPClient ftp = new FTPClient();
try {
ftp.connect(InetAddress.getByName(domain));
ftp.login(username, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
FileInputStream is = new FileInputStream(file);
BufferedInputStream buffIn = new BufferedInputStream(is);
ftp.enterLocalPassiveMode();
ftp.storeFile("database", buffIn);
buffIn.close();
ftp.logout();
ftp.disconnect();
} catch (Exception e) {
// TODO: handle exception
}
I've used it to send a text file and it works. However, I've tried it with my database and a file of the same size is put on the server but SQLite browser displays nothing when I open it. It works on a really small database but as soon as the database is larger I get this problem.
I was wondering if it could be to do with the buffer size? Could anyone shed some light on why this is happening?
Thanks
The code you posted will not work for files which don't fit to the buffered input stream's buffer. What you need to do is read repeatedly from the input stream until its end:
ftp.enterLocalPassiveMode();
ftp.storeFile("database", buffIn);
byte[] buffer = new byte[8192];
OutputStream os = ftp.storeFileStream("database");
int readCount = 0;
while ((readCount = buffIn.read(buffer)) > 0) {
os.write(buffer, 0, readCount);
}
os.close();
buffIn.close();
The important thing is the use of storeFileStream() instead of storeFile(). Also, as commenters suggest, you need to check return codes from the server and do proper error handling.
SQLite Database Copy Appears Corrupted When Generated by Device and not Emulator
Opening the database file in a different program seems to work. See above link.

java.net.SocketException: Software caused connection abort: socket write error [duplicate]

This question already has answers here:
Official reasons for "Software caused connection abort: socket write error"
(14 answers)
Closed 6 years ago.
I am trying to send an image from a Java desktop application to a J2ME application. The problem is that I am getting this exception:
java.net.SocketException: Software caused connection abort: socket write error
I have looked around on the net, and although this problem is not that rare, I was unable to find a concrete solution. I am transforming the image into a byte array before transferring it. These are the methods found on the desktop application and on the J2ME respectively
public void send(String ID, byte[] serverMessage) throws Exception
{
//Get the IP and Port of the person to which the message is to be sent.
String[] connectionDetails = this.userDetails.get(ID).split(",");
Socket sock = new Socket(InetAddress.getByName(connectionDetails[0]), Integer.parseInt(connectionDetails[1]));
OutputStream os = sock.getOutputStream();
for (int i = 0; i < serverMessage.length; i++)
{
os.write((int) serverMessage[i]);
}
os.flush();
os.close();
sock.close();
}
private void read(final StreamConnection slaveSock)
{
Runnable runnable = new Runnable()
{
public void run()
{
try
{
DataInputStream dataInputStream = slaveSock.openDataInputStream();
int inputChar;
StringBuffer results = new StringBuffer();
while ( (inputChar = dataInputStream.read()) != -1)
{
results.append((char) inputChar);
}
dataInputStream.close();
slaveSock.close();
parseMessage(results.toString());
results = null;
}
catch(Exception e)
{
e.printStackTrace();
Alert alertMsg = new Alert("Error", "An error has occured while reading a message from the server:\n" + e.getMessage(), null, AlertType.ERROR);
alertMsg.setTimeout(Alert.FOREVER);
myDisplay.setCurrent(alertMsg, resultScreen);
}
}
};
new Thread(runnable).start();
}
I am sending the message across a LAN, and I have no problems when I send short text messages instead of images. Also, I used wireshark and it seems that the desktop application is only sending part of the message. Any help would be highly appreciated. Also, everything works on the J2ME simulator.
Please refer to the answers to Official reasons for "Software caused connection abort: socket write error"
EDIT
I don't think there is much more that can be said in general, and there doesn't appear to be anything unusual about your code that would cause connections to abort. I would however note that:
Casting the bytes to integers for the write call is unnecessary. It will be promoted automatically.
It would be better (simpler, potentially more efficient in terms of network traffic) to use write(byte[]) instead of write(int).
The receiving side is assuming that each byte represents a complete character. This may be incorrect depending on how the sending side formed the bytes to be transmitted, and
It would be a good idea to start by sending a byte count so that the receiving end can tell if something has gone wrong before the sender sent the whole byte array.

Categories

Resources