For one of my projects, I'm wanting to compress a data stream and transmit over a socket. What I've done so far is
echoSocket = new Socket(SERVER_HOST_NAME, PORT);
consoleIn = System.in;
clientIn = echoSocket.getInputStream();
clientInputUnzipper = new InflaterInputStream(clientIn);
clientOut = echoSocket.getOutputStream();
clientOutputZipper = new DeflaterOutputStream(clientOut);
int r = 0, rc = 0;
System.out.println("Connection achieved to HostName : " + SERVER_HOST_NAME + " on port " + PORT);
while((r = consoleIn.read()) != END_OF_STREAM)
clientOutputZipper.write(r)
On my client side. And it seems to be sending the first byte fine (I troubleshooted the client side to confirm this). But my reader on my server side seems to be unable to read.
serverInputStream = clientSocket.getInputStream();
serverInputUnzipper = new InflaterInputStream(serverInputStream);
serverOutputStream = clientSocket.getOutputStream();
serverOutputZipper = new DeflaterOutputStream(serverOutputStream); //used to send the data back to the client
fileOutput = new FileOutputStream(log);
fileFilterOutput = new FilterOutputStream(fileOutput);
int r = 0, c = 0;
while((r = serverInputUnzipper.read()) != END_OF_STREAM) //getting stuck on this line (waiting for input)
Given that I've sent through the first byte, shouldn't the serverInputStream receive it? However, given it's stalled, I'd assume that it's waiting to read some data (the serverInputUnzipper.read() function). Why didn't it receive the data byte as intended?
Thanks in advance (I've spent a good portion of today trying to fix this presumably simple bug)
Related
I am currently implementing a game server manager for the RCON server protocol. I'm opening a connection to the server via a socket:
this.socket = new Socket();
this.socket.connect(new InetSocketAddress(this.getAddress(), this.getPort()), 3000);
The connection works fine, I can communicate with the server and receive the responses. No problem there. My problem is that when I am debugging the communication process and i take to long getting from the request to the read on the input stream, I am getting a message "Keep Alive". This is the code for request and response:
send:
Rcon rcon = new Rcon();
byte[] data = rcon.constructPackage(this.getPort(), pRequestType, pPayload);
OutputStream out = this.socket.getOutputStream();
out.write(data);
out.flush();
receive:
InputStream in = this.socket.getInputStream();
byte[] header = new byte[3*4];
in.read(header);
ByteBuffer buffer = ByteBuffer.wrap(header);
buffer.order(ByteOrder.LITTLE_ENDIAN);
int length = buffer.getInt();
int id = buffer.getInt();
int type = buffer.getInt();
int payloadLength = length - (2*4) - 2;
byte[] payload = new byte[payloadLength];
DataInputStream dis = new DataInputStream(in);
dis.readFully(payload);
dis.read(new byte[2]);
payloadString = new String(payload);
I have searched for this as Java and RCON related but I did not find a single clue where this is coming from. I'm guessing this is an RCON related effect, since I have to interpret the package which is received from the RCON server and split its contents to get to the actual payload. After this is done, the payload string contains "Keep Alive".
Despite hours of researching this problem, I have made very little progress. According to my professor, the code should be working as written...
I have a server that stays open, and a client that requests a file. Once the client receives the file, the client closes.
When I open the server, I am able to transfer a complete .jpg image file. The client then closes while the server remains open. I start up another client and try to transfer the same image, and only a portion of the bytes are transferred/written to the disk. The file transfer is only completely successful for the first file transferred by the server!
Additionally strange, a simple .txt text file never successfully transfers. I believe the cause is on the server side because it remains open as opposed to the client, which starts over each time.
Server Code:
import java.io.*;
import java.net.*;
import java.util.Arrays;
class ft_server {
public static void main(String args[]) throws Exception {
/*
* Asks user for port number and listens on that port
*/
BufferedReader portFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the port you'd like to use: ");
int portNumber = Integer.valueOf(portFromUser.readLine());
if (portNumber < 1 || portNumber > 65535) {
System.out.println("Please choose a port number between 1 and 65535.");
return;
}
portFromUser.close();
ServerSocket listenSocket = new ServerSocket(portNumber);
/*
* Finished with user input
*/
/*
* Continuously listens for clients:
*/
while (true) {
Socket clientSocket = listenSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(clientSocket.getOutputStream());
String clientIP = clientSocket.getRemoteSocketAddress().toString();
System.out.println("The client " + clientIP + " connected!");
String clientMessage = inFromClient.readLine();
System.out.println("The client requested file: " + clientMessage);
// Get file. If doesn't exist, let's client know.
// Otherwise informs client of file size.
File myFile = new File(clientMessage);
if (!myFile.exists()) {
outToClient.writeBytes("File does not exist!\n");
return;
} else {
outToClient.writeBytes(String.valueOf((int)myFile.length()) + "\n");
}
// Create array for storage of file bytes:
byte[] byteArray = new byte[(int)myFile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
// Read file into array:
bis.read(byteArray, 0, byteArray.length);
// Send the file:
outToClient.write(byteArray, 0, byteArray.length);
outToClient.close();
clientSocket.close();
}
}
}
Client Code:
import java.io.*;
import java.net.*;
class ft_client {
public static void main(String args[]) throws Exception {
int byteSize = 2022386;
int bytesRead;
/*
* Asks user for IP and port:
*/
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter an IP address: ");
String ipAddress = inFromUser.readLine();
System.out.println("Enter a port: ");
String port = inFromUser.readLine();
Socket clientSocket;
try {
// Makes socket, port, and calls connect. Assumes it's TCP:
clientSocket = new Socket(ipAddress, Integer.valueOf(port));
} catch (Exception e) {
System.out.println(e.getMessage());
return;
}
// Creates InputStream from server to get file size and other messages:
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Anything written to this will be sent to the server:
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
// Asks for a file name to download from the server:
System.out.println("What file do you want?: ");
String message = inFromUser.readLine();
outToServer.writeBytes(message + "\n");
inFromUser.close();
// Listens for confirmation from server.
// If the file exists, the file size is delivered here:
String response = inFromServer.readLine();
System.out.println("File size: " + response);
if (response.equals("File does not exist!")) {
return;
}
// Receives file from server:
byteSize = (int) Integer.valueOf(response);
byte[] byteArray = new byte[byteSize];
InputStream is = clientSocket.getInputStream(); // calling clientSocket.getInputStream() twice???
FileOutputStream fos = new FileOutputStream(message);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// Continuously writes the file to the disk until complete:
int total = 0;
while ((bytesRead = is.read(byteArray)) != -1) {
bos.write(byteArray, 0, bytesRead);
total += bytesRead;
}
bos.close();
System.out.println("File downloaded (" + total + " bytes read)");
clientSocket.close();
}
}
Are buffered readers interfering with output streams? Is there a better way to transfer files?
It's worth checking, in your server code, what value comes back from the file read() call, so:
int bytesRead = bis.read(byteArray, 0, byteArray.length);
System.out.println("File bytes read: " + bytesRead + " from file size: " + myFile.length());
The read() method is under no obligation to fill the byteArray - only to return something and to tell you how many bytes it read. From the docs, it:
Reads up to len bytes of data from this input stream into an array of
bytes. If len is not zero, the method blocks until some input is
available; otherwise, no bytes are read and 0 is returned.
You need to keep reading in a loop. I'd do this (actually, same as your client!):
int n;
while ((n = bis.read(byteArray, 0, byteArray.length)) != -1) {
// Send the chunk of n bytes
outToClient.write(byteArray, 0, n);
}
bis.close();
outToClient.close();
or something similar. I've closed the file too: it'd close on GC/finalize, but that could be a while, and meanwhile you're holding the file open.
EDIT
The specific problem with your image-read in this case is in your client code. You read the file size near the top of the code:
// Creates InputStream from server to get file size and other messages:
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
and then you access the client again:
InputStream is = clientSocket.getInputStream(); // calling clientSocket.getInputStream() twice???
and as your comment suggests, this is bad! Thank you to #EJP for highlighting this!
This causes a problem of buffer over-ingestion: the BufferedReader consumes more bytes into its belly than you extract from it, so when you visit the clientSocket inputstream the second time, the read-pointer has moved on. You never look again at what the BufferedReader consumed.
As a general rule, once you plug buffering code onto something, you must be careful to read only from that buffer. In this case, it's difficult, because you can't read image (raw binary) data from a Reader, because it will busily interpret the binary values as characters and read them as UTF-8 or something.
Even without buffers, it's a minor sin to mix Readers (text oriented) and binary data (DataStreams) on the same stream. HTTP and email does this, so you are in good company, but they get away with it by being very tightly specified. Problem is, you can easily get snarled with questions of local/default character encoding at each end, whether you're reading Unix "LF" vs Windows "CR/LF" line endings etc.
In this case, try not using BufferedReaders at all, and try using DataInput/Output streams all the way. Try writeUTF(s) and readUTF() for transferring the String data. Ideally, create them like this:
DataInputStream inFromServer = new DataInputStream (new BufferedInputStream(clientSocket.getInputStream()));
so you still get the benefits of buffering.
EDIT 2
So seeing the new client code:
byteSize = (int) Integer.valueOf(response);
byte[] byteArray = new byte[byteSize];
FileOutputStream fos = new FileOutputStream(message);
int readBytes = inFromServer.read(byteArray);
// Continuously writes the file to the disk until complete:
int total = 0;
for (int i=0; i<byteArray.length; i++) {
fos.write(byteArray[i]);
total++;
}
fos.close();
Here, we're assuming that because the byteArray array is set to the right size, that the inFromServer.read(byteArray) will populate it - it won't. It's good to assume that any and all read operations will return you just as much data as the system has to hand: in this case, it's probably going to return as soon as it gets the first packet or two, with an underfilled array. This is same as C and Unix read behaviour too.
Try this - I'm repeatedly reading and writing a 4K buffer, until the byte count is reached (as determined by summing the return values of the reads):
byteSize = (int) Integer.valueOf(response);
byte[] byteArray = new byte[4096];
FileOutputStream fos = new FileOutputStream(message);
int total = 0;
// Continuously writes the file to the disk until complete:
while (total < byteSize && (readBytes = inFromServer.read(byteArray)) != -1) {
fos.write(byteArray, 0, readBytes);
total += readBytes;
}
fos.close();
A variant is this - same thing, but byte at a time. Might be a bit clearer. It's going to be slow - all those reads and writes are hitting the OS, but if you put a BufferedInputStream/BufferedOutputStream around the socket/file streams, it'll iron that out. I've added them:
DataInputStream inFromServer =
new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));
...
byteSize = (int) Integer.valueOf(response);
OutputStream fos = new BufferedOutputStream(FileOutputStream(message));
int total = 0;
int ch;
// Continuously writes the file to the disk until complete:
while (total < byteSize && (ch = inFromServer.read()) != -1) {
fos.write(ch);
total ++;
}
fos.close();
And finally! the simplest answer is this. Your code, but changed to:
int readBytes = inFromServer.readFully(byteArray);
Yes! Those nice people in 1990's Javasoft added a DataInput.readFully method, which does what you want! - basically wraps the code above. It's the simplest solution, and arguably most correct approach: "use existing libraries where possible". OTOH, it's the least educational, and the time you spend getting used to read/writes like this is not deducted from your life-expectancy!
And in fact, the readFully approach has severe limitations. Try pointing it at a 1GB file and see what happens (after you've fixed up the array size at the top): you'll a) run out memory, and b) wish that while you were ingesting a huge blob, you could at least be spooling it out to disk. If you try a 2.5G file, you'll notice that some of those ints should become longs to cope with numbers >= 2^31.
If it was me, I'd do the 4K buffer one. (BTW I'm writing this on a laptop with no Java compiler installed, so I haven't actually run the above! DO respond if there are any difficulties.)
So I was implementing client and socket for java. I wanted to send huge files on tcp through sockets and I was able to send files too but the only problem was the files on the other end were either not complete or not working. I have checked the bits are being transfered then what is the error.
Client side:
Socket sock = new Socket("127.0.0.1", 1056);
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("abc.mp3");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
int len = 0;
while((len = is.read(mybytearray)) != -1)
{
bos.write(mybytearray, 0, len);
System.out.println("sending");
}
bos.close();
sock.close();
Server side:
ServerSocket ss = new ServerSocket(1056);
while (true) {
Socket s = ss.accept();
PrintStream out = new PrintStream(s.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String info = null;
String request = null;
System.out.println("sending");
String filename = "abc.mp3";
File fi = new File(filename);
InputStream fs = new FileInputStream(fi);
int n = fs.available();
byte buf[] = new byte[1024];
out.println("Content_Length:" + n);
out.println("");
while ((n = fs.read(buf)) >= 0) {
out.write(buf, 0, n);
System.out.println("sending");
}
out.close();
s.close();
in.close();
}
When you are connected via TCP you create a network stream which you can read and write in, similar to all other streams you worked with. Writing a large amount of data to the stream is not a good idea, so I suggest you break the selected file into smaller packets in which each packet length is 1024 bytes (1KB) and then send all the packets to the server. The SendTCP function is as follows:(I have used Windows Forms to make things more obvious)
public void SendTCP(string M, string IPA, Int32 PortN)
{
byte[] SendingBuffer = null
TcpClient client = null;
lblStatus.Text = "";
NetworkStream netstream = null;
try
{
client = new TcpClient(IPA, PortN);
lblStatus.Text = "Connected to the Server...\n";
netstream = client.GetStream();
FileStream Fs = new FileStream(M, FileMode.Open, FileAccess.Read);
int NoOfPackets = Convert.ToInt32
(Math.Ceiling(Convert.ToDouble(Fs.Length) / Convert.ToDouble(BufferSize)));
progressBar1.Maximum = NoOfPackets;
int TotalLength = (int)Fs.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++)
{
if (TotalLength > BufferSize)
{
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
Fs.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
if (progressBar1.Value >= progressBar1.Maximum)
progressBar1.Value = progressBar1.Minimum;
progressBar1.PerformStep();
}
lblStatus.Text=lblStatus.Text+"Sent "+Fs.Length.ToString()+"
bytes to the server";
Fs.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
netstream.Close();
client.Close();
}
}
As you can see, a TCP client and a network stream are being constructed and a network connection is initiated. After opening the selected file according to the buffer size which is 1024 bytes, the number of packets that are going to be sent is calculated. There are two other variables CurrentPacketLength and TotalLength. If the total length of the selected file is more than the buffer size the CurrentPacketLength is set to the buffer size, otherwise why send some empty bytes, so CurrentPacketLength is set to the total length of the file. After that, I subtract the current from the total length, so actually we can say total length is showing the total amount of data that has not been sent yet. The rest is pretty much straight forward, reading the data from the file stream and writing it to the SendingBuffer according to the CurrentPacketLength and writing the buffer to the network stream.
At the server side, the application is listening for an incoming connection:
public void ReceiveTCP(int portN)
{
TcpListener Listener = null;
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
byte[] RecData = new byte[BufferSize];
int RecBytes;
for (; ; )
{
TcpClient client = null;
NetworkStream netstream = null;
Status = string.Empty;
try
{
string message = "Accept the Incoming File ";
string caption = "Incoming Connection";
MessageBoxButtons buttons = MessageBoxButtons.YesNo;
DialogResult result;
if (Listener.Pending())
{
client = Listener.AcceptTcpClient();
netstream = client.GetStream();
Status = "Connected to a client\n";
result = MessageBox.Show(message, caption, buttons);
if (result == System.Windows.Forms.DialogResult.Yes)
{
string SaveFileName=string.Empty;
SaveFileDialog DialogSave = new SaveFileDialog();
DialogSave.Filter = "All files (*.*)|*.*";
DialogSave.RestoreDirectory = true;
DialogSave.Title = "Where do you want to save the file?";
DialogSave.InitialDirectory = #"C:/";
if (DialogSave.ShowDialog() == DialogResult.OK)
SaveFileName = DialogSave.FileName;
if (SaveFileName != string.Empty)
{
int totalrecbytes = 0;
FileStream Fs = new FileStream
(SaveFileName, FileMode.OpenOrCreate, FileAccess.Write);
while ((RecBytes = netstream.Read
(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Fs.Close();
}
netstream.Close();
client.Close();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
//netstream.Close();
}
}
}
A TCP listener is created and starts listening to the specified port. Again the buffer size is set to 1024 bytes. A TCP listener can pre check to see if there are any connections pending before calling the AcceptTcpClient method. It returns true if there are any pending connections. This method is a good way of avoiding the socket being blocked. Before reading anything from the network stream, a message box asks you if you want to accept the incoming connection, then a SaveFileDialog will be opened, and when you enter the file name plus extension, a file stream will be constructed and you start reading from the network stream and writing to the file stream. Create a thread in your code and run the receiving method in the created thread. I have sent more than 100 MB files in a LAN with the application.
For more details, check this article.
So, first you do this
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
That reads up to 1024 bytes into mybytearray.
You don't do anything with that and I don't understand why you are doing it. You never write those bytes so they get overwritten if the while loop reads anything.
Just delete that. The while loop should cover all of this.
I was trying to make a small java program which writes a text message from server to client using DatagramServer and DatagramPacket.
This is the code i've written on the server and client portion.
serverm.java
byte b[] = new byte[1200];
System.out.println("Enter some text");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputMessage = br.readLine();
b = inputMessage.getBytes();
DatagramSocket d = new DatagramSocket(6125);
DatagramPacket p = new DatagramPacket(b,i,InetAddress.getLocalHost(),5461);
d.send(p);
clientm.java
byte b[] = new byte[1024];
try
{
DatagramSocket d = new DatagramSocket(5461);
DatagramPacket p = new DatagramPacket(b,1024);
d.receive(p);
String outputMessage = new String(p.getData(),0,p.getLength());
System.out.println(outputMessage);
}
When running the java program, it runs when the server sends a message to the client - the received message only prints empty line. How can i get the string to be displayed ?
I was able to reproduce your problem when I set the 'i' variable in your server to 0.
Make sure that value is the length of the packet you're sending.
Hey everyone, I'm having a bit of a problem with UDP and Datagrams. I'm supposed to make a server that will get a request from the client to send a file in the same directory. The UDP Server will then get this file (a video), put it into a datagram and send it. I think I know how to do it, but I can't put the file in the datagram. I'm putting it in Binary form, so keep that in mind.
Here's my code so far:
edit: This is the server by the way, and I keep having trouble with BufferedInputReader and OutputReader, so keep that in mind :)
Scanner inFromUser = new Scanner(System.in);
int port = 12345;
DatagramSocket server = new DatagramSocket(port);
// Read name of file supplied by client (must be a line of text):
Scanner in = new Scanner(new DataInputStream(server.getInputStream()));
String filename = in.nextLine();
DatagramSocket request = server.accept();
// Create buffer, then we're ready to go:
// Puts file into binary form
BufferedInputStream inbinary =
new BufferedInputStream(new FileInputStream("poop.txt"));
// Outputs the binary form
BufferedOutputStream outbinary =
new BufferedOutputStream(request.getOutputStream());
int numbytes;
int countblocks = 0;
int countbytes = 0;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length, port);
server.receive(packet);
while ((numbytes = inbinary.read(buf,0,1024)) >= 0)
{
// receive packet from client, telling it to send the video file
server.receive(packet);
InetAddress address = packet.getAddress();
packet = new DatagramPacket(buf, buf.length, address, port);
server.send(packet);
countblocks++; // keep statistics on file size
countbytes += numbytes;
outbinary.write(buf,0,numbytes); // write buffer to socket
}
outbinary.flush(); // FLUSH THE BUFFER
server.close(); // done with the socket
System.out.println(countblocks + " were read; " + countbytes + " bytes");
}
}
I haven't done datagrams in a while, but I'm pretty sure the accept() call is wrong. That's for TCP servers.
I'd recommend cribbing from Sun's excellent tutorial: http://java.sun.com/docs/books/tutorial/networking/datagrams/clientServer.html