I'm making a simple FTP server in java. I have everything working when I test it locally (running both the server and client on my own machine). When I run the server and client on two different remote machines, however, the client hangs somewhere shortly after it receives the "150 File status okay" message from the server. I can't understand why it works fine in one location but not the other. Here is the relevant code:
Server (sending the file):
FileInputStream input = null;
try {
input = new FileInputStream(filePath);
} catch (FileNotFoundException e) {
out.writeBytes("550 File not found or access denied.\r\n");
}
out.writeBytes("150 File status okay.\r\n");
// TCP CONNECT
DataOutputStream outToClient_d = null;
Socket clientSocket1 = null;
try {
ipAddress = ipAddress.substring(0,
ipAddress.length() - 1);
clientSocket1 = new Socket(ipAddress,
portNumber);
outToClient_d = new DataOutputStream(
clientSocket1.getOutputStream());
}
catch (UnknownHostException e) {
out.writeBytes("425 Can not open data connection.\r\n");
}
byte[] buf = new byte[2048];
int len;
while ((len = input.read(buf)) > 0) {
outToClient_d.write(buf, 0, len);
}
input.close();
out.writeBytes("250 Requested file action completed.\r\n");
clientSocket1.close();
outToClient_d.close();
Client (saving file into /retr_files):
InputStream inFromServer_d = null;
if (welcomeSocket != null) {
if (!welcomeSocket.isClosed()) {
welcomeSocket.close();
}
}
try {
welcomeSocket = new ServerSocket(port);
System.out.print("PORT " + myIP + "," + num1 + "," + num2 + "\r\n");
out.writeBytes("PORT " + myIP + "," + num1 + "," + num2 + "\r\n");
System.out.print(parseReply(getResponse()));
System.out.print("RETR " + pathname + "\r\n");
out.writeBytes("RETR " + pathname + "\r\n");
String reply = parseReply(getResponse());
if (reply.charAt(10) == '1') {
System.out.print(reply);
System.out.print(parseReply(getResponse()));
try {
clientSocket_d = welcomeSocket.accept();
} catch (IOException e) {
System.out
.print("GET failed, FTP-data port not allocated.\r\n");
System.exit(-1);
}
inFromServer_d = clientSocket_d.getInputStream();
// READ
InputStream input = inFromServer_d;
OutputStream output = new FileOutputStream("retr_files/file"
+ retrCnt);
byte[] buf = new byte[2048];
int len;
while ((len = input.read(buf)) > 0) {
output.write(buf, 0, len);
}
input.close();
output.close();
clientSocket_d.close();
} else {
System.out.print(reply);
}
} catch (IOException e) {
System.out.print("GET failed, FTP-data port not allocated.\r\n");
System.exit(-1);
}
Any help is appreciated!
I would guess there is a firewall between the client and server blocking the reverse connection from the server to the client. this problem is the reason that people typically use "passive" transfers instead of "active" transfers these days.
Related
I'm working on a multi-threaded web-server for a school project. I should be able to go into the localhost on my browser and request 3 different files (.htm, .jpeg,.pdf). However, when I do this for a .htm file with the picture also inside of it (2 requests) the .htm file appears in browser but I get many broken pipe socket exceptions for each write I try to do on the picture (Assignment requires to write 1024 bytes at a time). Something is clearly wrong with the way I have implemented this but I am at a loss as to where the connection is being closed when I try to write for the second file?
I tried a few different things to try and fix this including a loop when trying to read the socket input stream but I think that defeats the purpose of the multi-threaded server.
The server:
while(true){
try {
sock = servSock.accept(); // Handles the connection
// Connection received log
System.out.println("Connection received: " + new Date().toString() + " at " + sock.getInetAddress() + sock.getPort());
HTTP pro = new HTTP(sock); // Client handler
pro.run();
ServerThread serverThread = new ServerThread(pro);
// Starts ServerThread
serverThread.start();
} catch (Exception e){
System.out.println(e);
}
}
HTTP:
public void run(){
// Try to open reader
try{
readSock = new BufferedReader(new InputStreamReader(sock.getInputStream()));
} catch (Exception e){
System.out.println(e);
}
// Open output stream
try{
this.out = new DataOutputStream(sock.getOutputStream());
this.printOut = new PrintWriter(sock.getOutputStream());
} catch (Exception e){
System.out.println(e);
}
// Try to read incoming line
try {
this.reqMes = readSock.readLine();
} catch (IOException e) {
e.printStackTrace();
}
StringTokenizer st = new StringTokenizer(reqMes);
// Parse the request message
int count = 0;
while(st.hasMoreTokens()){
String str = st.nextToken();
if (count == 1){
this.fileName = "." + str;
}
count += 1;
}
System.out.println("File name received.");
File file = null;
try {
file = new File(this.fileName);
this.f = new FileInputStream(file); // File input stream
this.fileExists = true;
System.out.println("File " + this.fileName + " exists.");
} catch (FileNotFoundException e) {
System.out.println(e);
this.fileExists = false;
System.out.println("File does not exist.");
}
byte[] buffer = new byte[1024];
// Write status line
if (this.fileExists) {
System.out.println("Trying to write data");
try{
this.out.writeBytes("HTTP/1.0 " + "200 OK " + this.CRLF);
this.out.flush();
this.printOut.println("HTTP/1.0 " + "200 OK " + this.CRLF);
// Write Header
this.out.writeBytes("Content-type: " + getMime(this.fileName) + this.CRLF);
this.printOut.println("Content-type: " + getMime(this.fileName) + this.CRLF);
this.out.flush();
// Read file data
byte[] fileData = new byte[1024];
while (this.f.read(fileData) != -1) {
// Write File data
try{
this.out.write(fileData,0,1024);
this.out.flush(); // Flush output stream
} catch (IOException e) {
System.out.println(e);
}
}
System.out.println("Flushed");
} catch (IOException e) {
e.printStackTrace();
}
}
For one .htm file in the browser, the file and html seem to appear fine. But it looks like it makes a second request for a .jpeg file within the html file and the browser gets stuck loading with java.net.SocketException: Broken pipe (Write failed) when writing the data each time at
this.out.write(fileData,0,1024);
Thank you, any help is appreciated.
After much searching among different problems, I found the answer here.
The problem was with the response headers not being formatted properly which led to the connection ending prematurely. Another empty line ("\r\n") must be sent after the header.
The following code now works (this.CRLF is equal to "\r\n"):
public void run(){
// Try to open reader
try{
readSock = new BufferedReader(new InputStreamReader(sock.getInputStream()));
} catch (Exception e){
System.out.println(e);
}
// Open output stream
try{
this.out = new DataOutputStream(sock.getOutputStream()); // Data output
this.printOut = new PrintWriter(sock.getOutputStream()); // Print output
} catch (Exception e){
System.out.println(e);
}
// Try to read incoming line
try {
this.reqMes = readSock.readLine();
} catch (IOException e) {
e.printStackTrace();
}
StringTokenizer st = new StringTokenizer(reqMes);
// Parse the request message
int count = 0;
while(st.hasMoreTokens()){
String str = st.nextToken();
if (count == 1){
this.fileName = "." + str;
}
count += 1;
}
System.out.println("File name received.");
// Initialize file to be sent
File file = null;
// Try to find file and create input stream
try {
file = new File(this.fileName);
this.f = new FileInputStream(file); // File input stream
this.fileExists = true;
System.out.println("File " + this.fileName + " exists.");
} catch (FileNotFoundException e) {
System.out.println(e);
this.fileExists = false;
System.out.println("File does not exist.");
}
byte[] buffer = new byte[1024];
// Write status line
if (this.fileExists) {
System.out.println("Trying to write data");
try{
this.out.writeBytes("HTTP/1.0 " + "200 OK " + this.CRLF);
this.out.flush();
// Write Header
this.out.writeBytes("Content-type: " + getMime(this.fileName) + this.CRLF);
this.out.flush();
this.out.writeBytes(this.CRLF);
this.out.flush();
// Read file data
byte[] fileData = new byte[1024];
int i;
while ((i = this.f.read(fileData)) > 0) {
// Write File data
try{
this.out.write(fileData,0, i);
} catch (IOException e) {
System.out.println(e);
}
}
this.out.flush(); // Flush output stream
System.out.println("Flushed");
closeSock(); // Closes socket
} catch (IOException e) {
e.printStackTrace();
}
I'm working on some code to interact with a server and send a file in 1000 byte chunks. I want to use setSoTimeout to resend a packet after 5 seconds if I have not received an ACK from the server by then. I have searched for the answer to this but to no avail. Here are some links i checked out and attempted:
What is the functionality of setSoTimeout and how it works?
how to use socket.setSoTimeout()?
setSotimeout on a datagram socket
I am under the impression that when the timer is going you are continuously waiting for the ACK. Is this the case? I am never receiving an ACK from the server, although I was at one point before.
import java.net.*;
import java.io.*;
import java.util.*;
public class FTPClient {
Socket tcpSocket;
DatagramSocket udpSocket;
DataInputStream dataIn;
DataOutputStream dataOut;
BufferedReader br;
String fileName;
int time;
int portNum;
/**
* Constructor to initialize the program
*
* #param serverName server name
* #param server_port server port
* #param file_name name of file to transfer
* #param timeout Time out value (in milli-seconds).
*/
public FTPClient(String server_name, int server_port, String file_name, int timeout) {
System.out.println("Server Name: " + server_name + " Server Port: " + server_port
+ " File Name: " + file_name + " Timeout: " + timeout);
fileName = file_name;
time = timeout;
portNum = server_port;
try {
Socket tcpSocket = new Socket(server_name, server_port);
dataIn = new DataInputStream(tcpSocket.getInputStream());
dataOut = new DataOutputStream(tcpSocket.getOutputStream());
br = new BufferedReader(new InputStreamReader(System.in));
}
catch (Exception ex) {
System.out.println("Exception in FTPClient initialization: " + ex);
}
}
/**
*Send file content as Segments
*
*/
public void send() {
try {
File f = new File(fileName);
if (!f.exists()) {
System.out.println("File does not exist...");
return;
}
System.out.println("Sending filename (" + fileName + ") to server.");
dataOut.writeUTF(fileName);
byte msgFromServer = dataIn.readByte();
if (msgFromServer == 0) {
System.out.println("Server ready to receive file");
}
// Create a UDP socket to send the file to the server
DatagramSocket udpSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("localhost");
FileInputStream fileIn = new FileInputStream(f);
int seqNum = 0;
int i = 0;
Boolean received = false;;
byte[] chunks = new byte[1000];
int rc = fileIn.read(chunks);
while(rc != -1)
{
System.out.println("Iteration #: " + i);
System.out.println(rc);
// rc should contain the number of bytes read in this operation.
//if (rc < 1000) {
//System.out.println("Bytes read less than 1000");
//System.out.println("Sequence Number: " + seqNum);
//System.out.println("Packet too small to send");
//}
System.out.println("Bytes read greater than 1000");
System.out.println("Sequence Number: " + seqNum);
while (received == false) {
System.out.println("You are looping and sending again");
transferPacket(seqNum, IPAddress, chunks);
received = getResponse();
}
rc = fileIn.read(chunks);
if (seqNum == 1) {
seqNum = 0;
}
else {
seqNum = 1;
}
i++;
}
}
catch (Exception e) {
System.out.println("Error: " + e);
}
}
public Boolean getResponse() {
try {
DatagramSocket udpSocket = new DatagramSocket();
System.out.println("You are in getResponse()");
byte[] receiveData = new byte[1000];
udpSocket.setSoTimeout(time); // set timer
while (true) {
try {
System.out.println("You are receiving a packet");
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
udpSocket.receive(receivePacket);
Segment unwrap = new Segment(receivePacket);
int num = unwrap.getSeqNum();
System.out.println("Received ACK with Sequence Number: " + num);
return true;
}
catch (SocketTimeoutException t) {
System.out.println("Timeout: return false to send()");
return false;
}
}
}
catch (Exception e) {
System.out.println("You don't wanna be here");
return false;
}
}
public void transferPacket(int seqNum, InetAddress IPAddress, byte[] chunks) {
try {
DatagramSocket udpSocket = new DatagramSocket();
byte[] sendData = new byte[1000];
Segment s = new Segment(seqNum, chunks);
sendData = s.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, portNum);
udpSocket.send(sendPacket);
System.out.println("Sent Packet with sequence number " + seqNum);
}
catch (Exception e) {
System.out.println("Exception in transferPacket: " + e);
}
}
/**
* A simple test driver
*
*/
public static void main(String[] args) {
String server = "localhost";
String file_name = "";
int server_port = 8888;
int timeout = 5000; // milli-seconds (this value should not be changed)
// check for command line arguments
if (args.length == 3) {
// either provide 3 parameters
server = args[0];
server_port = Integer.parseInt(args[1]);
file_name = args[2];
}
else {
System.out.println("Wrong number of arguments, try again.");
System.out.println("Usage: java FTPClient server port file");
System.exit(0);
}
FTPClient ftp = new FTPClient(server, server_port, file_name, timeout);
System.out.printf("Sending file \'%s\' to server...\n", file_name);
try {
ftp.send();
}
catch (Exception e) {
System.out.println("Exception: " + e);
}
System.out.println("File transfer completed.");
}
}
You need to keep using the same UDP socket for the life of the application, not a new one per packet, and use it for both sending and receiving.
At present you are also leaking UDP sockets like a firehose.
How do I make the files in the server appear in a list and appear a number behind it and press its number and download by inserting its number?
The point is trading files with my self that point I can but listing the files that I have in the directory I cant, I can already download files (thats the main point)
int porto = 21;
String IP = "x.x.x.x";
public Client() {
String destinyfile = "directory";
try {
Socket MyClient = new Socket(IP, porto);
DataInputStream input = new DataInputStream(MyClient.getInputStream());
DataOutputStream output = new DataOutputStream(MyClient.getOutputStream());
System.out.println(input.readUTF());
String arquivo = JOptionPane.showInputDialog("Insert the name of the file");
output.writeUTF(arquivo);
ObjectInputStream in = new ObjectInputStream(MyClient.getInputStream());
String fileName = in.readUTF();
if(fileName != null){
long size = in.readLong();
System.out.println("Processing the file: " + fileName + " - "+ size + " bytes.");
File file = new File(destinyfile);
if(file.exists() == false){
file.mkdir();
}
FileOutputStream fos = new FileOutputStream(caminhoDestino + fileName);
byte[] buf = new byte[4096];
while (true) {
int len = in.read(buf);
if (len == -1)
break;
fos.write(buf, 0, len);
}
fos.flush();
fos.close();
}
System.out.println(input.readUTF());
MyClient.close();
} catch (Exception e) {
Server
int port = 21;
public Servidor() {
try {
ServerSocket ss = new ServerSocket(port);
String caminho = "directory";
while (true) {
System.out.println("Waiting user.");
Socket socket = ss.accept();
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
output.writeUTF("Welcome");
String arq = input.readUTF();
System.out.println("File: " + arq);
File file = new File(caminho + arq);
if(file.exists()){
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("Transfering file: " + file.getName());
out.writeUTF(file.getName());
out.writeLong(file.length());
FileInputStream filein = new FileInputStream(file);
byte[] buf = new byte[4096];
while (true) {
int len = filein.read(buf);
if (len == -1)
break;
out.write(buf, 0, len);
}
out.close();
output.writeUTF("File Sent:");
}else{
output.writeUTF("File doesnt exist!");
}
ss.close();
}
} catch (Exception e) {
If you create a File object for the parent directory of the files you want to list, you can call that object's listFiles() to get an array of File objects in that directory.
E.g.
File parent = new File("/data/folder/");
for (File child : parent.listFiles()) {
System.out.println(child.getName());
}
I am trying to create File Transfer system by using socket. My code used to work properly before I started sending a String fileName from server to Client to have the files in same name. Now, whenever I try to send file, it keeps giving me different error in client and server.
Server side code:
public void soc_server() throws IOException {
long time = System.currentTimeMillis();
long totalSent = 0;
ServerSocket servsock = null;
Socket sock = null;
PrintWriter pw = null;
FileInputStream fileInputStream = null;
try {
servsock = new ServerSocket(55000);
sock = servsock.accept();
System.out.println("Hello Server");
Scanner sc = new Scanner(System.in);
System.out.println("Please enter the file name or file path");
String s = sc.nextLine();
sc.close();
File file = new File(s);
if (file.exists())
System.out.println("File found");
else
System.out.println("File not found");
OutputStream out = sock.getOutputStream();
pw = new PrintWriter(sock.getOutputStream(), true);
pw.print(s);
fileInputStream = new FileInputStream(s);
byte[] buffer = new byte[100 * 1024];
int bytesRead = 0;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
if (bytesRead > 0) {
out.write(buffer, 0, bytesRead);
totalSent += bytesRead;
System.out.println("sent " + (totalSent / 1024) + " KB "
+ ((System.currentTimeMillis() - time) / 1000)
+ " sec");
}
}
} catch (Exception e) {
System.out.println("exception " + e);
} finally {
sock.close();
pw.close();
servsock.close();
fileInputStream.close();
System.out.println("Sent " + (totalSent / 1024) + " kilobytes in "
+ ((System.currentTimeMillis() - time) / 1000) + " seconds");
}
}
Client Side code:
public void soc_client() throws Exception {
long time = System.currentTimeMillis();
long totalRecieved = 0;
Socket sock = null;
InputStream in = null;
BufferedReader br = null;
FileOutputStream fileOutputStream = null;
try {
sock = new Socket("172.16.27.106", 55000);
System.out.println("Hello Client");
in = sock.getInputStream();
br = new BufferedReader(new InputStreamReader(in));
String fileName = br.readLine();
File outputFile = new File(fileName + "");
fileOutputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[100 * 1024];
int bytesRead = 0;
while ((bytesRead = in.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
totalRecieved += bytesRead;
System.out.println("Recieved " + (totalRecieved / 1024)
+ " kilobytes in "
+ ((System.currentTimeMillis() - time) / 1000)
+ " seconds");
}
} catch (Exception e) {
System.out.println("Exception " + e);
} finally {
br.close(); // CLOSING BufferedReader
fileOutputStream.close();
sock.close();
System.out.println("Recieved " + totalRecieved + " bytes in "
+ (System.currentTimeMillis() - time) + "ms.");
}
}
Exceptions:
Client Side:
Exception java.io.FileNotFoundException: Invalid file path
Exception: java.lang.NullPointerException
Exception in thread "main" java.io.FileNotFoundException: Invalid file path
at java.io.FileOutputStream.<init>(Unknown Source)
at java.io.FileOutputStream.<init>(Unknown Source)
at Client.soc_client(Client.java:25)
at Index.main(Index.java:24)
Server Side:
Exception java.net.SocketException: Connection reset
Exception: java.util.NoSuchElementException
Exception java.net.SocketException: Broken pipe
Exception in thread "main" java.net.SocketException: Connection reset
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
at Server.soc_server(Server.java:59)
at Index.main(Index.java:21)
The file I am trying to send is the same directory (Desktop) from which I am compiling the class.
Thank you.
Try to give file name directly in the path at client side.
File outputFile = new File("yourfile.txt");
and then send it to server.
Because of exception FileNotFound at client side , you are closing the the stream at finaly block.
As you are closing the stream of client side, the server side does not recognize the stream from which it is reading hence giving Connection reset exception.
As no stream is there for reading data at server side, you are getting NoSuchElement exception
EDIT
Another thing is, you are not flushing the stream after writing to client,
So do pw.flush(); after pw.print(s) and out.write()
I'm trying to get a live flash that lives on a webserver to talk to a local java server, that will live on the clients PC.
I'm trying to achieve this with a socket connection. (port 6000)
Now, at first flash was able to connect, but it just sends <policy-file-request/>. After this nothing happens.
Now, some people at Kirupa suggested to send an cross-domain-policy xml as soon as any connection is established from the java side. http://www.kirupa.com/forum/showthread.php?t=301625
However, my java server just throws the following:
End Exception: java.net.SocketException: Software caused connection abort: recv failed
I've already spend a great amount of time on this subject, and was wondering if anyone here knows what to do?
I found the anwser, So ill post it here in case someone with a simmilar question finds this post.
The moment Flash connects to a local socket server it will send the following:
<policy-file-request/>
We will have to answer with a policy file and immediatly close the connection.
Java:
import java.net.*;
import java.io.*;
public class NetTest {
public static void main(String[] args) {
ServerSocket serverSocket = null;
/* Open a socket to listen */
try {
serverSocket = new ServerSocket(6000);
} catch (IOException e) {
System.out.println("Could not listen on port: 6000");
System.exit(-1);
}
// Try catch a socket to listen on
Socket clientSocket = null;
try {
System.out.println("Waiting for auth on 6000...");
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.out.println("Accept failed: 6000");
System.exit(-1);
}
// Now a stream has been opened...
InputStream in = null;
OutputStream out = null;
try {
in = clientSocket.getInputStream();
out = clientSocket.getOutputStream();
} catch (IOException e) {
System.out.println("Failed to get streams.");
System.exit(-1);
}
System.out.println("Socket connection incoming!");
// Keep going while we can...
byte b[] = new byte[100];
int offset = 0;
String s;
try {
boolean done = false;
boolean auth = false;
String protocol_target = "<policy-file-request/>";
byte[] p_bytes = protocol_target.getBytes();
int result;
while (!done) {
if (in.read(b, offset, 1) == -1)
done = true;
else {
if (!auth) {
++offset;
b[offset] = 0;
if (offset != p_bytes.length) {
System.out.println("Waiting for protocol data... ("
+ offset + "/" + p_bytes.length + ")");
} else {
// Compare byte data
for (int i = 0; i < p_bytes.length; ++i) {
System.out.print(b[i] + " ");
}
System.out.print("\n");
System.out.flush();
for (int i = 0; i < p_bytes.length; ++i) {
System.out.print(p_bytes[i] + " ");
}
System.out.print("\n");
System.out.flush();
boolean match = true;
for (int i = 0; i < p_bytes.length; ++i) {
if (b[i] != p_bytes[i]) {
match = false;
System.out
.println("Mismatch on " + i + ".");
}
}
if (match)
auth = true;
else {
System.out.println("Bad protocol input.");
System.exit(-1);
}
}
// Auth
if (auth) {
System.out.println("Authing...");
s = "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain='*' to-ports='6000' /></cross-domain-policy>";
b = s.getBytes();
out.write(b, 0, b.length);
b[0] = 0;
out.write(b, 0, 1); // End
out.flush();
offset = 0;
b = new byte[100];
b[0] = 0;
auth = true;
System.out.println("Auth completed.");
}
}
}
}
} catch (IOException e) {
System.out.println("Stream failure: " + e.getMessage());
System.exit(-1);
}
// Finished.
try {
in.close();
out.close();
clientSocket.close();
} catch (Exception e) {
System.out.println("Failed closing auth stream: " + e.getMessage());
System.exit(-1);
}
// Try catch a socket to listen on for data
try {
System.out.println("Waiting on 6000 fo data...");
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.out.println("Accept failed: 6000");
System.exit(-1);
}
// Now a stream has been opened...
in = null;
out = null;
try {
in = clientSocket.getInputStream();
out = clientSocket.getOutputStream();
} catch (IOException e) {
System.out.println("Failed to get streams.");
System.exit(-1);
}
System.out.println("Socket data connection waiting.");
// Echo
try {
boolean done = false;
while (!done) {
if (in.read(b, offset, 1) == -1)
done = true;
else {
b[1] = 0;
s = new String(b);
System.out.print(s);
System.out.flush();
}
}
} catch (IOException e) {
System.out.println("Failed echo stream: " + e.getMessage());
System.exit(-1);
}
// Finished.
try {
in.close();
out.close();
clientSocket.close();
serverSocket.close();
} catch (Exception e) {
System.out.println("Failed closing stream: " + e.getMessage());
System.exit(-1);
}
}
}