Writing bytes to file from multiple packets - java

i am working on algorithm that will receive data and i want to write them to the file.
First packet that i receive is packet containing fileName.
Second packet is containing sizeOfPacket.
then i have to calculate number of Packets that i receive.
But my actual problem starts when i want to receive next packets and write these packets to the file byte by byte.
I tried it in many ways but every time the resulting file is just 1kb large but actual image is 72kb large.
I have to read from the packets from 4th byte because first 4 bytes are storing position of packet in file.
Size of every packet is 1024B
public void run(int port) throws IOException {
try {
byte[] receiveData = new byte[1024];
DatagramSocket serverSocket = new DatagramSocket(port);
System.out.printf("Listening on udp:%s:%d%n",
InetAddress.getLocalHost().getHostAddress(), port);
DatagramPacket receivePacket = new DatagramPacket(
receiveData,
SIZE_OF_PACKET
);
//first packet with name of file
serverSocket.receive(receivePacket);
String fileName = utils.getFileName(receivePacket);
//System.out.println(fileName);
//System.out.println(fileName.length());
//second packet with size of whole data()
serverSocket.receive(receivePacket);
int sizeOfFile = utils.BytesToInt(receivePacket);
//get number of packets that are needed
int numOfPackets = utils.getNumOfPackets(sizeOfFile);
//System.out.println(sizeOfFile);
//System.out.println(numOfPackets);
//output stream for file "test.jpg"
FileOutputStream fos = new FileOutputStream("test.jpg");
//loop over for the number of Packets
for(int i = 0; i < numOfPackets - 1; i++) {
serverSocket.receive(receivePacket);
receiveData = receivePacket.getData();
//byte byte after byte and write it to the file
// start at index 3 bcs first byte is packet number
for(int a = 3; a < SIZE_OF_PACKET - 1;a++) {
Byte nextByte = receiveData[a];
if(nextByte != 0) fos.write(nextByte);
}
}
fos.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}

Related

Sending and receiving byte array in java

I'm having some trouble with my socket programming codes. I have a server tcp that receives the password from client, if it's true, the server will send a file back to client to save, else server will send a byte array with the length is 0.
Then the client will receive the byte array and get the length to compare with 0, if byte length = 0, the client will print out "Wrong password", else it will tell you to enter the file name.
The big problem is the server sent byte array with length = 0 when password is wrong, but client receive byte array with length = 1. I do not know how to solve it....:(
Here is my TCPServer code:
import java.io.*;
import java.net.*;
import java.util.Scanner;
class ServerTCP{
public static void main (String[] args){
try{
ServerSocket ss = new ServerSocket(2018);
System.out.println("\n(*) Server Socket has been created!");
while(true){
Socket s = ss.accept();
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
PrintWriter pw = new PrintWriter(os);
Scanner sc = new Scanner(is);
//Receive information from client
String mail = sc.nextLine();
String pass = sc.nextLine();
System.out.println("Password is: " + pass);
if(matkhau.equals("passtcp")){
String filegui = "D:/filename.pdf";
FileInputStream f = new FileInputStream(filegui);
int lenf = f.available();
byte b2[] = new byte[lenf];
f.read(b2);
f.close();
os.write(b2);
}
else{
byte b[] = new byte[1];
int lenb = 0;
os.write(b);
}
}
}catch(IOException e){
System.out.println("\n(!)An error occured while creating socket!");
}
}
}
Here is my client code
import java.net.*;
import java.io.*;
import java.util.Scanner;
class UdpTcpTest{
public static void main (String[] args){
//String matkhau = new String();
Scanner k = new Scanner(System.in);
try{
//Enter TCP Server's ip
System.out.print("Enter TCP Server's ip: ");
String ip1 = k.nextLine();
//Tao socket
Socket s = new Socket(ip1, 2018);
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
PrintWriter pw = new PrintWriter(os);
String mail = "yourmail#test.com";
String password = "matkhaune";
//send mail and password to server
pw.println(mail); pw.flush();
pw.println(password); pw.flush();
//receive information
byte brecv[] = new byte[60000];
int lenfile = is.read(brecv);
System.out.println("Length = " + lenfile);
if(lenfile <= 1){
System.out.println("Wrong password! Length = " + lenfile);
}
else{
//Save file
System.out.print("Enter file name to save: ");
String filenamed = k.nextLine();
FileOutputStream f = new FileOutputStream(filenamed);
f.write(brecv, 0, lenfile);
f.close();
System.out.println("Saving Scuccess!");
s.close();
}
}catch(IOException e){
System.out.println("Error while excuting!");
}
}
}
I'm having some trouble with my socket programming codes. I have a server tcp that receives the password from client, if it's true, the server will send a file back to client to save, else server will send a byte array with the length is 0.
Impossible.
Then the client will receive the byte array and get the length to compare with 0, if byte length = 0, the client will print out "Wrong password", else it will tell you to enter the file name.
Impossible. You will have to redesign your protocol. You can't send a byte array of zero length over TCP. The minimum is one byte.
The big problem is the server sent byte array with length = 0 when password is wrong
No it didn't. It sent a byte array with length = 1:
byte b[] = new byte[1]; // Here is your byte array of length 1
int lenb = 0; // This is unused. Delete.
os.write(b); // Here you are sending the entire byte array
but client receive byte array with length = 1.
That is correct.
I do not know how to solve it....:(
There is nothing here to solve. Your code is working as designed. You just need to adjust your client to test for a 1-byte receive instead of an impossible zero-byte receive:
int lenfile = is.read(brecv);
System.out.println("Length = " + lenfile);
if(lenfile == 1){

When creating an array of DatagramPackets, each element becomes the same as the most recent element added

public DatagramPacket[] makePackets(byte[] data, InetAddress IP, int portNumber) {
// create packet buffer
ByteBuffer buffer = ByteBuffer.allocate(packetSize);
// calculate number of packets
int dataSize = packetSize - 10;
int totalPackets = data.length / dataSize;
if(data.length % dataSize > 0)
totalPackets++;
System.out.println("Total Packets " + totalPackets);
DatagramPacket[] pkts = new DatagramPacket[totalPackets];
for(int seqNumber = 0; seqNumber < totalPackets; seqNumber++)
{
// insert metadata
buffer.putChar(informUpdate);
buffer.putInt(seqNumber);
buffer.putInt(totalPackets);
// adds data to the buffer
if(seqNumber == totalPackets -1) // if last packet adjust length to avoid null pointer
buffer.put(data, seqNumber * dataSize, data.length - seqNumber*dataSize);
else
buffer.put(data, seqNumber * dataSize, dataSize);
// create packet
byte[] sendData = buffer.array();
// add packets to packet array and clear buffer
pkts[seqNumber] = new DatagramPacket(sendData, sendData.length, IP, portNumber);
System.out.println(new String(pkts[seqNumber].getData())); // <- Check if packets are being made correctly
buffer.clear();
}
// this shows prints all elements in pkts which proves all data is the same
for(int i = 0; i < pkts.length; i++)
System.out.println(new String(pkts[i].getData()));
return pkts; }
Hopefully I've added my code in a readable format. Thanks ahead of time!
When you do this:
byte[] sendData = buffer.array();
You are retrieving the same byte array in each loop iteration. Each DatagramPacket you create is reusing that same byte array.
The easiest solution is to clone the byte array, since every array in Java has a public clone() method which throws no exceptions:
byte[] sendData = buffer.array().clone();

File download from PC to Android device - OutputStream write( ) stucks for large files

I'm trying to download a file from PC to Android device (emulator or physical)
Everything goes fine for small and medium sized files, but when I try to send something larger than say 10Mb, server never reaches this statement out2.println("ready");, hence the client hangs waiting for "ready" from server
Seems that server stucks at this: os.write(bytearray, 0, bytearray.length);
So far I've tried this on emulator, I'm going to report about results on a real device shortly
Here is my client part, in Android app: Android client sends "download" string to server, then receives "ready" reply from it, and starts reading file from InputStream
int filesize = 2022386;
int bytesRead;
int currentTot = 0;
Socket socket1 = new Socket("172.16.6.119", 50001); //data line
Socket socket2 = new Socket("172.16.6.119", 50001); //control line
BufferedReader in2 = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
PrintWriter out2 = new PrintWriter(socket2.getOutputStream(), true);
out2.println("download:"); //control line
String usrtxt = in2.readLine();
if(usrtxt.substring(0,5).equals("ready")) //control line
{
byte [] bytearray = new byte [filesize];
InputStream is = socket1.getInputStream(); //data line
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().toString() + "/sunset.jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray,0,bytearray.length);
currentTot = bytesRead;
Log.e("DOWNLOAD", "init value: bytesread = " + Integer.toString(bytesRead));
do {
bytesRead =
is.read(bytearray, currentTot, (bytearray.length-currentTot)); //<--does not pull data (WHY?)
Log.e("DOWNLOAD", "bytesread = " + Integer.toString(bytesRead));
if(bytesRead >= 0) currentTot += bytesRead;
} while(bytesRead > -1);
out1.println("finished:");
bos.write(bytearray, 0 , currentTot);
Log.e("DOWNLOAD", Integer.toString(currentTot));
bos.flush();
bos.close();
socket1.close(); socket2.close();
}
And this is my server code: it accepts connection from client, then receives "download" string from it, replies with "ready", and puts the file onto OutputStream
while (true) {
final Socket socket = serverSocket.accept(); //data line
final Socket socket2= serverSocket.accept(); //control line
BufferedReader in2 = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
PrintWriter out2 = new PrintWriter(socket2.getOutputStream(), true);
String usrtxt = in2.readLine(); //control line
if(usrtxt.substring(0,8).equals("download"))
{
System.out.println("accepted download request. sending file");
File transferFile = new File("sunset.jpg");
byte[] bytearray = new byte[(int)transferFile.length()];
FileInputStream fin = new FileInputStream(transferFile);
BufferedInputStream bin = new BufferedInputStream(fin);
bin.read(bytearray, 0, bytearray.length);
OutputStream os = socket.getOutputStream();
os.write(bytearray, 0, bytearray.length); //data line
os.flush();
os.close();
out2.println("ready"); //control line
socket.close(); socket2.close();
bin.close(); fin.close();
System.out.println("file transfer complete");
}//end if
}//end while
This is no way to copy streams. It assumes too many things that may not be true.
The canonical way in Java is as follows:
byte[] buffer = new byte[8192]; // or whatever you like, anything above zero. Note that it doesn't have to be the size of the file
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you know the length in advance and you want to keep the socket open afterwards, keep track of the bytes transferred so far via 'total += count;' after the read call inside the loop, and change the read call to read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total)).

How to read all of Inputstream in Server Socket JAVA

I am using Java.net at one of my project.
and I wrote a App Server that gets inputStream from a client.
But some times my (buffered)InputStream can not get all of OutputStream that client sent to my server.
How can I write a wait or some thing like that, that my InputStream gets all of the OutputStream of client?
(My InputStream is not a String)
private Socket clientSocket;
private ServerSocket server;
private BufferedOutputStream outputS;
private BufferedInputStream inputS;
private InputStream inBS;
private OutputStream outBS;
server = new ServerSocket(30501, 100);
clientSocket = server.accept();
public void getStreamFromClient() {
try {
outBS = clientSocket.getOutputStream();
outputS = new BufferedOutputStream( outBS);
outputS.flush();
inBS = clientSocket.getInputStream();
inputS = new BufferedInputStream( inBS );
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks.
The problem you have is related to TCP streaming nature.
The fact that you sent 100 Bytes (for example) from the server doesn't mean you will read 100 Bytes in the client the first time you read. Maybe the bytes sent from the server arrive in several TCP segments to the client.
You need to implement a loop in which you read until the whole message was received.
Let me provide an example with DataInputStream instead of BufferedinputStream. Something very simple to give you just an example.
Let's suppose you know beforehand the server is to send 100 Bytes of data.
In client you need to write:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
while(!end)
{
int bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length == 100)
{
end = true;
}
}
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
Now, typically the data size sent by one node (the server here) is not known beforehand. Then you need to define your own small protocol for the communication between server and client (or any two nodes) communicating with TCP.
The most common and simple is to define TLV: Type, Length, Value. So you define that every message sent form server to client comes with:
1 Byte indicating type (For example, it could also be 2 or whatever).
1 Byte (or whatever) for length of message
N Bytes for the value (N is indicated in length).
So you know you have to receive a minimum of 2 Bytes and with the second Byte you know how many following Bytes you need to read.
This is just a suggestion of a possible protocol. You could also get rid of "Type".
So it would be something like:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
int bytesRead = 0;
messageByte[0] = in.readByte();
messageByte[1] = in.readByte();
int bytesToRead = messageByte[1];
while(!end)
{
bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length == bytesToRead )
{
end = true;
}
}
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
The following code compiles and looks better. It assumes the first two bytes providing the length arrive in binary format, in network endianship (big endian). No focus on different encoding types for the rest of the message.
import java.nio.ByteBuffer;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
class Test
{
public static void main(String[] args)
{
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
Socket clientSocket;
ServerSocket server;
server = new ServerSocket(30501, 100);
clientSocket = server.accept();
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
int bytesRead = 0;
messageByte[0] = in.readByte();
messageByte[1] = in.readByte();
ByteBuffer byteBuffer = ByteBuffer.wrap(messageByte, 0, 2);
int bytesToRead = byteBuffer.getShort();
System.out.println("About to read " + bytesToRead + " octets");
//The following code shows in detail how to read from a TCP socket
while(!end)
{
bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length() == bytesToRead )
{
end = true;
}
}
//All the code in the loop can be replaced by these two lines
//in.readFully(messageByte, 0, bytesToRead);
//dataString = new String(messageByte, 0, bytesToRead);
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
You can read your BufferedInputStream like this. It will read data till it reaches end of stream which is indicated by -1.
inputS = new BufferedInputStream(inBS);
byte[] buffer = new byte[1024]; //If you handle larger data use a bigger buffer size
int read;
while((read = inputS.read(buffer)) != -1) {
System.out.println(read);
// Your code to handle the data
}
int c;
String raw = "";
do {
c = inputstream.read();
raw+=(char)c;
} while(inputstream.available()>0);
InputStream.available() shows the available bytes only after one byte is read, hence do .. while

Sending large data over sockets in java

I am working on client server architecture and i am just beginner in this thing. Here my server is of C and client is of Java and i want to send a binary/database (.db)/image file of size around 10 - 20 MB from C server to the Java client. But data is lost while implementing the following code:
Server side C code is:
int sockfd, newsockfd, portno, clilen;
struct sockaddr_in serv_addr, client_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
strcpy(message,"Error opening socket");
eFlag = 1;
send_message(message);
}
bzero((char *)&serv_addr, sizeof(serv_addr));
portno = 6789;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
strcpy(message,"Error on binding");
eFlag = 1;
send_message(message);
}
listen(sockfd, 5);
clilen = sizeof(client_addr);
newsockfd = accept(sockfd, (struct sockaddr *)&client_addr, &clilen);
if(newsockfd < 0)
{
strcpy(message,"Error on accept");
eFlag = 1;
send_message();
exit(4);
}
void send_file()
{
buffer = (char *)malloc(sizeof(char)*lSize);
result = fread(buffer, sizeof(char), lSize, fp);
printf("\n\n########## data read into buffer successfully #######");
if(newsockfd)
{
n = send(newsockfd, buffer, lSize);
printf("\n\n$$$$$$$$ Data sent successfully $$$$$");
strcpy(message,"Data sent successfully");
send_message(message);
}
else
{
strcpy(message, "Error writing on socket");
send_message(message);
}
sleep(sleepTime);
sleepTime = (int) (sleepTime*1.02);
free(buffer);
}
And, my client side Java code is:
final int PORT_NO = 6789;
final String Server_name = "192.133.133.1";
Socket m_socket = null;
String str;
int ch;
try {
if(m_socket == null)
m_socket = new Socket(Server_name, PORT_NO);
if(m_socket == null)
System.out.println("Unable to open the socket");
DataInputStream dis = new DataInputStream(m_socket.getInputStream());
PrintStream ps = new PrintStream(m_socket.getOutputStream());
DataInputStream ds = new DataInputStream(System.in);
while(true)
{
System.out.println("1. Synchronize");
System.out.println("2. Exit");
System.out.println("Enter your choice...");
str = ds.readLine();
ch = Integer.parseInt(str);
switch(ch)
{
case 1:
ps.println("<message action='buttonpress' value='synchronize' />");
System.out.println("avilable data to read is:"+dis.available());
FileOutputStream fos = new FileOutputStream("mukul.db");
byte data[] = new byte[102400]; //100 Kb byte array
dis.read(data);
String str_data = new String(data);
str_data = str_data.trim();
data = str_data.getBytes();
fos.write(data);
fos.close();
break;
here only part of data is read i.e around 10 kb or less.
I am just a beginner to such posts and my code may be cumbersome, so please ignore all the mistakes in posting.
So please kindly tell me how can i receive 1 MB/10 MB of data in this client-server architecture without the loss of data.
What if i use "sendfile(out_fp, in_fp, pos, len)" method in C code instead of "send()". This method sends file handle. So what will be the corresponding function in Java to capture file handle.
Thank you in advance.
You're misusing the send()/recv() functions. send() and recv() are not required to send as much data as you request, due to limits that may be present in the kernel. You have to call send() over and over until all data has been pushed through.
e.g.:
int sent = 0;
int rc;
while ( sent < should_send )
{
rc = send(sock, buffer + sent, should_send - sent, 0);
if ( rc <= 0 ) // Error or hangup
// do some error handling;
sent += rc;
}
Java side,
int lent2 = 0;
int LengthToReceive = 102400;
char[] chTemp = new char[LengthToReceive];
while (true) {
int readlength = bufferedreader.read(chTemp, lent2,LengthToReceive - lent2);
if(readlength==-1){
break;
}
lent2 += readlength;
if (lent2 >= LengthToReceive) {
flag = false;
break;
}
}
m_socket can't possibly be null the line after you call m_socket = new Socket(...). It will either throw an exception or assign a Socket to m_socket, never null. So that test is pointless.
After you call readLine() you must check for a null return value, which means EOS, which means the other end has closed the connection, which means you must exit the reading loop and close the socket.
As it says in the Javadoc, InputStream.available() shouldn't be used for a test for EOS. Its contract is to return the number of bytes that can be read without blocking. That's rarely the same as the length of an incoming file via a socket. You must keep reading the socket until EOS:
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
out.write(buffer, 0, count);
If your sending end doesn't close the socket when it finishes sending the file you will have to have it send the file length ahead of the file, and modify the loop above to read exactly that many bytes.

Categories

Resources