This is one of the most common application scenario that can be found all over the net. and I'm not asking any questions about the java codes that I did because I was successful in running it on my laptop where both the client and server part of the .java file resides. Rather I have had problem getting it to work in between two computers. I tried establishing physical connection using cross-over cable to connect two computers, and did a test to see if file transfers successfully and it did, however, keeping one Server part of the .java file in one computer and client part in the other, I tried to run the server first and then the client but it got a "access denied" error.
For reference here's my two .java files:
/* ChatClient.java */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class ChatClient {
private static int port = 5000; /* port to connect to */
private static String host = "localhost"; /* host to connect to (server's IP)*/
private static BufferedReader stdIn;
private static String nick;
/**
* Read in a nickname from stdin and attempt to authenticate with the
* server by sending a NICK command to #out. If the response from #in
* is not equal to "OK" go bacl and read a nickname again
*/
private static String getNick(BufferedReader in,
PrintWriter out) throws IOException {
System.out.print("Enter your nick: ");
String msg = stdIn.readLine();
out.println("NICK " + msg);
String serverResponse = in.readLine();
if ("SERVER: OK".equals(serverResponse)) return msg;
System.out.println(serverResponse);
return getNick(in, out);
}
public static void main (String[] args) throws IOException {
Socket server = null;
try {
server = new Socket(host, port);
} catch (UnknownHostException e) {
System.err.println(e);
System.exit(1);
}
stdIn = new BufferedReader(new InputStreamReader(System.in));
/* obtain an output stream to the server... */
PrintWriter out = new PrintWriter(server.getOutputStream(), true);
/* ... and an input stream */
BufferedReader in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
nick = getNick(in, out);
/* create a thread to asyncronously read messages from the server */
ServerConn sc = new ServerConn(server);
Thread t = new Thread(sc);
t.start();
String msg;
/* loop reading messages from stdin and sending them to the server */
while ((msg = stdIn.readLine()) != null) {
out.println(msg);
}
}
}
class ServerConn implements Runnable {
private BufferedReader in = null;
public ServerConn(Socket server) throws IOException {
/* obtain an input stream from the server */
in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
}
public void run() {
String msg;
try {
/* loop reading messages from the server and show them
* on stdout */
while ((msg = in.readLine()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
System.err.println(e);
}
}
}
and here's the ChatServer.java:
/* ChatServer.java */
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Hashtable;
public class ChatServer {
private static int port = 5000; /* port to listen on */
public static void main (String[] args) throws IOException
{
ServerSocket server = null;
try {
server = new ServerSocket(port); /* start listening on the port */
} catch (IOException e) {
System.err.println("Could not listen on port: " + port);
System.err.println(e);
System.exit(1);
}
Socket client = null;
while(true) {
try {
client = server.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.err.println(e);
System.exit(1);
}
/* start a new thread to handle this client */
Thread t = new Thread(new ClientConn(client));
t.start();
}
}
}
class ChatServerProtocol {
private String nick;
private ClientConn conn;
/* a hash table from user nicks to the corresponding connections */
private static Hashtable<String, ClientConn> nicks =
new Hashtable<String, ClientConn>();
private static final String msg_OK = "OK";
private static final String msg_NICK_IN_USE = "NICK IN USE";
private static final String msg_SPECIFY_NICK = "SPECIFY NICK";
private static final String msg_INVALID = "INVALID COMMAND";
private static final String msg_SEND_FAILED = "FAILED TO SEND";
/**
* Adds a nick to the hash table
* returns false if the nick is already in the table, true otherwise
*/
private static boolean add_nick(String nick, ClientConn c) {
if (nicks.containsKey(nick)) {
return false;
} else {
nicks.put(nick, c);
return true;
}
}
public ChatServerProtocol(ClientConn c) {
nick = null;
conn = c;
}
private void log(String msg) {
System.err.println(msg);
}
public boolean isAuthenticated() {
return ! (nick == null);
}
/**
* Implements the authentication protocol.
* This consists of checking that the message starts with the NICK command
* and that the nick following it is not already in use.
* returns:
* msg_OK if authenticated
* msg_NICK_IN_USE if the specified nick is already in use
* msg_SPECIFY_NICK if the message does not start with the NICK command
*/
private String authenticate(String msg) {
if(msg.startsWith("NICK")) {
String tryNick = msg.substring(5);
if(add_nick(tryNick, this.conn)) {
log("Nick " + tryNick + " joined.");
this.nick = tryNick;
return msg_OK;
} else {
return msg_NICK_IN_USE;
}
} else {
return msg_SPECIFY_NICK;
}
}
/**
* Send a message to another user.
* #recepient contains the recepient's nick
* #msg contains the message to send
* return true if the nick is registered in the hash, false otherwise
*/
private boolean sendMsg(String recipient, String msg) {
if (nicks.containsKey(recipient)) {
ClientConn c = nicks.get(recipient);
c.sendMsg(nick + ": " + msg);
return true;
} else {
return false;
}
}
/**
* Process a message coming from the client
*/
public String process(String msg) {
if (!isAuthenticated())
return authenticate(msg);
String[] msg_parts = msg.split(" ", 3);
String msg_type = msg_parts[0];
if(msg_type.equals("MSG")) {
if(msg_parts.length < 3) return msg_INVALID;
if(sendMsg(msg_parts[1], msg_parts[2])) return msg_OK;
else return msg_SEND_FAILED;
} else {
return msg_INVALID;
}
}
}
class ClientConn implements Runnable {
private Socket client;
private BufferedReader in = null;
private PrintWriter out = null;
ClientConn(Socket client) {
this.client = client;
try {
/* obtain an input stream to this client ... */
in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
/* ... and an output stream to the same client */
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.err.println(e);
return;
}
}
public void run() {
String msg, response;
ChatServerProtocol protocol = new ChatServerProtocol(this);
try {
/* loop reading lines from the client which are processed
* according to our protocol and the resulting response is
* sent back to the client */
while ((msg = in.readLine()) != null) {
response = protocol.process(msg);
out.println("SERVER: " + response);
}
} catch (IOException e) {
System.err.println(e);
}
}
public void sendMsg(String msg) {
out.println(msg);
}
}
Now, what should I do in order to run this two files from two computers given that I have the physical connection(TCP/IP) setup already??
Thanks in advance... :)
Sounds like it's quite possibly a firewall problem. Have you tried opening a hole in your firewall for port 1001?
Have you also looked at your java.policy and make sure that it is configured to allow local codebase to open sockets?
as mentioned in comment, you should not use port < 1025 for you applications, since they are always used in deamon processes. However you should test your program like this
1) if you get connection refused then you should check the exception properly, whether client program takes time before generating exception ( that mean request is going to server and then it's giving connection refused), in that case you should try java.policy put following in a file named java.policy
grant {
permission java.net.SocketPermission ":1024-65535",
"connect,accept";
permission java.net.SocketPermission ":80", "connect";
permission java.io.FilePermission "", "read,write,delete";
permission java.security.SecurityPermission "";
};
while compiling use this flag -Djava.security.policy=java.policy
more-over you should also try -Djava.rmi.server.hostname=IP, where IP is clien-ip for client.java and server-ip for server.java
2) if you are immediately getting exception at client side then your request is not going outside your pc, so client has some problem.
check the exception properly and post them over here.
3) though i've not got access denied error, but it seems to have port problem that might be solved using policy or port>1024.
post what are you getting now.
Related
I'm confused as to why I cant seem to get the server to output to the client properly. I'm not the most experienced when it comes to java and have exhausted anything I could think of. The other systems in place seem to work fine(The Add/List commands).
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.tcpechoclient;
import java.io.*;
import java.net.*;
/**
*
* #author Leepe
*/
public class TCPEchoClient {
private static InetAddress host;
private static final int PORT = 1248;
public static void main(String[] args) {
try
{
host = InetAddress.getLocalHost();
}
catch(UnknownHostException e)
{
System.out.println("Host ID not found!");
System.exit(1);
}
run();
}
private static void run() {
Socket link = null; //Step 1.
try
{
link = new Socket(host,PORT); //Step 1.
//link = new Socket( "192.168.0.59", PORT);
BufferedReader in = new BufferedReader(new InputStreamReader(link.getInputStream()));//Step 2.
PrintWriter out = new PrintWriter(link.getOutputStream(),true); //Step 2.
//Set up stream for keyboard entry...
BufferedReader userEntry =new BufferedReader(new InputStreamReader(System.in));
String message = "";
String response = "";
while (!message.equals("Stop")) {
System.out.println("Enter message to be sent to server: ");
message = userEntry.readLine();
out.println(message); //Step 3.
// out.flush();
response = in.readLine(); //Step 3.
System.out.println("\nSERVER RESPONSE> " + response);
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
System.out.println("\n* Closing connection... *");
link.close(); //Step 4.
}catch(IOException e)
{
System.out.println("Unable to disconnect/close!");
System.exit(1);
}
}
} // finish run method
} //finish the class
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.tcpechoserverthreads;
import java.io.*;
import java.net.*;
/**
*
* #author Leepe
*/
public class TCPEchoServer {
private static ServerSocket servSock;
private static final int PORT = 1248;
private static int clientConnections = 0;
public static void main(String[] args) {
System.out.println("Opening port..."+"\n"+"Listening on port: "+PORT);
try
{
servSock = new ServerSocket(PORT); //Step 1.
}
catch(IOException e)
{
System.out.println("Unable to attach to port!");
System.exit(1);
}
do
{
run();
}while (true);
}
synchronized private static void run()
{
Socket link = null; //Step 2.
try
{
link = servSock.accept();
clientConnections++;
String client_ID = clientConnections + "";
Runnable resource = new ClientConnectionRun(link, client_ID);
Thread t = new Thread (resource);
t.start();
}
catch(IOException e1)
{
e1.printStackTrace();
try {
System.out.println("\n* Closing connection... *");
link.close(); //Step 5.
}
catch(IOException e2)
{
System.out.println("Unable to disconnect!");
System.exit(1);
}
}
} // finish run method
} // finish the class
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.tcpechoserverthreads;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.*;
/**
*
* #author Leepe
*/
public class ClientConnectionRun implements Runnable {
Socket client_link = null;
String clientID;
public static List<String> currentList = new ArrayList<String>();
String[] parts;
String part1;
String part2;
String part3;
String message = "";
public ClientConnectionRun(Socket connection, String cID) {
this.client_link = connection;
clientID = cID;
}
#Override
synchronized public void run() {
try{
BufferedReader in = new BufferedReader( new InputStreamReader(client_link.getInputStream())); //Step 3.
PrintWriter out = new PrintWriter(client_link.getOutputStream(),true); //Step 3.
System.out.println("\n* started connection with the client " + clientID + " ... *");
while (!message.equals("Stop")){//Step 4.
message = in.readLine();
// out.flush();
System.out.println("\n Message received from client: " + clientID + " - "+ message);
out.println("\n Echo Message: " + message);
//out.flush();
if(message.contains(";")){
// String userinput = message;
// String item = message;
// System.out.println("Contains ;");
String[] parts = message.split(";");
String part1 = parts[0];
String part2 = parts[1];
System.out.println(part1);
System.out.println(part2);
if(parts.length >= 3 && part1.equals("add")){
String part3 = parts[2];
System.out.println(part1);
System.out.println(part2);
System.out.println(part3);
currentList.add(part2+" - "+part3);
//AddItem();
}
else if(parts.length <= 2 && part1.equals("list") ){
System.out.println("list command working");
//ListItem();
System.out.println();
System.out.println("----------------------");
System.out.println("To-Do List");
System.out.println("----------------------");
int number = 0;
for (Iterator<String> it = currentList.iterator(); it.hasNext();) {
message = it.next();
if(message.contains(part2)){
System.out.println(++number + " " + message);
}
}
System.out.println("----------------------");
}
else {
System.out.println("\n Don't add a description if you are searching for a date");
}
}
else if(!message.contains(";")){
System.out.println("\n Unknown command, Try using 'add' or 'list' followed by a ' ; ' as listed above ");
}
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try {
System.out.println("\n* Closing connection with the client " + clientID + " ... *");
client_link.close(); //Step 5.
}
catch(IOException e)
{
System.out.println("Unable to disconnect!");
}
}
}
}
I want the server to be able to output info to the client that's connected. What's happening is that the server will output the info eventually but requires me to enter several more inputs, i'm not sure how its delayed and any help would be appreciated.
Leaving everything else untouched, simply changing your line out.println("\nEcho Message: " + message); in your Class ClientConnectionRun to out.println("Echo Message: " + message); will fix this.
Essentially, what goes wrong is that your line response = in.readLine(); in the client terminates when it encounters a line-feed. So, if you begin your response with a line-feed, it will terminate instantly and is thus always trailing by one line, which is why you will only see the actual response the next time you enter some input.
From the doc of java.io.BufferedReader.readLine():
Reads a line of text. A line is considered to be terminated by any one
of a line feed ('\n'), a carriage return ('\r'), a carriage return
followed immediately by a line feed, or by reaching the end-of-file
(EOF).
Also, some general input:
You can drastically improve your code by using try-with-resources statements (since Java 8). This way you can avoid the "nasty" nested try-catch-finally constructs to handle your streams. For your Client for example you could simplify do:
try (Socket link = new Socket(host, PORT);
BufferedReader in = new BufferedReader(new InputStreamReader(link.getInputStream()));
PrintWriter out = new PrintWriter(link.getOutputStream(), true);
BufferedReader userEntry = new BufferedReader(new InputStreamReader(System.in))) {
And all you need at the end is this:
} catch (IOException e) {
e.printStackTrace();
}
I wish to get the service name being used in the port. However, I am unable to. What I want to do is to check if a port is used. If it is used, then I want to get the service details on that port. How can I achieve this and what I am doing wrong?
public int checkPort(int port){
try {
InetAddress inetAddress = InetAddress.getLocalHost();
ss = new Socket(inetAddress.getHostAddress(), port);
if(ss.isBound()) {
System.out.println("Port " + port + " is being used by ");
Process p1 = Runtime.getRuntime().exec("grep -w " + port + " /etc/services");
p1.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p1.getInputStream()));
String line = reader.readLine();
while(line != null) {
System.out.println(line);
line = reader.readLine();
}
}
ss.close();
} catch (Exception e) {
System.out.println("Port " +port+ " is not being used");
}
return 0;
}
Results in
Port 139 is being used by
Port 139 is not being used
Well, assuming you are on Windows (it may or may not be different on other operating systems), you may be getting this exception.
Cannot run program "grep": CreateProcess error=2, The system cannot find the file specified
At least, that is what I got. You might be getting a totally different error. The main issue here is that there is one big try catch block with no e.printStackTrace() and it catches every exception. This means that when it goes wrong, there is no way to know why.
Hopefully this will work for you. Ironically you do not need a socket to test for services on a port so this may be an XY problem.
My solution to finding services on a port is the following.
SocketTester.java
package socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeSet;
/**
* An answer for Unable to get service details on port?
*
* #see Unable to get service details on port?
* #version 1.0
* #author Dan
*/
public class SocketTester {
/**
* This method checks whether a port is being used by any services.
* It will output any information to the system console.
*
* #param port The port to be checked for any services
*/
public static void checkPort(int port) {
TreeSet<String> pids = null;
List<Service> services = null;
pids = getPIDs(port);
if(pids != null) {
services = getServices(port, pids);
}
listInformation(port, services);
}
/**
* This method checks whether there are any PIDs on the specified port.
* If there are these are then returned.
*
* #param port The port to check for PIDs
* #return It returns a TreeSet containing any found PIDs on the specified port
*/
private static TreeSet<String> getPIDs(int port) {
TreeSet<String> returnVal = new TreeSet<String>();
ProcessBuilder pidProcessBuilder = new ProcessBuilder("cmd.exe", "/C", "netstat -ano | find \"" + port + "\"");
pidProcessBuilder.redirectErrorStream(true);
Process pidProcess = null;
try {
pidProcess = pidProcessBuilder.start();
} catch (IOException e) {
return null;
}
BufferedReader pidProcessOutputReader = new BufferedReader(new InputStreamReader(pidProcess.getInputStream()));
String outputLine = null;
try {
outputLine = pidProcessOutputReader.readLine();
} catch (IOException e) {
return null;
}
while (outputLine != null) {
List<String> outputLineParts = new ArrayList<String>(Arrays.asList(outputLine.split(" ")));
outputLineParts.removeAll(Arrays.asList(""));
//outputLineParts.get(1) is the local address. We don't want a foreign address to accidently be found
//outputLineParts.size() - 1 is the PID
if(outputLineParts.get(1).contains(":" + port) && !returnVal.contains(outputLineParts.get(outputLineParts.size() - 1))) {
returnVal.add(outputLineParts.get(outputLineParts.size() - 1));
}
try {
outputLine = pidProcessOutputReader.readLine();
} catch (IOException e) {
return null;
}
}
try {
pidProcess.waitFor();
} catch (InterruptedException e) {
return null;
}
return returnVal;
}
/**
* This method checks whether there are any services related to the PID.
* If there are these are then returned.
*
* #param port A reference to the PIDs port
* #param pids A list of PIDs found by getPIDs
* #return It returns a List containing any found services on the specified PIDs
*/
private static List<Service> getServices(int port, TreeSet<String> pids) {
List<Service> returnVal = new ArrayList<Service>();
for(String pid : pids) {
ProcessBuilder serviceProcessBuilder = new ProcessBuilder("cmd.exe", "/C", "tasklist /svc /FI \"PID eq " + pid + "\" | find \"" + pid + "\"");
serviceProcessBuilder.redirectErrorStream(true);
Process serviceProcess = null;
try {
serviceProcess = serviceProcessBuilder.start();
} catch (IOException e) {
return null;
}
BufferedReader serviceProcessOutputReader = new BufferedReader(new InputStreamReader(serviceProcess.getInputStream()));
String outputLine = null;
try {
outputLine = serviceProcessOutputReader.readLine();
} catch (IOException e) {
return null;
}
while(outputLine != null) {
List<String> outputLineParts = new ArrayList<String>(Arrays.asList(outputLine.split(" ")));
outputLineParts.removeAll(Arrays.asList(""));
//outputLineParts.get(0) is the service
returnVal.add(new Service(port, pid, outputLineParts.get(0)));
try {
outputLine = serviceProcessOutputReader.readLine();
} catch (IOException e) {
return null;
}
}
try {
serviceProcess.waitFor();
} catch (InterruptedException e) {
return null;
}
}
return returnVal;
}
/**
* This method lists the information found by checkPort
*
* #param port The port that has been checked for services
* #param servicesRunning The services found on the port
*/
private static void listInformation(int port, List<Service> servicesRunning) {
if(servicesRunning != null && servicesRunning.size() != 0) {
System.out.println("The following services are being run on port " + port);
for(Service service : servicesRunning) {
System.out.println("\t" + service.getService());
}
} else {
System.out.println("There are no services being run on port " + port);
}
}
public static void main(String[] args) {
final int portToCheck = 135;
checkPort(portToCheck);
}
}
Sevice.java
package socket;
/**
* An supplementary class to support SocketTester
*
* #see Unable to get service details on port?
* #version 1.0
* #author Dan
*/
public class Service {
private int port;
private String pid;
private String service;
public Service(int port, String pid, String service) {
this.port = port;
this.pid = pid;
this.service = service;
}
public int getPort() {
return port;
}
public String getPID() {
return pid;
}
public String getService() {
return service;
}
#Override
public String toString() {
return "Service \"" + "\" is being run on port " + port + " and has the PID " + pid;
}
}
Im working on a simple ftp server, and the client must send multiples messages to the server, and for each message the server send back to the client a anwser. when the client sends one message it works perfectly and the server responds without any problem, for example, when the client sends "USER username" the server send back to the client "password needed".
But when the client sends another message "PASS password" (using the same socket) it doesnt work ! ONLY the first exchange works (for the username), when the first message is sent, the server anwser without any problem, but it block when it want to send the second message (for the password).
please anyone can help me ? thank you !!
here is my code :
#Test
public void testProcessPASS() throws IOException{
Socket socket = new Socket(server.getAddress(), server.getcmdPort());
this.ClientReceiveMessage(socket); // to flush
String cmd = "USER user_test\r\n";
this.ClientSendMessage(socket, cmd);
String anwser = this.ClientReceiveMessage(socket);
assertEquals("Response error.", Constants.MSG_331.replace("\r\n", ""), anwser);
//PROBLEME STARTS HERE :/
String cmd2 = "PASS pass_test\r\n";
this.ClientSendMessage(socket, cmd2);
String anwser2 = this.ClientReceiveMessage(socket);
assertEquals(Constants.MSG_230.replace("\r\n", ""), anwser2);
socket.close();
}
public void ClientSendMessage(Socket skt, String msg) throws IOException{
PrintWriter messageClient = new PrintWriter(new OutputStreamWriter(skt.getOutputStream()),true);
messageClient.println(msg);
messageClient.flush();
}
public String ClientReceiveMessage(Socket skt) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String res = br.readLine() ;
return res;
}
this is the server code :
public class Server implements Runnable {
private ServerSocket cmdserverSocket;
private ServerSocket dataServerSocket;
private boolean running;
public Server() throws IOException {
this.cmdserverSocket = new ServerSocket(1024);
this.dataServerSocket = new ServerSocket(1025);
this.running = false;
}
public boolean isRunning() {
return this.running;
}
public InetAddress getAddress() {
return this.cmdserverSocket.getInetAddress();
}
public int getcmdPort() {
return this.cmdserverSocket.getLocalPort();
}
public int getDataPort() {
return this.dataServerSocket.getLocalPort();
}
public void run() {
// TODO Auto-generated method stub
this.running = true;
System.out.println("server started on port : " + this.getcmdPort());
while (this.running) {
try {
Socket socket = this.cmdserverSocket.accept();
new Thread(new FtpRequest(socket, this.dataServerSocket))
.start();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("server error : " + e.getMessage());
this.running = false;
}
}
}
}
and this is the class that handles client requests and that sends messages to client and running on a new thread :
public class FtpRequest implements Runnable {
private Socket cmdSocket;
private Socket dataSocket;
private BufferedReader cmdBufferedReader;
private DataOutputStream cmdDataOutputStream;
private ServerSocket dataServerSocket;
private boolean anonymous;
private boolean connected;
private String username;
private boolean processRunning;
private String directory;
public FtpRequest(Socket cmds, ServerSocket dts) throws IOException {
this.cmdSocket = cmds;
this.dataServerSocket = dts;
this.cmdBufferedReader = new BufferedReader(new InputStreamReader(
this.cmdSocket.getInputStream()));
this.cmdDataOutputStream = new DataOutputStream(
this.cmdSocket.getOutputStream());
this.anonymous = true;
this.connected = false;
this.username = Constants.ANONYMOUS_USER;
this.processRunning = true;
this.directory = "/home";
}
/**
* send a message on the socket of commands
*
* #param msg
* the msg to send on the socket of commands
* #throws IOException
*/
public void sendMessage(String msg) throws IOException {
System.out.println("FtpRequest sendMessage : " + msg);
PrintWriter messageClient = new PrintWriter(new OutputStreamWriter(
this.cmdDataOutputStream), true);
messageClient.println(msg);
messageClient.flush();
/*
* this.cmdDataOutputStream.writeBytes(msg);
* this.cmdDataOutputStream.flush(); this.cmdSocket.close();
*/
}
public void run() {
// TODO Auto-generated method stub
System.out.println("FtpRequest running ...");
try {
this.sendMessage(Constants.MSG_220); // service ready for new user
this.handleRequest();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // service ready for new user
}
/**
* this method handle the request readen from cmd socket and run the
* required method
*
* #throws IOException
*/
private void handleRequest() throws IOException {
String rqst = this.cmdBufferedReader.readLine();
Request request = new Request(rqst);
System.out.println("FtpRequest handleRequest" + rqst);
switch (request.getType()) {
case USER:
this.processUSER(request);
break;
case PASS:
this.processPASS(request);
break;
default:
this.sendMessage(Constants.MSG_502); // Command not implemented.\r\n
break;
}
/*
* if (this.processRunning = true) this.handleRequest();
*
* else { this.cmdSocket.close(); System.out.println("socket closed ");
* }
*/
}
private void processUSER(Request rqst) throws IOException {
System.out.println("FtpRequest processUSER");
if (rqst.getArgument().equals(Constants.ANONYMOUS_USER)) {
this.sendMessage(Constants.MSG_230); // user loged in
this.connected = true;
this.anonymous = true;
this.username = Constants.ANONYMOUS_USER;
} else if (rqst.getArgument().equals(Constants.USER_TEST)) {
this.sendMessage(Constants.MSG_331); // User name okay, need
// password.\r\n
this.username = Constants.USER_TEST;
} else
this.sendMessage(Constants.MSG_332);
}
private void processPASS(Request rqst) throws IOException {
System.out.println("FtpRequest processPASS");
if (rqst.getArgument().equals(Constants.USER_TEST)
&& rqst.getArgument().equals(Constants.PASS_TEST)) {
this.sendMessage(Constants.MSG_230);
this.connected = true;
this.anonymous = false;
} else
this.sendMessage(Constants.MSG_332); // au cas seulement le mot de
// passe est fourni
}
}
There are some problems with your code.
ClientSendMessage() is using PrintWriter.println(), which outputs a line break. But your input strings already have line breaks on them, so the println() is sending extra line breaks. Also, the line break println() outputs is platform-dependent, whereas FTP uses CRLF specifically. So you should not be using println() at all.
ClientReceiveMessage() does not account for multi-line responses. Per RFC 959, section 4.2 "FTP REPLIES":
A reply is defined to contain the 3-digit code, followed by Space
<SP>, followed by one line of text (where some maximum line length
has been specified), and terminated by the Telnet end-of-line
code. There will be cases however, where the text is longer than
a single line. In these cases the complete text must be bracketed
so the User-process knows when it may stop reading the reply (i.e.
stop processing input on the control connection) and go do other
things. This requires a special format on the first line to
indicate that more than one line is coming, and another on the
last line to designate it as the last. At least one of these must
contain the appropriate reply code to indicate the state of the
transaction. To satisfy all factions, it was decided that both
the first and last line codes should be the same.
Thus the format for multi-line replies is that the first line
will begin with the exact required reply code, followed
immediately by a Hyphen, "-" (also known as Minus), followed by
text. The last line will begin with the same code, followed
immediately by Space <SP>, optionally some text, and the Telnet
end-of-line code.
For example:
123-First line
Second line
234 A line beginning with numbers
123 The last line
The user-process then simply needs to search for the second
occurrence of the same reply code, followed by <SP> (Space), at
the beginning of a line, and ignore all intermediary lines. If
an intermediary line begins with a 3-digit number, the Server
must pad the front to avoid confusion.
The server's initial greeting is likely to be multi-line, but any response to any command can potentially be multi-line, so you need to handle that.
But more importantly, when doing error checking, you need to look at only the 3-digit response code, not the text that accompanies it. Except for a few select commands, like PASV, MLST/MLSD, etc, the text is otherwise arbitrary, the server can send whatever it wants. So you need to ignore the text except for those cases where it is actually needed, or when reporting error messages to the user.
Try something more like this:
private Socket socket;
private BufferedReader br;
#Test
public void testProcessPASS() throws IOException{
socket = new Socket(server.getAddress(), server.getcmdPort());
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.ClientReceiveMessage(220);
this.ClientSendMessage("USER user_test", 331);
this.ClientSendMessage("PASS pass_test", 230);
this.ClientSendMessage("QUIT", 221);
socket.close();
br = null;
socket = null;
}
public int ClientSendMessage(String msg, int ExpectedReplyCode) throws IOException{
Writer bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(msg);
bw.write("\r\n");
bw.flush();
return ClientReceiveMessage(ExpectedReplyCode);
}
public int ClientReceiveMessage(int ExpectedReplyCode) throws IOException{
String line = br.readLine();
String msgText = msgText.substring(4);
if ((line.length() >= 4) && (line[3] == '-')) {
String endStr = line.substring(0, 2) + " ";
do {
line = br.readLine();
msgText += ("\r\n" + line.substring(4));
}
while (line.substring(0, 3) != endStr);
}
int actualReplyCode = Integer.parseInt(line.substring(0, 2));
assertEquals("Response error. " + msgText, ExpectedReplyCode, actualReplyCode);
// TODO: if the caller wants the msgText for any reason,
// figure out a way to pass it back here...
return actualReplyCode;
}
I am implementing a Java Client-Server application for a university task and I'm stuck at the following point: I am obliged to use client-server and also update the view whenever the data in the database changes. What I have done is that whenever a change in the database should occur I notify all the clients with the "CHANGE IN DATA" message and then the client should read and understand this message in order to call a method that will update it's graphic interface. However, or I'm mistaking the reading part on client side or because of some error, the clients don't read the "CHANGE IN DATA" message so the whole gets stuck at this point and the view doesn't update.
Here are some relevant codes!
Server class:
public class FinesPaymentServer implements Runnable {
private Database database;
private UserGateway userGateway;
private FineGateway fineGateway;
private DriverGateway driverGateway;
private Socket connection;
private int ID;
static ArrayList<Socket> clientsConnected;
/**
* Constructor of the class connecting to the database and initializing the socket
* #param database the database used
* #param connection the socket for the server
* #param ID the id
*/
private FinesPaymentServer(Database database, UserGateway userGateway, FineGateway fineGateway, DriverGateway driverGateway, Socket connection, int ID) {
this.connection = connection;
this.userGateway = userGateway;
this.fineGateway = fineGateway;
this.driverGateway = driverGateway;
this.database = database;
this.ID = ID;
}
/**
* Run method of the threads for each socket on the server
*/
public void run() {
try {
while(true)
readFromClient(connection);
} catch (IOException | SQLException e) {
System.out.println(e);
}
}
/**
* Read method from the client
* #param client the client socket from where to read
* #throws IOException
* #throws SQLException
*/
public void readFromClient(Socket client) throws IOException, SQLException {
BufferedInputStream is = new BufferedInputStream(client.getInputStream());
InputStreamReader reader = new InputStreamReader(is);
StringBuffer process = new StringBuffer();
int character;
while((character = reader.read()) != 13) {
process.append((char)character);
}
System.out.println("[SERVER READ]: "+process);
String[] words = process.toString().split("\\s+");
switch (process.charAt(0)) {
case 'a' :
{
int type = database.verifyLogin(words[1], words[2]);
sendMessage(client, ""+type + " ");
break;
}
case 'b' :
{
String rs = userGateway.getUsers();
sendMessage(client, rs);
break;
}
case 'c' :
{
userGateway.createUser(words[1], words[2], words[3]);
notifyClients();
break;
}
case 'd' :
{
userGateway.updateUser(words[1], words[2], words[3]);
notifyClients();
break;
}
case 'e' :
{
userGateway.deleteUser(words[1]);
notifyClients();
break;
}
}
try {
Thread.sleep(1000);
} catch (Exception e){}
String time_stamp = new java.util.Date().toString();
String returnCode = "Single Socket Server responded at " + time_stamp + (char) 13;
sendMessage(client, returnCode);
}
/**
* Method for sending messages from the server to the client
* #param client the client socket where to send the message
* #param message the message itself to be sent
* #throws IOException
*/
private void sendMessage(Socket client, String message) throws IOException {
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(client.getOutputStream()));
writer.write(message);
System.out.println("[SERVER WRITE]: "+message);
writer.flush();
}
public void notifyClients() throws IOException
{
for(Socket s : clientsConnected)
{
sendMessage(s, "CHANGE IN DATA ");
}
}
/**
* #param args the command line arguments
* #throws java.sql.SQLException
*/
public static void main(String[] args) throws SQLException {
Database database = new Database();
UserGateway userGateway = new UserGateway();
FineGateway fineGateway = new FineGateway();
DriverGateway driverGateway = new DriverGateway();
clientsConnected = new ArrayList<>();
// Setting a default port number.
int portNumber = 2015;
int count = 0;
System.out.println("Starting the multiple socket server at port: " + portNumber);
try {
ServerSocket serverSocket = new ServerSocket(portNumber);
System.out.println("Multiple Socket Server Initialized");
//Listen for clients
while(true) {
Socket client = serverSocket.accept();
clientsConnected.add(client);
Runnable runnable = new FinesPaymentServer(database, userGateway, fineGateway, driverGateway, client, ++count);
Thread thread = new Thread(runnable);
thread.start();
}
} catch (Exception e) {}
}
}
The client class:
public class FinesPaymentClient implements Runnable {
private String hostname = "localhost";
private int port = 2015;
Socket socketClient;
AdministratorModel adminModel;
PoliceModel policeModel;
PostModel postModel;
/**
* Constructor of the class
* #param hostname the host name of the connection
* #param port the port of the connection
* #throws UnknownHostException
* #throws IOException
*/
public FinesPaymentClient(String hostname, int port, AdministratorModel adminModel, PoliceModel policeModel, PostModel postModel) throws UnknownHostException, IOException
{
this.hostname = hostname;
this.port = port;
this.adminModel = adminModel;
this.policeModel = policeModel;
this.postModel = postModel;
connect();
}
/**
* Method for connecting to the host by a socket
* #throws UnknownHostException
* #throws IOException
*/
public void connect() throws UnknownHostException, IOException {
System.out.println("Attempting to connect to " + hostname + ":" + port);
socketClient = new Socket(hostname, port);
System.out.println("Connection Established");
}
/**
* Method for reading response from the server
* #return the string read from the server
* #throws IOException
*/
public String readResponse() throws IOException {
String userInput;
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(socketClient.getInputStream()));
System.out.println("[CLIENT READ]:");
while ((userInput = stdIn.readLine()) != null) {
System.out.println(userInput);
return userInput;
}
return userInput;
}
/**
* Method for closing connection between client and server
* #throws IOException
*/
public void closeConnection() throws IOException {
socketClient.close();
}
/**
* Method for writing messages to the server
* #param message the message to be sent
* #throws IOException
*/
public void writeMessage(String message) throws IOException {
String time_stamp = new java.util.Date().toString();
// Please note that we placed a char(13) at the end of process...
// we use this to let the server know we are at the end
// of the data we are sending
String process = message + (char) 13;
BufferedWriter stdOut = new BufferedWriter(
new OutputStreamWriter(socketClient.getOutputStream()));
stdOut.write(process);
System.out.println("[CLIENT WRITE]: "+process);
// We need to flush the buffer to ensure that the data will be written
// across the socket in a timely manner
stdOut.flush();
}
#Override
public void run() {
try {
String response;
while(true)
{
response = readResponse();
System.out.println("HERE"+response.substring(0, 13));
if(response.substring(0, 13).equals("CHANGE IN DATA"))
{
adminModel.setChange();
}
}
} catch (IOException e) {
System.out.println(e);
}
}
/**
* Main method of the application
* #param arg the parameters given as arguments
* #throws SQLException
* #throws UnknownHostException
* #throws IOException
*/
public static void main(String arg[]) throws SQLException, UnknownHostException, IOException {
AdministratorModel adminModel = new AdministratorModel();
PoliceModel policeModel = new PoliceModel();
PostModel postModel = new PostModel();
FinesPaymentClient client = new FinesPaymentClient("localhost", 2015, adminModel, policeModel, postModel);
Runnable client2 = new FinesPaymentClient("localhost", 2015, adminModel, policeModel, postModel);
Thread thread = new Thread(client2);
thread.start();
Login login = new Login();
ClientSide clientSide = new ClientSide(login, client, adminModel, policeModel, postModel);
}
}
ClientSide class:
public class ClientSide {
private final Login login;
private FinesPaymentClient client;
AdministratorModel adminModel;
PoliceModel policeModel;
PostModel postModel;
/**
* Constructor instantiating needed classes
* #param login an instance of the login class
* #param client the client needing the control logic
* #param adminModel
* #param policeModel
* #param postModel
* #throws SQLException using classes connecting to a database sql exceptions can occur
*/
public ClientSide(Login login, FinesPaymentClient client, AdministratorModel adminModel, PoliceModel policeModel, PostModel postModel) throws SQLException
{
this.login = login;
this.client = client;
this.adminModel = adminModel;
this.policeModel = policeModel;
this.postModel = postModel;
login.addButtonListener(new ButtonListener());
}
/**
* Listener for the login button. Reads, verifies and provides the interface according to logged in user type.
*/
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
try
{
client.writeMessage("a " + login.field1.getText()+ " " + login.field2.getText());
String response = client.readResponse();
if(response.charAt(0) == '1')
{
login.setVisible(false);
AdministratorGUI administratorGUI = new AdministratorGUI(adminModel, client);
AdministratorController adminController = new AdministratorController(client, administratorGUI, adminModel);
}
//if user is post office employee
else if(response.charAt(0) == '2')
{
login.setVisible(false);
PostGUI postGUI = new PostGUI();
PostController postController = new PostController(client, postGUI, postModel);
}
//if user is police employee
else if(response.charAt(0) == '3')
{
login.setVisible(false);
PoliceGUI policeGUI = new PoliceGUI();
PoliceController policeController = new PoliceController(client, policeGUI, policeModel);
}
else
{
JOptionPane.showMessageDialog(null,"Login failed! Please try again!");
}
}
catch (IOException ex)
{
Logger.getLogger(ClientSide.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
I'm 99% sure that the error is on client side reading the message sent from the server as notification, but I simply cannot figure it out how could I retrieve that message. Right now I have a try in the client threads run method, but doesn't work. Other classes and other functionalities work just fine, this is my only problem. Do you have any ideas what the mistake could be? I would appreciate any help.
Based on this tutorial and another tutorial that unfortunately I can't get my hands on right now, I've created my Client-Server application but instead of sending string messages, the client asks for data(using Object Input/Output Streams) from the server using a custom class "Message".
First I created, the basic concept of it, using simple Java and tested both the server and the client on my computer, and displayed the data my client received in the console output. Everything worked out great, so I started to make the transition to Android(for the client). Trying to use the AsycTask, as show in the linked tutorial, I've managed so far to establish the connection between the client and the server. But I'm having a problem getting my server to read my "Message" object. Here are my classes:
Server:
import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class T_Server extends Thread {
private static int port = 4444;
private ServerSocket srvSock = null;
private Socket clntSock = null;
private boolean running = false;
private ObjectInputStream in;
private ObjectOutputStream out;
private OnMessageReceived msgListener;
private Message msgIn;
private Object objSend;
public static void main(String[] args) {
OnMessageReceived _msgListener=new OnMessageReceived();
T_Server server=new T_Server(_msgListener);
server.start();
}
public T_Server(OnMessageReceived _msgListener) {
this.msgListener = _msgListener;
}
public void send(Object _msg) {
if (out != null) {
try {
out.writeObject(_msg);
out.flush();
} catch (IOException ex) {
Logger.getLogger(T_Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
#Override
public void run() {
running = true;
try {
srvSock = new ServerSocket(port);
System.out.println("Server startet. IP : " + InetAddress.getLocalHost() + ", Port : " + srvSock.getLocalPort());
System.out.println("\nWaiting for a client ...");
clntSock = srvSock.accept();
System.out.println("\nClient accepted: " + clntSock);
try {
out = new ObjectOutputStream(clntSock.getOutputStream());
in = new ObjectInputStream(clntSock.getInputStream());
while (running) {
msgIn = (Message) in.readObject();
System.out.println(msgIn.toString());
objSend = msgListener.messageReceived(msgIn);
send(objSend);
}
} catch (Exception e) {
System.out.println("S: Error");
e.printStackTrace();
} finally {
clntSock.close();
}
} catch (Exception e) {
System.out.println("S: Error");
e.printStackTrace();
}
}
}
I use the same Message class both on the Server and on the Client
Message Class:
import java.io.Serializable;
public class Message implements Serializable{
private static final long serialVersionUID = 1L;
public String sender, content, type;
public Message(String sender, String type, String content){
this.sender = sender; this.type=type; this.content = content;
}
#Override
public String toString(){
return "{type='"+type+"', sender='"+sender+"', content='"+content+"'}";
}
}
I have also created a class to handle the Messages, on the server side, called OnMessageReceived.
P.S. In this class there are fields and some options that have to do with my backend database.
OnMessageReceived:
import java.sql.SQLException;
import java.util.regex.Pattern;
public class OnMessageReceived {
public Object messageReceived(Message message) throws SQLException {
Message _msg = message;
Database db = new Database();
Object objReturn;
String strResult;
boolean addResult;
final Pattern pattern = Pattern.compile("\\[.*?&");
final String[] result;
if (_msg.type.equals("getUsers")) {
objReturn = db.getUsers();
return objReturn;
} else if (_msg.type.equals("getFriends")) {
objReturn = db.getFriends(_msg.sender);
return objReturn;
} else if (_msg.type.equals("addFriend")) {
String _UserName, _UserNameFriend;
_UserName = _msg.sender;
_UserNameFriend = _msg.content;
addResult = db.addFriend(_UserName, _UserNameFriend);
if (addResult) {
strResult = "Add was successfull";
return strResult;
} else if (!addResult) {
strResult = "Add failed";
return strResult;
}
System.out.println(addResult);
} else if (_msg.type.equals("addUser")) {
String _UserName, _Password, _Phone;
result = pattern.split(_msg.content);
_UserName = _msg.sender;
_Password = result[0];
_Phone = result[1];
addResult = db.addUser(_UserName, _Password, _Phone);
if (addResult) {
strResult = "Add was successfull";
return strResult;
} else if (!addResult) {
strResult = "Add failed";
return strResult;
}
System.out.println(addResult);
} else if (_msg.type.equals("Login")) {
boolean isUser;
String _UserName;
_UserName = _msg.sender;
isUser = db.isUser(_UserName);
if (isUser) {
strResult = "Login Successfull";
return strResult;
} else if (!isUser) {
strResult = "Login failed";
return strResult;
}
}
return null;
}
}
For the client side(on the Android) it's very simillar to the one in the linked tutorial.
The difference is that I only have 2 buttons, one to connect to the server and one to send my message, which is an instance of my Message class.
Client:
import java.io.*;
import java.net.*;
import android.util.Log;
public class T_Client {
private static final String TAG = "MyActivity";
private static String serverIP = "192.168.1.11";
private static int port = 4444;
private InetAddress serverAddr = null;
private Socket sock = null;
private boolean running = false;
private ObjectInputStream in;
private ObjectOutputStream out;
private OnMessageReceived msgListener;
Object objIn, objReceived;
public T_Client(OnMessageReceived _msgListener){
this.msgListener=_msgListener;
}
public void send(Message _msg) {
if (out != null) {
try {
out.writeObject(_msg);
out.flush();
Log.i(TAG,"Outgoing : " + _msg.toString());
} catch (IOException ex) {
Log.e(TAG,ex.toString());
}
}
}
public void stopClient(){
running = false;
}
public void run(){
running = true;
try {
//here you must put your computer's IP address.
serverAddr = InetAddress.getByName(serverIP);
Log.i("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
sock = new Socket(serverAddr, port);
try {
//send the message to the server
out =new ObjectOutputStream(sock.getOutputStream());
//receive the message which the server sends back
in =new ObjectInputStream(sock.getInputStream());
Log.i("TCP Client", "C: Connected.");
//in this while the client listens for the messages sent by the server
while (running) {
objIn = in.readObject();
if (objIn != null && msgListener != null) {
//call the method messageReceived from MyActivity class
msgListener.messageReceived(objIn);
}
objIn = null;
}
Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + objIn + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
sock.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
public interface OnMessageReceived {
public void messageReceived(Object objReceived);
}
}
Main Activity:
import java.io.IOException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
private static final String TAG = "MyActivity";
private T_Client client;
private Message msgSend;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void connect(View v) throws IOException {
new connectTask().execute("");
}
public void btnSend(View v) throws IOException {
msgSend=new Message("Setlios", "getUsers", "");
if(client!=null){
client.send(msgSend);
}
}
public class connectTask extends AsyncTask<Object,Object,T_Client> {
#Override
protected T_Client doInBackground(Object... objIn) {
//we create a TCPClient object and
client = new T_Client(new T_Client.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(Object objIn) {
//this method calls the onProgressUpdate
publishProgress(objIn);
}
});
client.run();
return null;
}
#Override
protected void onProgressUpdate(Object... values) {
super.onProgressUpdate(values);
Log.i(TAG,values.getClass().getName().toString());
}
}
}
When I hit the "Send" button I get this error on the server console which points me to the point where I read the object read from the ObjectInputStream and pass it an instance of the Message class but I can't understand what the problem is. I also noticed that it shows this "in.neverhide.connect" which is the package name of the project for my android client
java.lang.ClassNotFoundException: in.neverhide.connect.Message
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:622)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1593)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at Objects_WORKING.T_Server.run(T_Server.java:61)
Ok after searching around I found this post and the answer from Akinsola 'mys Tunmise. I've made the Message class into a jar and used it as an external reference in both the client and the server.