I wrote a server that listens for client messages, it's a variation of http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html. I wrote them both in eclipse as java classes in the same project. To test it I have a client class with a main that starts the server and then sends messages to it. When I run it the program just hangs at serverSocket.accept(); according to the javadoc for ServerSocket accept is not asynchronous? That would explain the hanging, but then how does the tutorial code work then?
UPDATE - here is my working code:
Here is the working code:
MyServer.java
/*imports neglected for brevity */
public class MyServer {
public static final String hostname = "localhost";
public static final int portNum = 4444;
ServerSocket serverSocket;
BufferedReader serverReader;
File serverLog;
FileWriter fw;
BufferedWriter serverWriter;
Socket clientSocket;
public static void main(String[] args) {
MyServer server = new MyServer(portNum);
// start the server so it can listen to client messages
server.start();
}
public MyServer(int portNum) {
try {
// endpt for server side, used to listen for client socket
serverSocket = new ServerSocket(portNum);
/* have server socket listen for connection, return client socket.
* serverSocket can now talk to clientSocket
*/
clientSocket = serverSocket.accept();
// server writes messages to this log
serverLog = new File("ServerLog.txt");
if(!serverLog.exists())
serverLog.createNewFile();
fw = new FileWriter(serverLog.getAbsoluteFile());
serverWriter = serverWriter = new BufferedWriter(fw);
/* server reads from this stream that is populated by the client's
* OUTPUT stream/client socket's INPUT stream
*/
serverReader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())
);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void start() {
String clientMsg;
try {
while((clientMsg = serverReader.readLine()) != null) {
if(clientMsg.startsWith("exit")) {
break;
}
serverWriter.append(clientMsg);
}
serverWriter.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
MyClient.java
public class MyClient {
public static final String hostname = "localhost";
public static final int portNum = 4444;
public static void main(String[] args) {
String msg = "message 1";
try {
// server is listening on http://localhost:4444
Socket serversSocket = new Socket(hostname, portNum);
PrintWriter clientOut = new PrintWriter(serversSocket.getOutputStream(), true);
// send first message
clientOut.println(msg);
msg = "message 2";
// send second message
clientOut.println(msg);
msg = "exit";
// this will stop the server
clientOut.println(msg);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
If you go through the tutorial it creates two applications one with client one with server.
You cannot create a variation like this as, when you call the constructor, your whole application blocks in clientSocket = serverSocket.accept();.
If you insist on creating a single application for whatever reason, you can do multithreading. But I do not see any reason why you would want to do that.
The tutorial assumes you are not running them in the same program. If you must run them in the same program, then start your server in a separate thread.
if you have an android phone you can test this with the app TCP socket
make sure you PortForward the port the server is listening to.
some isp also block ports so make sure with your isp that all ports are open
trust me broke my head on this one :)
http://docs.oracle.com/javase/6/docs/api/java/net/ServerSocket.html
also make sure your server has the public ip and not local ip
if you test this localy then the code above is fine if not you will need to add
bind(SocketAddress endpoint)
/*Binds the ServerSocket to a specific address (IP address and port number).*/
you can find your ip by typeing in google: whats my ip
Related
I have two classes server and client. I am running both the server and the client on the intelliji. I am able to write the data to the Json file on the server but when it comes to reading the data, I am not able to read it. My application is not responding when I am trying to read the data. I am new to Socket Programming please help me.
Here is the code on the client side
import java.io.*;
import java.net.Socket;
public class Client {
public String readDataFromServer(Socket socket) throws IOException {
InputStreamReader inputStreamReader = new
InputStreamReader(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
return bufferedReader.readLine();
}
public void writeDataToServer(String obj) throws IOException {
Socket socket = new Socket("localhost", 1299);
OutputStreamWriter outputStreamWriter = new
OutputStreamWriter(socket.getOutputStream());
PrintWriter printWriter = new PrintWriter(outputStreamWriter);
printWriter.write(obj);
printWriter.flush();
printWriter.close();
}
}
Here is the code on the server side
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
static void writeJson (String str) throws IOException {
FileWriter pw = null;
try {
pw = new FileWriter("MYJSON.json", true);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
pw.write(str + '\n');
pw.flush();
try {
} catch (Exception E) {
E.printStackTrace();
}
pw.close();
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(1299);
Socket socket = serverSocket.accept();
InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = bufferedReader.readLine();
writeJson(str);
FileReader fileReader = new FileReader("MYJSON.json");
BufferedReader buff = new BufferedReader(fileReader);
OutputStreamWriter outputStreamWriter = new
OutputStreamWriter(socket.getOutputStream());
PrintWriter printWriter = new PrintWriter(outputStreamWriter);
printWriter.write(buff.readLine());
printWriter.flush();
}
}
I have another class called display controller which is calling the method which is calling the method by passing the socket object. Here is the piece of code from this class.
Client client = new Client();
button1.setOnAction(e-> {
try {
String str;
while ((str = client.readDataFromServer(socket)) != null) {
Object obj = null;
try {
obj = jsonParser.parse(str);
What I am doing wrong here? How do I fix it?
Thank you
There's a couple of issues in your code.
The main one is in the main method of the Server class. Your server only accepts one connection. That connection writes and reads the json file and then your main method ends. If your main program ends, then the server is gone. This means that the first client that connects will work and write to the file, but any subsequent connections will not connect because there's no server accepting connections anymore. Typical servers run indefinitely by using a while loop with true as the condition.
Example Structure of a server without threads:
public class Server {
// this class represents an instance of a client connection to this server
// It's an object that keeps track of the socket created by referencing
// the connection.
private class ClientInstanceOnTheServer {
private Socket connectionToClient;
public ClientInstanceOnTheServer(Socket connectionToClient) {
this.connectionToClient = connectionToClient;
}
private void logicToServeAClient() {
// here goes the logic that serves a client
}
public void run () {
try {
logicToServeAClient();
} finally {
try {
socket.close();
} catch (IOException e) {// handle exceptions!}
}
}
}
public static void main(String [] args) {
try {
ServerSocket serverSocket = new ServerSocket(1299);
while (true) { // run indefinitely
Socket socket = serverSocket.accept(); // accept connections from clients
// keep track of the socket object as it represents a connection to a client
// the server is responsible for keeping track of its connections to clients
// Example:
ClientInstanceOnTheServer client = new ClientInstanceOnTheServer(socket);
client.run();
}
} finally {
serverSocket.close();
}
}
}
Example Structure of a server with Threads:
NOTE: The code below is not to represent a complete solution with threads, but rather an example to explain how a server works.
public class Server {
// this class represents an instance of a client connection to this server
// It's an object that keeps track of the socket created by
// the connection and it runs in a separate thread to not block
// the main method thread on this server.
private class ClientInstanceOnTheServer extends Thread {
private Socket connectionToClient;
public ClientInstanceOnTheServer(Socket connectionToClient) {
this.connectionToClient = connectionToClient;
}
private void logicToServeAClient() {
// here goes the logic that serves a client
}
public void run () {
try {
logicToServeAClient();
} finally {
try {
socket.close();
} catch (IOException e) {// handle exceptions!}
}
}
}
public static void main(String [] args) {
try {
ServerSocket serverSocket = new ServerSocket(1299);
while (true) { // run indefinitely
Socket socket = serverSocket.accept(); // accept connections from clients
// keep track of the socket object as it represents a connection to a client
// the server is responsible for keeping track of its connections to clients
// and it should use a separate thread for each client to not block the main method thread.
// Example:
ClientInstanceOnTheServer client = new ClientInstanceOnTheServer(socket);
client.start(); // this will execute the run method in ClientInstanceOnTheServer class.
}
} finally {
serverSocket.close();
}
}
}
Your server is always doing both, writing and reading the json file, regardless of what the client wants. The server should somehow allow the client to communicate what it wants to do, and then it executes only what the client asked for. If we use the skeleton code above, this logic would go in the method logicToServeAClient of the ClientInstanceOnTheServer class. The server and client use the socket object's input and output streams to communicate with each other. The server and client need to agree beforehand on which commands/operations the client needs and the server is willing to serve. In your case, it would be READ and WRITE. Then you create a contract (Protocol) between the client and server on how to send these commands to the server and how the server will respond to the client for each command.
Example of a protocol:
// client sends READ to server
// client waits for respond from server
// server read json file and send it to the client
// client sends WRITE to server
// server then waits for the client to send the string to write.
// Once it receives the string, it writes it to the json file.
All of this is achievable using the socket's input and output streams
It's important to distinguish the difference between the Client and the ClientInstanceOnTheServer classes. Client is your Client class that connects to the server and ClientInstanceOnTheServer holds the connection and also runs the server code that serves the commands requested by the Client class. In the protocol above, whenever client is mentioned, is referring to the Client class. Whenever the server is mentioned is referring to the ClientInstanceOnTheServer class.
You can find more examples on google, like: http://cs.lmu.edu/~ray/notes/javanetexamples/. However, this should set you up on a path to fix your issue.
Cheers
If I have a server and a client and I opened a socket between the two:
1.Is it possible that the client will have a printWriter stream, in order to write things to the socket, but the server won't have in the mean time a bufferReader?
If the answer of 1 is yes, if that client will send a message to the server (who currently doesn't have a reading stream), what will happend to this message until te server will create a reading stream and read the message?
thank you
This is not at all specific to Java, but TCP/IP. There are buffers to keep the data received, so it's not possible that some data would be lost because one end isn't "ready" yet. This is because TCP will retransmit data that hasn't been acknowledged as received, guaranteeing that all the bytes that are written are received on the other (barring obvious cases).
in addition to #Kayaman's answer:
consider this Compile-able simple Java implemented example:
Server Side:
import java.io.*;
import java.net.*;
public class SimpleServer implements Runnable{
int serverPort = 45000;
ServerSocket serverSocket = null;
boolean isStopped = false;
public SimpleServer(int port){
this.serverPort = port;
}
public void run(){
try {
serverSocket = new ServerSocket(serverPort);
} catch (IOException e) {
System.err.println("Cannot listen on this port.\n" + e.getMessage());
System.exit(1);
}
while(!isStopped){
try {
Socket clientSocket = serverSocket.accept();
} catch (IOException e) {
// do nothing
}
}
}
public static void main(String[] args) throws IOException {
SimpleServer server = new SimpleServer(45000);
new Thread(server).start();
System.out.println("Server is waiting to connect");
}
}
Client Side:
import java.io.*;
import java.net.*;
public class SimpleClient {
public static void main(String[] args) throws IOException {
Socket socket = null;
PrintWriter out = null;
try {
socket = new Socket("127.0.0.1", 45000);
out = new PrintWriter(socket.getOutputStream(), true);
System.out.println("output stream created");
out.write(9);
System.out.println("message was sent to output with no listener");
} catch (UnknownHostException e) {
// do nothing
} catch (IOException e) {
// do nothing
}
}
}
the example is an implementation of a very basic client server connection in which a socket is created and a stream is defined only on the client side, followed by a write to the stream that will eventually be read by the server (if at all).
therefore, to answer you questions:
1) yes, it's possible to open a one-way connection stream without a "listener"
2) edit: according to #EJP: It will be saved within the socket's buffer until it is read or the socket is closed.
I have a TcpServer class that is responsible to, well, act like a tcp server. You can find the class below :
public class TcpServer {
private ServerSocket serverSocket;
private Socket socket;
private int locallyBoundPort;
public TcpServer() {
}
public TcpServer(int locallyBoundPort) {
try {
this.serverSocket = new ServerSocket(locallyBoundPort);
serverSocket.setReuseAddress(true);
} catch (IOException e) {
System.out.println("Error at binding to port TCP : " + locallyBoundPort + "...cause : " + e.getMessage());
}
socket = null;
}
public void accept() {
try {
socket = serverSocket.accept();
socket.setReuseAddress(true);
} catch (IOException e) {
System.out.println("Error at accept : " + locallyBoundPort);
}
}
public void send(Data data) throws IOException {
if(socket != null) {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(data);
}
}
public Data receive() throws ClassNotFoundException, IOException {
if(socket != null) {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
return (Data) in.readObject();
} else {
return null;
}
}
public boolean bind(int port) throws IOException {
try {
this.serverSocket = new ServerSocket(port);
this.locallyBoundPort = port;
} catch(IOException e) {
return false;
}
return true;
}
public void close() {
try {
serverSocket.close();
socket.close();
} catch (IOException e) {
OzumUtils.print("IOException in close, TcpServer");
}
}
public int getLocallyBoundPort() {
return locallyBoundPort;
}
public Socket getSocket() {
return socket;
}
public ServerSocket getServerSocket() {
return serverSocket;
}
}
And I have a code piece that does this :
TcpServer tcpServer = new TcpServer(LocalPort);
while(1)
{
tcpServer.accept();
Thread thread = new Thread(new runnable(tcpServer));
thread.start();
tcpServer = new TcpServer(LocalPort);
}
However I am getting a port already in use error. I thought two different socket instances could listen to the same port as multiplexing allows two connections through the same port when the connector has different ip or port ?
What am I missing?
You cannot bind two tcp server sockets to the same port. reuseAddress is really for client sockets, and it does not work the way you think it does ... and the way you are using it would not do anything at all either way (because you are setting it after binding).
You don't really need to bind twice to the same port either. Just remove this line tcpServer = new TcpServer(LocalPort); from the bottom of your while loop, and you'll be all set.
The way this works is that you bind your server socket once and listen to the port. When a connection arrives, it forks a client socket for you to communicate with the client, and the original server socket continues to listen for more connections.
Basically, you need to remove the socket member (and any other state) from your TcpServer, and make the accept method return the accepted socket. Then make your runnable take that socket as a parameter instead of the TcpServer, and use that to serve the client connection. Then just keep calling accept in the loop, and forking threads for new connections same way you do know, except do not recreate the server every time.
Or, alternatively, remove the server socket and port from TcpServer, create the socket outside the loop, then while(true) call accept on it, create a new TcpServer with the returned client socket, and use it in a thread to process the connection.
Do not forget to close client sockets after you are done with them.
No, you can't use a port already in listening state. However any number of clients can connect to this same port. You don't need to listen to the port again, you just spawn a new thread to process the current connection and wait for a new one. For example, supposing you have a class TcpConnectionHanlder that implements Runnable and takes the Socket as parameter, the loop would look like
while (true) { //while(1) is not valid Java syntax
final Socket tcpSocket = tcpServer.accept(); // Get socket for incoming connection
final Thread thread = new Thread(new TcpConnectionHanlder(tcpSocket)); // Create a thread for this socket/client connection
thread.start(); // Launch the thread
// tcpServer = new TcpServer(LocalPort); <- not needed, port still listening.
}
Then in your TcpConnectionHanlder instance you handle this particular client (socket).
I'm working on a program where multiple clients need to interact with a remote server.
I've tested it locally and everything's ok (sort of, more on that later), but I can't understand how to set a remote IP.
I read Socket's API and also InetAddress' API. Is this the right way to do it? How does Java deal with IPs? There are not just simple Strings as on the localhost case, am I right?
This is my code:
Client:
public class Client {
final String HOST = "localhost";
final int PORT = 5000;
Socket sc;
DataOutputStream message;
DataInputStream istream;
public void initClient() {
try {
sc = new Socket(HOST, PORT);
message = new DataOutputStream(sc.getOutputStream());
message.writeUTF("test");
sc.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Server:
public class Server {
final int PORT = 5000;
ServerSocket sc;
Socket so;
DataOutputStream ostream;
String incomingMessage;
public void initServer() {
try {
sc = new ServerSocket(PORT);
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
}
BufferedReader input;
while(true){
try {
so = new Socket();
System.out.println("Waiting for clients...");
so = sc.accept();
System.out.println("A client has connected.");
input = new BufferedReader(new InputStreamReader(so.getInputStream()));
ostream = new DataOutputStream(so.getOutputStream());
System.out.println("Confirming connection...");
ostream.writeUTF("Successful connection.");
incomingMessage = input.readLine();
System.out.println(incomingMessage);
sc.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
}
Also, I'm dealing with some troubles on my local tests.
First of all, some times I get the following result:
Waiting for clients...
A client has connected.
Confirming connection...
Error: Software caused connection abort: recv failed
Though some other times it works just fine. Well, that first connection at least.
Last question:
When I try to send a message from the server to the client, the program enters in an infite loop and need to be closed manually. I'm adding this to the code to do so:
fromServerToClient = new BufferedReader(new InputStreamReader(sc.getInputStream()));
text = fromServerToClient.readLine();
System.out.println(text);
Am I doing it right?
Thanks.
Instead of using
String host = "localhost";
you can use something like
String host = "www.ibm.com";
or
String host = "8.8.8.8";
this is how you would usually implement a Server:
class DateServer {
public static void main(String[] args) throws java.io.IOException {
ServerSocket s = new ServerSocket(5000);
while (true) {
Socket incoming = s.accept();
PrintWriter toClient =
new PrintWriter(incoming.getOutputStream());
toClient.println(new Date());
toClient.flush();
incoming.close();
}
}
}
And following would be As Client:
import java.util.Scanner;
import java.net.Socket;
class DateClient {
public static void main(String[] args) throws java.io.IOException
{
String host = args[0];
int port = Integer.parseInt(args[1]);
Socket server = new Socket(host, port);
Scanner scan = new Scanner( server.getInputStream() );
System.out.println(scan.nextLine());
}
}
You should consider doing this in threads. Right now multiple users can't connect to the server at once. This means that they have to queue for connection to the server resulting in very poor performance.
Normally you receive the client and instantiate a new thread to handle the clients request. I only have exampls in C# so i won't bother you with that, but you can easily find examples on google.
eg.
http://www.kieser.net/linux/java_server.html
ok is hard for me to describe my problem now but then i will try my best to in order for me to get some assist.
technically i have a server.java and client.java as a super class. and my layout structure for my server and client connection goes like this
MAIN SERVER --- CLIENT/SERVER ----- CLIENT
my main problem is the this CLIENT/SERVER part is 1 driver class that calls 2 different classes which is CLIENT and SERVER together... and this creates a problem when my CLIENT sends something that needs to be received by MAIN SERVER side needs to go through CLIENT/SERVER part. if is that condition happens..
the CLIENT of course need to interact with CLIENT/SERVER (SERVER) part because is a SERVER that accepts the CLIENT data. but now i wanted the (SERVER) part in the CLIENT/SERVER to transfer the data to (CLIENT) in the CLIENT/SERVER part so that it can be send to the MAIN SERVER
how is it possible for me to write something that allows the CLIENT/SERVER to interact with each other so it can transfer the data between them vise versa? how ever this is my code for calling the CLIENT and SERVER together
public class Slave {
public static void main(String args []) throws IOException{
try{
// set Config file settings to slave mode
Config cfg = new Config("Slave");
String MasterServerIP = cfg.getProperty("ServerIP");
String MasterServerPort = cfg.getProperty("ServerPort");
String SlaveServerPort = cfg.getProperty("ListeningPort");
System.out.println("Slave Client connecting to Master Server");
// start connect to master server by calling the SlaveClient class
new SlaveClient(MasterServerIP,Integer.parseInt(MasterServerPort)).start();
int numClient = 0;
ServerSocket listener = new ServerSocket(Integer.parseInt(SlaveServerPort));
System.out.println("Server starts running");
try{
while(true){
// start listening to the server port by calling SlaveServer class
new SlaveServer(listener.accept(), numClient++, Integer.parseInt(SlaveServerPort)).start();
}
} finally {
listener.close();
}
} catch (FileNotFoundException file) {
System.out.println("File Not Found Error: "+file.getMessage());
}
}
}
the above is only the driver class that calls the 2 object class which is the SERVER and CLIENT side.
i will attach my slaveserver and slaveclient code here but i am not sure how to do it like you said
public class SlaveServer extends Server {
private JFrame frame = new JFrame();
private JTextArea msgArea = new JTextArea();
private JTextArea connectionArea = new JTextArea();
// SlaveServer Constructor
public SlaveServer(Socket socket, int numClient, int port) {
super(socket, numClient, port);
}
public void writeToMsg(String msg){
msgArea.append(msg+"\n");
}
public void writeToConnection(String msg){
connectionArea.append(msg+"\n");
}
public void run(){
try{
startGUI();
// initial BufferedReader and PrintWriter object by binding it with Socket
BufferedReader in = new BufferedReader(new InputStreamReader(getSocket().getInputStream()));
PrintWriter out = new PrintWriter(getSocket().getOutputStream(), true);
// welcome message send from server to client
out.println("Welcome to the Slave Server port:"+getPort()+" client #"+getNumClient());
while(true){
String readmsg = in.readLine();
writeToMsg(readmsg);
}
} catch (IOException e){
writeToMsg("Error in closing Socket");
}
writeToConnection("Connection from client #"+getNumClient()+" is closed");
}
}
public class SlaveClient extends Client{
private BufferedReader in;
private PrintWriter out;
private JFrame frame = new JFrame();
private JTextArea msgArea = new JTextArea();
private JTextArea connectionArea = new JTextArea();
// SlaveClient Constructor
public SlaveClient(String ip, int port) {
super(ip, port);
}
public void run(){
startGUI();
Socket sock = null;
try {
sock = new Socket(getIp(), getPort());
} catch (IOException e) {
e.printStackTrace();
}
try {
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
try {
out = new PrintWriter(sock.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
}
out.println("TEST");
// while loop for reading message from server
while(true){
try {
getMsg(in);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
So you are trying to write a proxy?
You you need to give the server half of the proxy a reference to the client half, so that it can forward the data.
Then create a method in the client half to accept messages from the server half.
So each message you read in at the server half, you pass to the client half. The client half can then pass it to the real server.