File transfer over socket using JAVA - java

I was searching a code in java for sending multiple files over a socket, I found this code which consists of a TX main, a RX main and a class for all the dirty work I assume. Code runs with no errors but I have a questions for the experts,
where exactly in the code, the user types the files that he/she want to send to the server ?
And in the server main, what is the location where the server stores the received file, and with what name ?
Where exactly in this code ( TX / RX / ByteStream), should I amend to specify what file goes in ?
I would like to input the filename myself in the client (TX) side, where futher on I would include a JFileChooser for the user to select Graphically which file to send.
package file_rx;
import java.io.*;
import java.net.*;
public class File_RX implements Runnable
{
private static final int port = 4711;
private Socket socket;
public static void main(String[] _)
{
try
{
ServerSocket listener = new ServerSocket(port);
while (true)
{
File_RX file_rec = new File_RX();
file_rec.socket = listener.accept();
new Thread(file_rec).start();
}
}
catch (java.lang.Exception e)
{
e.printStackTrace(System.out);
}
}
public void run()
{
try
{
InputStream in = socket.getInputStream();
int nof_files = ByteStream.toInt(in);
for (int cur_file = 0; cur_file < nof_files; cur_file++)
{
String file_name = ByteStream.toString(in);
File file = new File(file_name);
ByteStream.toFile(in, file);
}
}
catch (java.lang.Exception e)
{
e.printStackTrace(System.out);
}
}
}
package file_tx;
import java.io.*;
import java.net.*;
public class File_TX
{
private static final int port = 4711;
private static final String host = "localhost";
public static void main(String[] args)
{
try
{
Socket socket = new Socket(host, port);
OutputStream os = socket.getOutputStream();
int cnt_files = args.length;
ByteStream.toStream(os, cnt_files);
for (int cur_file = 0; cur_file < cnt_files; cur_file++)
{
ByteStream.toStream(os, args[cur_file]);
ByteStream.toStream(os, new File(args[cur_file]));
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
package file_rx;
import java.io.*;
public class ByteStream
{
private static byte[] toByteArray(int in_int)
{
byte a[] = new byte[4];
for (int i = 0; i < 4; i++)
{
int b_int = (in_int >> (i*8)) & 255;
byte b = (byte) (b_int);
a[i] = b;
}
return a;
}
private static int toInt(byte[] byte_array_4)
{
int ret = 0;
for (int i = 0; i < 4; i++)
{
int b = (int) byte_array_4[i];
if (i < 3 && b < 0)
{
b = 256 + b;
}
ret += b << (i * 8);
}
return ret;
}
public static int toInt(InputStream in) throws java.io.IOException
{
byte[] byte_array_4 = new byte[4];
byte_array_4[0] = (byte)in.read();
byte_array_4[1] = (byte)in.read();
byte_array_4[2] = (byte)in.read();
byte_array_4[3] = (byte)in.read();
return toInt(byte_array_4);
}
public static String toString(InputStream ins) throws java.io.IOException
{
int len = toInt(ins);
return toString(ins, len);
}
private static String toString(InputStream ins, int len) throws java.io.IOException
{
String ret = new String();
for (int i = 0; i < len; i++)
{
ret += (char) ins.read();
}
return ret;
}
public static void toStream(OutputStream os, int i) throws java.io.IOException
{
byte [] byte_array_4 = toByteArray(i);
os.write(byte_array_4);
}
public static void toStream(OutputStream os, String s) throws java.io.IOException
{
int len_s = s.length();
toStream(os, len_s);
for (int i = 0; i < len_s; i++)
{
os.write((byte) s.charAt(i));
}
os.flush();
}
private static byte[] toByteArray(InputStream ins, int an_int) throws java.io.IOException
{
byte[] ret = new byte[an_int];
int offset = 0;
int numRead = 0;
int outstanding = an_int;
while ((offset < an_int) && (numRead = ins.read(ret, offset, outstanding)) > 0)
{
offset += numRead;
outstanding = an_int - offset;
}
if (offset < ret.length)
{
//throw new Exception("Could not completely read from stream, numRead =" + numRead + ", ret.lenght = " + ret.length);
}
return ret;
}
private static void toFile(InputStream ins, FileOutputStream fos, int len, int buf_size) throws java.io.IOException, java.io.FileNotFoundException
{
byte[] buffer = new byte[buf_size];
int len_read = 0;
int total_len_read = 0;
while (total_len_read + buf_size <= len)
{
len_read = ins.read(buffer);
total_len_read += len_read;
fos.write(buffer, 0, len_read);
}
if (total_len_read < len)
{
toFile(ins, fos, len - total_len_read, buf_size / 2);
}
}
private static void toFile(InputStream ins, File file, int len) throws java.io.IOException, java.io.FileNotFoundException
{
FileOutputStream fos = new FileOutputStream(file);
toFile(ins, fos, len, 1024);
}
public static void toFile (InputStream ins, File file) throws java.io.IOException, java.io.FileNotFoundException
{
int len = toInt(ins);
toFile(ins, file, len);
}
public static void toStream(OutputStream os, File file) throws java.io.IOException, java.io.FileNotFoundException
{
toStream(os, (int) file.length());
byte b[] = new byte[1024];
InputStream is = new FileInputStream(file);
int numRead = 0;
while ((numRead = is.read(b)) > 0)
{
os.write(b, 0, numRead);
}
os.flush();
}
}

The names (and paths) of the files to be transmitted are specified as arguments to the main method in the File_TX class. On the server side (File_RX class), the files will be saved relatively to the current directory of the File_RX.class file, having the same relative path as the input arguments above.

Related

String serialization unit test failed

After running a Junit test for String serialization, it is failed and gave me the following results:
Expected: "netmodel"
Actual: "l"
The serialize method as follows
public static void serializeString(String objectToSerialize, OutputStream outputStream) {
byte[] bytesArr = objectToSerialize.getBytes();
serializeInt(bytesArr.length, outputStream);
try {
outputStream.write(bytesArr);
} catch (IOException e) {
e.printStackTrace();
}
}
And my deserialize method as follows
public static String deserializeString(InputStream inputStream) {
String deserializeObject = "";
char asciiToChar;
int stringByteArrayLength = deserializeInt(inputStream);
byte[] databytesArr = new byte[stringByteArrayLength];
try {
inputStream.read(databytesArr, 0, stringByteArrayLength);
}
catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < databytesArr.length; i++) {
asciiToChar = (char) databytesArr[i];
deserializeObject = "" + Character.toString(asciiToChar);
}
return deserializeObject;
}
Finally, I wrote a unit test as follows
public class StringSerializerTest {
private InputStream iStream;
private ByteArrayOutputStream oStream;
#Before
public void init() {
oStream = new ByteArrayOutputStream();
}
String serialzeAndDeserializeObject(String stringValue) {
OutputStreamUtil.serializeString(stringValue, oStream);
iStream = new ByteArrayInputStream(oStream.toByteArray());
return InputStreamUtil.deserializeString(iStream);
}
#Test
public void equals_equal() {
String stringValue = "netmodel";
String deserializedStringValue = serialzeAndDeserializeObject(stringValue);
assertThat(deserializedStringValue).isEqualTo(stringValue);
}
}
what was wrong? and how to fix it?
You are reassigning the entire value of deserializeObject during each iteration of
for (int i = 0; i < databytesArr.length; i++) {
asciiToChar = (char) databytesArr[i];
deserializeObject = "" + Character.toString(asciiToChar);
}
This results in only the last character (l in this case) being stored in deserializeObject. This loop should append the next character to the deserializeObject as in the following:
for (int i = 0; i < databytesArr.length; i++) {
asciiToChar = (char) databytesArr[i];
deserializeObject += Character.toString(asciiToChar);
}
The corrected deserialization logic would be:
public static String deserializeString(InputStream inputStream) {
String deserializeObject = "";
char asciiToChar;
int stringByteArrayLength = deserializeInt(inputStream);
byte[] databytesArr = new byte[stringByteArrayLength];
try {
inputStream.read(databytesArr, 0, stringByteArrayLength);
}
catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < databytesArr.length; i++) {
asciiToChar = (char) databytesArr[i];
deserializeObject += Character.toString(asciiToChar);
}
return deserializeObject;
}
The error was already reported by Justin Albano.
However take also care of strings with non-ASCII: like special characters.
Something like the following. Also one should close at the end to ensure flushing in case of a buffered stream. And theoretically a read could yield only a non-blocking part of the array. DataOutputStream has nice methods, though you seem to roll your own serialisation.
public static void serializeString(String objectToSerialize, OutputStream outputStream)
throws IOException {
byte[] bytesArr = objectToSerialize.getBytes(StandardCharsets.UTF_8);
serializeInt(bytesArr.length, outputStream);
outputStream.write(bytesArr);
}
public static String deserializeString(InputStream inputStream)
throws IOException {
int stringByteArrayLength = deserializeInt(inputStream);
byte[] databytesArr = new byte[stringByteArrayLength];
readFully(inputStream, databytesArr);
return new String(databytesArr, StandardCharsets.UTF_8);
}
private static void readFully(InputStream inputStream, byte[] bytes) throws IOException {
int i = 0;
while (i < bytes.length) {
int nread = inputStream.read(bytes, i, bytes.length - i);
if (nread <= 0) {
throw new IOException("Premature EOF");
}
i += nread;
}
}
Mind that StandardCharsets is not in Android SDK, only standard Java.

Java BufferedInputStream not reading the file

Need your help guys.The problem I have is in my code.While I am using RandomAccessFile I don't have any problem in writing or reading the file.But if I am trying to use ObjectInputStream with BufferedInputStream the file can't be read fully(only the first Object).
Here is my code of 2 different ways of reading and writing through stream or RandomAccessFile
public static final String FNAME1 = "1.dat";
public static final String FNAME2 = "2.dat";
final static int ID_SIZE = 10;
final static int NAME_SIZE = 20;
final static int GRADE_SIZE = 5;
final static int RECORD_SIZE = (ID_SIZE + NAME_SIZE + GRADE_SIZE) * 2; // *2 because of the UNI-CODE.
private static Scanner s = new Scanner(System.in);
public static void main(String[] args){
int studNum;
System.out.println("Please enter how many students: ");
studNum=s.nextInt();
Student<?>[] a = new Student[studNum];
try{
createArrary(a,studNum);
save(a,FNAME1);
System.out.println("2.dat saved successfully!! \n");
fileCopy(FNAME1,FNAME2);
System.out.println("The Students in file: ");
read(FNAME2);
bubbleSort(FNAME1);
fileCopy(FNAME1,FNAME2);
System.out.println("2.dat after sorting:");
read(FNAME2);
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**Creates array of Students.*/
public static Student<?>[] createArrary(Student<?>[] a,int studNum) {
String input="";
for(int i = 0; i < studNum; i++) {
System.out.println("Student # "+(i+1)+":");
System.out.print("\nPlease enter the student's id: ");
int id = s.nextInt();
System.out.print("\nPlease enter Student's name : ");
s.nextLine();
String name = s.nextLine();
System.out.print("\nPlease enter Student's grade ");
input=s.nextLine();
if(isInteger(input)){
a[i]=new Student<>(id, name,Integer.parseInt(input));
}else{
a[i]=new Student<>(id,name,input);
}
}
return a;
}
/**Check if string has integer num.*/
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch(NumberFormatException e) {
return false;
} catch(NullPointerException e) {
return false;
}
return true;
}
/**Save Student array to the file.*/
public static void save(Student<?>[] a,String fileName) throws FileNotFoundException, IOException {
try (RandomAccessFile f = new RandomAccessFile(fileName, "rw")) {
f.setLength(0);
for (Student<?> p : a) {
writeFixedLengthString(String.valueOf(p.getId()),ID_SIZE,f);
writeFixedLengthString(p.getFullName(),NAME_SIZE,f);
writeFixedLengthString(String.valueOf(p.getGrade()),GRADE_SIZE,f);
}
}
}
public static void save(Student<?>[] a,String fileName) throws FileNotFoundException, IOException {
try(ObjectOutputStream o = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)))){
for(Student<?> p : a){
writeFixedLengthString(String.valueOf(p.getId()),ID_SIZE,o);
writeFixedLengthString(p.getFullName(),NAME_SIZE,o);
writeFixedLengthString(String.valueOf(p.getGrade()),GRADE_SIZE,o);
}
}
}
/**Read Students from file.*/
public static void read(String fileName) throws FileNotFoundException, IOException,NumberFormatException {
try (RandomAccessFile f = new RandomAccessFile(fileName, "r")) {
while (f.getFilePointer() < f.length()) {
int id=Integer.parseInt(readFixedLengthString(ID_SIZE,f));
String name=readFixedLengthString(NAME_SIZE,f);
String grade=readFixedLengthString(GRADE_SIZE,f);
System.out.println(new Student<>(id, name,grade));
}
}
}
public static void read(String fileName) throws FileNotFoundException, IOException,NumberFormatException {
BufferedInputStream f;
try(ObjectInputStream i = new ObjectInputStream(f = new BufferedInputStream(new FileInputStream(fileName)))){
while (f.available() > 0) {
int id=Integer.parseInt((readFixedLengthString(ID_SIZE,i)));
String name=readFixedLengthString(NAME_SIZE,i);
String grade=readFixedLengthString(GRADE_SIZE,i);
System.out.println(new Student<>(id, name,grade));
}
}
}
/** Write fixed number of characters to a DataOutput stream */
public static void writeFixedLengthString(String s, int size,
DataOutput out) throws IOException
{ char[] chars = new char[size];
s.getChars(0, Math.min(s.length(), size), chars, 0);
for (int i = s.length(); i < size; i++)
chars[i] = ' ';
out.writeChars(new String(chars));
}
/** Read fixed number of characters from a DataInput stream */
public static String readFixedLengthString(int size, DataInput in)
throws IOException
{ char[] chars = new char[size];
for (int i = 0; i < size; i++)
chars[i] = in.readChar();
return new String(chars).replaceAll(" ", "");
}
/** Copying source file to destination file */
public static void fileCopy(String fileSource,String fileDest) throws FileNotFoundException,IOException{
try(BufferedInputStream input=new BufferedInputStream(new FileInputStream(fileSource));BufferedOutputStream output =new BufferedOutputStream(new FileOutputStream(fileDest));){
int r;
while ((r = input.read()) != -1)
{ output.write(r);
}
}
}
/** Read Students from file and returns Object */
public static <T> Student<?> readSort(RandomAccessFile f) throws FileNotFoundException, IOException,NumberFormatException {
int id=Integer.parseInt(readFixedLengthString(ID_SIZE,f));
String name=readFixedLengthString(NAME_SIZE,f);
String grade=readFixedLengthString(GRADE_SIZE,f);
return new Student<>(id, name,grade);
}
/** Receive Student Objects and Save them to file */
public static <T> void saveSort(Student<T> stud,RandomAccessFile f) throws FileNotFoundException, IOException {
writeFixedLengthString(String.valueOf(stud.getId()),ID_SIZE,f);
writeFixedLengthString(stud.getFullName(),NAME_SIZE,f);
writeFixedLengthString(String.valueOf(stud.getGrade()),GRADE_SIZE,f);
}
/** Bubble Sort of Student's grades */
#SuppressWarnings("unchecked")
public static <T> void bubbleSort(String file) throws FileNotFoundException, IOException {
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
boolean needNextPass = true;
for (int k = 1; k < raf.length() / RECORD_SIZE && needNextPass; k++) {
needNextPass = false;
for (int i = 0; i < (raf.length() / RECORD_SIZE) - k; i++) {
raf.seek(RECORD_SIZE * i);
long tmpPrev = raf.getFilePointer();
Student<T> prevStud = (Student<T>) readSort(raf);
long tmpNext = raf.getFilePointer();
Student<T> nextStud = (Student<T>) readSort(raf);
if(isInteger((String) prevStud.getGrade())&&isInteger((String) nextStud.getGrade())){
if(Integer.parseInt((String) prevStud.getGrade())>Integer.parseInt((String) nextStud.getGrade())){
Student<T> temp=prevStud;
prevStud = nextStud;
nextStud = temp;
raf.seek(tmpPrev);
saveSort(prevStud, raf);
raf.seek(tmpNext);
saveSort(nextStud, raf);
needNextPass = true;
}
}else if(String.valueOf(prevStud.getGrade())
.compareTo(String.valueOf(nextStud.getGrade())) > 0 &&!isInteger((String) prevStud.getGrade())&&!isInteger((String) nextStud.getGrade())){
Student<T> temp=prevStud;
prevStud = nextStud;
nextStud = temp;
raf.seek(tmpPrev);
saveSort(prevStud, raf);
raf.seek(tmpNext);
saveSort(nextStud, raf);
needNextPass = true;
}else if(isInteger((String) prevStud.getGrade())&&!isInteger((String) nextStud.getGrade())||!isInteger((String) prevStud.getGrade())&&isInteger((String) nextStud.getGrade())&&String.valueOf(prevStud.getGrade())
.compareTo(String.valueOf(nextStud.getGrade())) < 0){
Student<T> temp=prevStud;
prevStud = nextStud;
nextStud = temp;
raf.seek(tmpPrev);
saveSort(prevStud, raf);
raf.seek(tmpNext);
saveSort(nextStud, raf);
needNextPass = true;
}
}
}
}
}
}
ok I understand I can just write like this.
public static void read(String fileName) throws FileNotFoundException, IOException,NumberFormatException {
try(ObjectInputStream i = new ObjectInputStream(new BufferedInputStream(new FileInputStream(fileName)))){
while (i.available()>0) {
int id=Integer.parseInt((readFixedLengthString(ID_SIZE,i)));
String name=readFixedLengthString(NAME_SIZE,i);
String grade=readFixedLengthString(GRADE_SIZE,i);
System.out.println(new Student<>(id, name,grade));
}
}
}
But how I can translate inputstream to RandomAccessFile ?

