DataInputStream readert blocks - java

I'm reading and writing bytes on an open socket. This is my code.
#Test
public void testSingleRequest() throws IOException {
Server server = new Server(9000, 100);
new Thread(server).start();
Socket clientSocket = new Socket("localhost", 9000);
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
String payload = "a";
byte[] load = buildPushPayload(payload);
out.write(load);
DataInputStream in = new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));
byte[] buffer = new byte[128];
for (int i = 0; i <128 ; i++) {
int read = in.read(buffer, 0, 128);
}
out.close();
server.stop();
assertEquals(0, buffer[0]);
Since I'm reading a fixed length, I believe the for loop shouldn't block, but it still does. How do I get the loop to unblock?

Related

Why is my TCP system faster than UDP one?

I have two (client - server - client) system. First one uses TCP and second one uses UDP. It is interesting that my TCP using system is faster than UDP using one when transferring files in size 5-6 mb. Does problem occurs because of my coding mistakes or can that happen?
TCP Client
try {
socket = new Socket("localhost", 7755);
} catch (Exception e) {
System.out.println(e.getMessage().toString());
}
out = new PrintWriter(socket.getOutputStream(), true);
int i = 0;
while (file.hasNext()) {
String line = file.nextLine();
if (!line.isEmpty()) {
out.println(line);
}
i++;
}
TCP Server
try {
serverSocketA = new ServerSocket(7755);
serverSocketB = new ServerSocket(7760);
} catch (Exception e) {
System.out.println("Port error!");
}
System.out.println("Server is ready...");
clientSocketA = serverSocketA.accept();
clientSocketB = serverSocketB.accept();
PrintWriter out = new PrintWriter(clientSocketB.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocketA.getInputStream()));
while((dataFromClientA = in.readLine()) != null) {
out.println(dataFromClientA);
}
UDP Server
private static byte[] buf = new byte[6];
static Scanner file;
public static void main(String[] args) throws IOException{
long startTime = System.currentTimeMillis();
socket = new DatagramSocket();
address = InetAddress.getByName("localhost");
file = new Scanner(new File("sentfile.txt"));
DatagramPacket packet;
while (file.hasNext()) {
String line = file.nextLine();
if (!line.isEmpty()) {
buf = line.getBytes();
packet = new DatagramPacket(buf, buf.length, address, 7765);
socket.send(packet);
}
}
UDP Client
private static byte[] buffer = new byte[6];
private static byte[] buffer2 = new byte[6];
private static boolean running;
static PrintWriter writer;
public static void main(String[] args) throws IOException {
udpSocketB = new DatagramSocket();
address = InetAddress.getByName("localhost");
udpSocketA = new DatagramSocket(7765);
running = true;
DatagramPacket packet;
while(running) {
packet = new DatagramPacket(buffer, buffer.length);
udpSocketA.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
packet = new DatagramPacket(buffer, buffer.length, address, port);
String received = new String(packet.getData(), 0, packet.getLength());
DatagramPacket packetToB;
buffer2 = received.getBytes();
packetToB = new DatagramPacket(buffer2, buffer2.length, address, 7770);
udpSocketB.send(packetToB);
if (received.equals("end")) {
running = false;
continue;
}
}
I just add client1 and server codes and rest is similar. What could be the reason?
When you write over a TCP socket, it will coalesce bytes if possible into an MTU of data of around ~1500 bytes making the overhead of the packet header relatively small.
When you write each line in its own UDP packet it has an overhead for each line, possibly more than the actual data sent.
Note: in neither case do you need to read a line at a time. You can read say a byte[] of 1 KB at a time and print that.
public class TCPClient {
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket("localhost", 7755);
FileInputStream fis = new FileInputStream(args[0])) {
byte[] bytes = new byte[1024];
OutputStream out = socket.getOutputStream();
for (int len; (len = fis.read(bytes)) > 0; ) {
out.write(bytes, 0, len);
}
}
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7755);
System.out.println("Server is ready...");
try (Socket socket = serverSocket.accept()) {
byte[] bytes = new byte[1024];
for (int len; (len = socket.getInputStream().read(bytes)) > 0; )
System.out.write(bytes, 0, len);
}
}
}
You can do the same thing with UDP, transfering 1 KB at a time and get a similar throughput.
NOTE: UDP is lossy, so you might lose packets, or get them out of order.
TCP has been heavily optimized by some of the greatest networking experts in the world. It's specifically designed for sending streams of data over IP networks as quickly and efficiently as possible. It's tied into the kernel and they are heavily optimized as a unit on most modern platforms. You're not going to outperform it unless it does something that you don't need and you can obtain a significant benefit from not doing that thing.

Performing both character and byte input from java socket inputstream at same time

I am writing a raw socket server (for learning purpose), which on any request, should parse the Content-Length header and should then extract bytes equal to Content-Length from the socket input stream and echo it back to the client.
I found only one class 'DataInputStream' in Java IO system that provides with the capabilities of reading both, characters and bytes. However, the method readLine() of 'DataInputStream' is deprecated which I am using in my code. How can I get rid of the deprecated readLine() method in following code? Is there any class in Java IO system that allows reading of both, characters and bytes. Code follows:
class Server {
public Server() {
}
public void run() throws IOException {
ServerSocket serverSocket = new ServerSocket(7000);
while (true) {
Socket socket = serverSocket.accept();
DataInputStream requestStream = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
byte[] responseContent = null;
int contentLength = getContentLength(requestStream);
if (contentLength == 0)
responseContent = new byte[0];
else {
int totalBytesRead = 0, bytesRead = 0;
final int bufferSize = 5120;
final byte[] buffer = new byte[bufferSize];
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while (totalBytesRead != contentLength) {
bytesRead = requestStream.read(buffer, 0, bufferSize);
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
}
responseContent = outputStream.toByteArray();
}
OutputStream outputStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(outputStream);
writer.println(String.format("HTTP/1.1 %s", 200));
writer.println(String.format("Content-Length: %d", contentLength));
writer.println("");
writer.flush();
outputStream.write(responseContent);
outputStream.flush();
socket.close();
}
}
private int getContentLength(DataInputStream requestStream)
throws IOException {
int contentLength = 0;
String headerLine;
// TODO - Get rid of deprecated readLine() method
while ((headerLine = requestStream.readLine()) != null
&& headerLine.length() != 0) {
final String[] headerTokens = headerLine.split(":");
if (headerTokens[0].equalsIgnoreCase("Content-Length")) {
contentLength = Integer.valueOf(headerTokens[1].trim());
}
}
return contentLength;
}
}

Not receiving any further messages after receiving a file over socket

I am sending a file over socket from client to server. Thats working fine. But once a file is received, server program is not receiving any further messages. Its all receiving is null.
Here is the client-server code.
Client:
main(...){
Socket sock = new Socket("127.0.0.1", 12345);
File file = new File("file.txt");
byte[] mybytearray = new byte[(int) file.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
bis.read(mybytearray, 0, mybytearray.length);
OutputStream os = sock.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
PrintWriter out = new PrintWriter(os, true);
out.println("next message");
//closing here all streams and socket
}
Server:
main(...){
ServerSocket servsock = new ServerSocket(12345);
while (true) {
Socket sock = servsock.accept();
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
Scanner scan1 = new Scanner(is);
FileOutputStream fos = new FileOutputStream("myfile.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
bos.close();
fos.close();
//Till here works fine, and file is successfully received.
//Below is the code to receive next message.
//Unfortunately it is not working
BufferedReader input = new BufferedReader(new InputStreamReader(is));
String line = input.readLine();
System.out.println(line); //prints null, Whats the reason?
}
}
This is an example that assumes it is a file then a line of text. In both cases I send the length first so it can just be dealt with as byte arrays.
Server:
ServerSocket servsock = new ServerSocket(12345);
while (true) {
Socket sock = servsock.accept();
try (DataInputStream dis = new DataInputStream(sock.getInputStream())) {
int len = dis.readInt();
byte[] mybytearray = new byte[len];
dis.readFully(mybytearray);
try (FileOutputStream fos = new FileOutputStream("myfile.txt")) {
fos.write(mybytearray);
}
len = dis.readInt();
mybytearray = new byte[len];
dis.readFully(mybytearray);
String line = new String(mybytearray);
System.out.println("line = " + line);
}
}
Client:
Socket sock = new Socket("127.0.0.1", 12345);
File file = new File("file.txt");
byte[] mybytearray = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(mybytearray);
try(DataOutputStream os = new DataOutputStream(sock.getOutputStream())) {
os.writeInt(mybytearray.length);
os.write(mybytearray, 0, mybytearray.length);
String nextMessage = "next message\n";
byte message[] = nextMessage.getBytes();
os.writeInt(message.length);
os.write(message, 0, message.length);
}
The basic problem is you assume a) your file is exactly 1024 bytes long when you read. b) when you attempt to read you get all the data in one go. The minimum is 1 byte even if you wrote much more.
I suggest you
send the length with the file so you know how much to read.
you chose either binary or text and only do one or the other.