Special key in Mac OS

I'm writing a Vigenere cipher. It works with normal char, but when I use extra char on Mac keyboard (using option and c, for example) it breaks. Is it because it's outside of char range?
Output using read byte individually
hello testing long output!##)!(!*!(#()asdfasdfljkasdfjË©âå¬ÃËââÃ¥ËÃâçËâËøÅËèâÏåøÃ
Output using read(byte[])
hello testing long output!##)!(!*!(#()asdfasdfljkasdfjᅨルᅡᄅ¬ネニᅢᆬᅡᆲᅢ゚ᅨレ¬ネツ¬ネニᅢᆬᅨルᅢ゚¬ネニᅢ뎨ニ¬ネムᅨニᅢ쟤モᅨニᅢ゚ᅡᄄ¬ネツᅬタᅢᆬᅢ재゚
Code:
import java.io.*;
class VigenereFilterInputStream extends FilterInputStream {
private final byte[] key;
private int index = 0;
VigenereFilterInputStream(InputStream in, byte[] k) {
super(in);
key = k.clone();
}
public int read() throws IOException {
int c = super.read();
if (c == -1)
return -1;
int out = c ^ key[index];
index ++;
index %= key.length;
return out;
}
public int read(byte[] b) throws IOException {
int result = in.read(b);
for(int i = 0; i < b.length; i++) {
b[i] = (byte) (b[i] ^ key[i % key.length]);
}
return result;
}
}
class VigenereFilterOutputStream extends FilterOutputStream {
private final byte[] key;
VigenereFilterOutputStream(OutputStream out, byte[] k) {
super(out);
key = k.clone();
}
public void write(byte[] b) throws IOException {
byte[] out = new byte[b.length];
for(int i = 0; i < b.length; i++) {
out[i] = (byte) (b[i] ^ key[i % key.length]);
}
super.write(out);
}
}
class Vigenere {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
throw new Exception("Missing filename");
}
File f = new File(args[0]);
byte[] text = "hello testing long output!##)!(!*!(#()asdfasdfljkasdfj˙©∆å¬ß˚∂∆å˙ß∆çˆ∑ˆøœˆß¨∂πåøß".getBytes();
byte[] key = "hello".getBytes();
FileOutputStream os = new FileOutputStream(f);
VigenereFilterOutputStream encrypt = new VigenereFilterOutputStream(os, key);
encrypt.write(text);
FileInputStream is = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(is);
VigenereFilterInputStream decrypt = new VigenereFilterInputStream(bis, key);
bis.mark(text.length);
int c;
while((c = decrypt.read()) != -1) {
System.out.print((char) c);
}
System.out.println();
bis.reset();
byte[] b = new byte[text.length];
decrypt.read(b);
for(byte d: b) {
System.out.print((char) d);
}
System.out.println();
}
}