Data loss while sending image over socket from android client to Java server

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.

java send file using sockets

I am trying to send a file from one computer to another using Java. I have written the code below, it works fine if both sender and receiver are started in the same computer but if they work on different machines received file size is bigger than the original file and it is corrupted.
Note: I am trying to transfer files which are max 10 MBs.
How can I fix this?
Sender:
ServerSocket server_socket = new ServerSocket(8989);
File myFile = new File(myPath);
Socket socket = server_socket.accept();
int count;
byte[] buffer = new byte[1024];
OutputStream out = socket.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(myFile));
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
out.flush();
}
socket.close();
Receiver:
Socket socket = new Socket(address, 8989);
FileOutputStream fos = new FileOutputStream(anotherPath);
BufferedOutputStream out = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int count;
InputStream in = socket.getInputStream();
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
fos.close();
socket.close();
On the client side you write up to count bytes and send them:
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
on the server side you read up to count bytes - but then you write the whole buffer to file!
while((count=in.read(buffer)) > 0){
fos.write(buffer);
Just change it to:
fos.write(buffer, 0, count);
and you'll be on the safe side. BTW your program has another small bug: read() can return 0 which doesn't mean InputStream ended. Use >= instead:
count = in.read(buffer)) >= 0
Have you considered IOUtils.copy(InputStream, OutputStream) from Apache Commons? It would reduce your whole while loops to:
OutputStream out = socket.getOutputStream();
InputStream in = new FileInputStream(myFile);
IOUtils.copy(in, out);
socket.close();
Less code to write, less code to test. And buffering is done internally.
Remember that in.read(buffer) not necessarily fills up the whole buffer with new data. Therefore you should make sure you don't write the whole buffer. Change
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
to
while((count=in.read(buffer)) >0){
fos.write(buffer, 0, count);
}
sender
Socket sock = new Socket("127.0.0.1", 5991);
System.out.println("Connecting.........");
File myFile = new File("/root/qrcode/");
File[] files = myFile.listFiles();
OutputStream os = sock.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.length);
long totalBytesRead = 0;
int percentCompleted = 0;
for(File file : files)
{
long length = file.length();
dos.writeLong(length);
String name = file.getName();
dos.writeUTF(name);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while((theByte = bis.read()) != -1)
{
totalBytesRead += theByte;
bos.write(theByte);
}
// System.out.println("file read");
bis.close();
}
dos.close();
//Closing socket
sock.close();
receiver
ServerSocket serverSocket = new ServerSocket(5991);
while(true) {
Socket clientSocket = null;
System.out.println("Starting...");
clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream(); //used
BufferedInputStream bis = new BufferedInputStream(in);
String dirPath ;
dirPath = "/root/NewFolder";
try{
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
long f_l = 0;
int count =0 ;
long totalBytesRead = 0;
int percentCompleted = 0;
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
f_l = f_l +fileLength;
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int tot = 0;
for(int j = 0; j < fileLength; j++) {
bos.write(bis.read());
}
bos.close();
}
}catch(Exception ex)
{
System.out.println("error in socket programming ");
}
}

Categories

Resources