No data found in socket but definitely received a response

I currently am writing a program which communicates to a server hosted on a separate device via TCP packets. Writing to the server works fine, but I never seem to be able to read the response. I am positive there is a response because when sniffing network packets, I see the incoming packet from the device, though the program never detects it.
public class SocketTest
{
private Socket socket;
private int currentSequence = 0;
public static void main(String[] args)
{
new SocketTest();
}
public SocketTest()
{
try
{
System.out.println("Connecting");
socket = new Socket("192.168.1.8", 8000);
System.out.println("Connected!");
System.out.println("Pinging...");
sendPacket(0, 3, null, 0);
System.out.println("Pinged!");
System.out.println("Reading..");
while (socket.isConnected())
{
byte[] res = new byte[84];
socket.getInputStream().read(res);
System.out.println("Read!");
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void sendPacket(int type, int command, int[] args, int length)
{
int t = 0;
currentSequence += 1000;
byte[] resultBuffer = new byte[84];
byte[] payload1 = getBytes(0x12345678);
System.arraycopy(payload1, 0, resultBuffer, t, payload1.length);
t += 4;
byte[] payload2 = getBytes(currentSequence);
System.arraycopy(payload2, 0, resultBuffer, t, payload2.length);
t += 4;
byte[] payload3 = getBytes(type);
System.arraycopy(payload3, 0, resultBuffer, t, payload3.length);
t += 4;
byte[] payload4 = getBytes(command);
System.arraycopy(payload4, 0, resultBuffer, t, payload4.length);
for (int i = 0; i < 16; i++)
{
t += 4;
int arg = 0;
if (args != null)
{
arg = args[i];
}
byte[] payloadArg = getBytes(arg);
System.arraycopy(payloadArg, 0, resultBuffer, t, payloadArg.length);
}
t += 4;
byte[] payload5 = getBytes(length);
System.arraycopy(payload5, 0, resultBuffer, t, payload5.length);
write(resultBuffer, 0, resultBuffer.length);
}
private void write(byte[] buffer, int startOffset, int length)
{
DataOutputStream out;
try
{
out = new DataOutputStream(socket.getOutputStream());
out.write(buffer, startOffset, length);
out.flush();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private byte[] getBytes(int value)
{
ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder());
buffer.putInt(value);
return buffer.array();
}
}
I've tried a bunch of different methods of reading.. Multithreading, heartbeat, etc.. But everytime I use InputStream's read() method, it blocks because there is no data to be read, and the socket is definitely open because the result isn't -1.
This is the actual read method i'm using in my program (The above code is an shortened xample)
private int read(byte[] buffer, int offset, int length)
{
int res = 0;
DataInputStream bis;
try
{
bis = new DataInputStream(socket.getInputStream());
if (bis.available() > 0)
{
System.out.println("Waiting bytes: " + bis.available());
System.out.println("buffer = [" + Arrays.toString(buffer) + "], offset = [" + offset + "], length = [" + length + "]");
res = bis.read(buffer, offset, length);
}
else
{
NTR.getLogger().debug("Available: " + bis.available());
}
}
catch (IOException e)
{
e.printStackTrace();
}
return res;
}
Interestingly, the C# version of the code works just fine.
namespace ntrclient
{
public class NtrClient
{
public delegate void LogHandler(string msg);
private readonly object _syncLock = new object();
private uint _currentSeq;
private int _heartbeatSendable;
public string Host;
private string _lastReadMemFileName;
private uint _lastReadMemSeq;
public NetworkStream NetStream;
public Thread PacketRecvThread;
public int Port;
public volatile int progress = -1;
public TcpClient Tcp;
public event LogHandler OnLogArrival;
private int ReadNetworkStream(Stream stream, byte [] buf, int length)
{
var index = 0;
var useProgress = length > 100000;
do
{
if (useProgress)
{
progress = (int) ((double) index / length * 100);
}
var len = stream.Read(buf, index, length - index);
if (len == 0)
{
Console.WriteLine("No data to be read");
return 0;
}
Console.WriteLine("Read " + len + " datas");
index += len;
} while (index < length);
progress = -1;
Console.WriteLine("Length: " + length + ", Buffer: " + buf);
return length;
}
private void PacketRecvThreadStart()
{
var buf = new byte [84];
var args = new uint [16];
var stream = NetStream;
while (true)
{
try
{
var ret = ReadNetworkStream(stream, buf, buf.Length);
if (ret == 0)
{
break;
}
var t = 0;
var magic = BitConverter.ToUInt32(buf, t);
t += 4;
var seq = BitConverter.ToUInt32(buf, t);
t += 4;
var type = BitConverter.ToUInt32(buf, t);
t += 4;
var cmd = BitConverter.ToUInt32(buf, t);
for (var i = 0; i < args.Length; i++)
{
t += 4;
args [i] = BitConverter.ToUInt32(buf, t);
}
t += 4;
var dataLen = BitConverter.ToUInt32(buf, t);
if (cmd != 0)
{
Log($"packet: cmd = {cmd}, dataLen = {dataLen}");
}
if (magic != 0x12345678)
{
Log($"broken protocol: magic = {magic}, seq = {seq}");
break;
}
if (cmd == 0)
{
if (dataLen != 0)
{
var dataBuf = new byte [dataLen];
ReadNetworkStream(stream, dataBuf, dataBuf.Length);
var logMsg = Encoding.UTF8.GetString(dataBuf);
Log(logMsg);
}
lock (_syncLock)
{
_heartbeatSendable = 1;
}
continue;
}
if (dataLen != 0)
{
var dataBuf = new byte [dataLen];
ReadNetworkStream(stream, dataBuf, dataBuf.Length);
HandlePacket(cmd, seq, dataBuf);
}
}
catch (Exception e)
{
Log(e.Message);
break;
}
}
Log("Server disconnected.");
Disconnect(false);
}
public void ConnectToServer()
{
if (Tcp != null)
{
Disconnect();
Log("Disconnected from previous server, connecting to new one");
}
new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
Tcp = new TcpClient { NoDelay = true };
Tcp.Connect(Host, Port);
_currentSeq = 0;
NetStream = Tcp.GetStream();
_heartbeatSendable = 1;
PacketRecvThread = new Thread(PacketRecvThreadStart);
PacketRecvThread.Start();
Program.getMain().Connected = true;
Log("Server connected.");
}).Start();
}
public void Disconnect(bool waitPacketThread = true)
{
try
{
Tcp?.Close();
if (waitPacketThread)
{
PacketRecvThread?.Join();
}
// Not connected anymore
Program.getMain().Connected = false;
Log("Server disconnected.");
}
catch (Exception ex)
{
Log(ex.Message);
}
Tcp = null;
}
public void SendPacket(uint type, uint cmd, uint [] args, uint dataLen)
{
var t = 0;
_currentSeq += 1000;
var buf = new byte [84];
BitConverter.GetBytes(0x12345678).CopyTo(buf, t);
t += 4;
BitConverter.GetBytes(_currentSeq).CopyTo(buf, t);
t += 4;
BitConverter.GetBytes(type).CopyTo(buf, t);
t += 4;
BitConverter.GetBytes(cmd).CopyTo(buf, t);
for (var i = 0; i < 16; i++)
{
t += 4;
uint arg = 0;
if (args != null)
{
arg = args [i];
}
BitConverter.GetBytes(arg).CopyTo(buf, t);
}
t += 4;
BitConverter.GetBytes(dataLen).CopyTo(buf, t);
NetStream.Write(buf, 0, buf.Length);
}
public void SendHeartbeatPacket()
{
if (Tcp == null)
return;
lock (_syncLock)
{
if (_heartbeatSendable != 1)
return;
_heartbeatSendable = 0;
SendPacket(0, 0, null, 0);
}
}
}
}
I'm honestly stumped. I noticed that C#'s NetworkStream read and write methods are different from java, but I don't exactly know how different they are, or if it makes any difference.
Thanks in advance!

Reading files bits and saving them

i have file reader which read entire file and write it's bits.
I have this class which help reading:
import java.io.*;
public class FileReader extends ByteArrayInputStream{
private int bitsRead;
private int bitPosition;
private int currentByte;
private int myMark;
private final static int NUM_BITS_IN_BYTE = 8;
private final static int END_POSITION = -1;
private boolean readingStarted;
/**
* Create a BitInputStream for a File on disk.
*/
public FileReader( byte[] buf ) throws IOException {
super( buf );
myMark = 0;
bitsRead = 0;
bitPosition = NUM_BITS_IN_BYTE-1;
currentByte = 0;
readingStarted = false;
}
/**
* Read a binary "1" or "0" from the File.
*/
public int readBit() throws IOException {
int theBit = -1;
if( bitPosition == END_POSITION || !readingStarted ) {
currentByte = super.read();
bitPosition = NUM_BITS_IN_BYTE-1;
readingStarted = true;
}
theBit = (0x01 << bitPosition) & currentByte;
bitPosition--;
if( theBit > 0 ) {
theBit = 1;
}
return( theBit );
}
/**
* Return the next byte in the File as lowest 8 bits of int.
*/
public int read() {
currentByte = super.read();
bitPosition = END_POSITION;
readingStarted = true;
return( currentByte );
}
/**
*
*/
public void mark( int readAheadLimit ) {
super.mark(readAheadLimit);
myMark = bitPosition;
}
/**
* Add needed functionality to super's reset() method. Reset to
* the last valid position marked in the input stream.
*/
public void reset() {
super.pos = super.mark-1;
currentByte = super.read();
bitPosition = myMark;
}
/**
* Returns the number of bits still available to be read.
*/
public int availableBits() throws IOException {
return( ((super.available() * 8) + (bitPosition + 1)) );
}
}
In class where i call this, i do:
FileInputStream inputStream = new FileInputStream(file);
byte[] fileBits = new byte[inputStream.available()];
inputStream.read(fileBits, 0, inputStream.available());
inputStream.close();
FileReader bitIn = new FileReader(fileBits);
and this work correctly.
However i have problems with big files above 100 mb because byte[] have the end.
So i want to read bigger files. Maybe some could suggest how i can improve this code ?
Thanks.
If scaling to large file sizes is important, you'd be better off not reading the entire file into memory. The downside is that handling the IOException in more locations can be a little messy. Also, it doesn't look like your application needs something that implements the InputStream API, it just needs the readBit() method. So, you can safely encapsulate, rather than extend, the InputStream.
class FileReader {
private final InputStream src;
private final byte[] bits = new byte[8192];
private int len;
private int pos;
FileReader(InputStream src) {
this.src = src;
}
int readBit() throws IOException {
int idx = pos / 8;
if (idx >= len) {
int n = src.read(bits);
if (n < 0)
return -1;
len = n;
pos = 0;
idx = 0;
}
return ((bits[idx] & (1 << (pos++ % 8))) == 0) ? 0 : 1;
}
}
Usage would look similar.
FileInputStream src = new FileInputStream(file);
try {
FileReader bitIn = new FileReader(src);
...
} finally {
src.close();
}
If you really do want to read in the entire file, and you are working with an actual file, you can query the length of the file first.
File file = new File(path);
if (file.length() > Integer.MAX_VALUE)
throw new IllegalArgumentException("File is too large: " + file.length());
int len = (int) file.length();
FileInputStream inputStream = new FileInputStream(file);
try {
byte[] fileBits = new byte[len];
for (int pos = 0; pos < len; ) {
int n = inputStream.read(fileBits, pos, len - pos);
if (n < 0)
throw new EOFException();
pos += n;
}
/* Use bits. */
...
} finally {
inputStream.close();
}
org.apache.commons.io.IOUtils.copy(InputStream in, OutputStream out)

Categories