I'm new to java and i'm trying to learn how to use sockets.
I'm trying to write a simple text messenger, server - client, but i don't know how to make the server always listening for client's stream:
Here's the server code, by now it just manages 1 incoming connection, when the client connects, the server send a message to it:
import java.net.*;
import java.io.*;
public class SocketServer {
private InetAddress ServerAddress;
private int ServerPort;
private int ServerQueue;
private ServerSocket Server;
public SocketServer(String ServerAddress, int ServerPort, int ServerQueue)
{
try
{
this.ServerAddress = InetAddress.getByName(ServerAddress);
}
catch (UnknownHostException uhe)
{
uhe.printStackTrace();
}
this.ServerPort = ServerPort;
}
public boolean ServerCreate()
{
try
{
Server = new ServerSocket(this.ServerPort, 10, this.ServerAddress);
System.out.println("System Message: Server started!");
return true;
}
catch(IOException ioe)
{
ioe.printStackTrace();
System.out.println("System Message: Can't start server!");
return false;
}
}
public void ServerStartListening()
{
int exit = -1;
while(exit < 1)
{
try
{
Socket client = this.Server.accept();
OutputStream clientout = client.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientout));
bw.write("Welcome: "+client.toString());
bw.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
Sorry for my bad english.
You need to implement multi-threading in order to listen for multiple incoming requests. Refer this link: a very nice multi-threaded server example by oracle
You need to read sth. about threads. Here is an initial code:
ServerSocket socketListener;
DoSthWithThisSocket doSthWithThisSocketObj;
socketListener = new ServerSocket(LISTENINGPORT);
Socket socket;
Thread doSthWithThisSocketThread;
while (continueSocketListening()) {
socket = socketListener.accept();
doSthWithThisSocketObj = new DoSthWithThisSocket(socket);
doSthWithThisSocketThread = new Thread(doSthWithThisSocketObj);
doSthWithThisSocketThread.start();
}
There are two main options for doing multi-client socket servers in Java:
Start a new thread for each new client TCP connection as previous responders suggest. This is OK for smallish/toy servers, and when you are just starting playing with sockets. The big downside here is that this approach does not scale - just think about having a thousand concurrent clients ...
Use IO multiplexing with non-blocking sockets as provided by Java NIO package, dispatching accept/read/write events to registered callbacks. You can extend this with work-item queue(s) and a pool of pre-allocated worker threads to take advantage of multiple cores/CPUs in your hardware.
Related
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 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
I'm working on a project which expects a TCP client and Server, where server echoes the message back to client. Following is from the assignment:
The server application shall:
Listen for TCP connections on a well known IP address and port
Accept connections initiated on that port
Receive messages from the client and echo them back
Continue to do this until the client drops the connection.
The client application shall:
Establish a connection with the server at its well known IP address and port
Send messages in an asynchronous manner to the server. The format of the message is
of your choice; however, it must contain enough information in order for it to be
recognized on its return from the server.
I have completed the coding for Server, and this is what i've come up with for the client.
My questions:
What does it mean that Server listens for TCP connections on a well known IP and Port In my implementation, i've used ServerSocket which accepts the port server listens on. Did i interpret it correctly?
In my current implementation of TCPClient, client sends messages to Server, but the println() seems to be a blocking call, which makes it Synchronous. What can i do to make my client asynchronous?
For brevity, I havent added the code of TCPServer, let me know if it is needed
UPDATE**
Based on the feedback, i have modified by TCPClient class. After receiving client request, i spawn two threads ReceiveMessage and SendMessage. Doing that gives me following exception:
[Client] Message sent: Message from Client 97
[Client] Message sent: Message from Client 98
[Client] Message sent: Message from Client 99
[Client] Done Sending all the messages
java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at org.chanders.client.ReceiveMessage.run(ReceiveMessage.java:18)
at java.lang.Thread.run(Thread.java:680)
Following is the new Client Code:
public class TCPClient {
Socket clientSocket = null;
OutputStream out = null;
BufferedReader in = null;
String message = "Hello from Client";
int messagecount = 100;
// server credentials
private static final String SERVER_ADDRESS = "localhost";
private static final int SERVER_PORT = 50001;
protected void execute() {
try {
clientSocket = new Socket(SERVER_ADDRESS, SERVER_PORT);
Thread send = new Thread(new SendMessage(clientSocket.getOutputStream()));
Thread receive = new Thread(new ReceiveMessage(clientSocket.getInputStream()));
send.start();
receive.start();
//For server to wait until send and receive threads finish
send.join();
receive.join();
} catch (UnknownHostException uhe) {
System.err.println("Couldnt find host: " + SERVER_ADDRESS);
uhe.printStackTrace();
System.exit(-1);
}catch(IOException ioe) {
System.err.println("Couldnt get I/O: " + SERVER_ADDRESS);
ioe.printStackTrace();
System.exit(-1);
}catch(InterruptedException ie) {
System.err.println("Thread.join failed: ");
ie.printStackTrace();
System.exit(-1);
}
finally {
//cleanup();
}
}
private void cleanup() {
try {
clientSocket.close();
}catch(Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
public static void main(String[] args) {
TCPClient client = new TCPClient();
client.execute();
}
public class SendMessage implements Runnable {
OutputStream out = null;
String message = "Message from Client";
int messageCount = 100;
public SendMessage(OutputStream out) {
this.out = out;
}
public void run() {
PrintWriter writer = new PrintWriter(out);
try {
for (int i = 0; i < messageCount; i++) {
String m = message + " " + i;
writer.println(m);
System.out.println("[Client] Message sent: " + m);
}
System.out.println("[Client] Done Sending all the messages");
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
} finally {
cleanup();
}
}
private void cleanup() {
try {
out.close();
}catch(Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
public class ReceiveMessage implements Runnable {
InputStream in = null;
String message;
public ReceiveMessage(InputStream in) {
this.in = in;
}
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
try {
while ((message = reader.readLine()) != null) {
System.out.println("[Client] Received message from Server: "
+ message);
}
System.out.println("[Client] Done Receiving messages from Server");
} catch (Exception e) {
e.printStackTrace();
} finally {
cleanup();
}
}
private void cleanup() {
try {
in.close();
}catch(Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
In this context, Asynchronous probably doesn't mean that you can't use println, but that the client must be able to recevie messages while it's sending new ones.
The client should create the socket and then create two threads, one to send messages and the other to recive and print them.
Update
To avoid the exception, use clientSocket.shutdownOutput() instead of closing the output stream.
You could move the send code back to the main thread and keep a separate thread for the receive code or call shutdownOutput() after joining the send thread. Whatever works better for you.
Use a separate thread for each client. When you write something, in the server end , there must be a method which accepts the string. Otherwise it will be blocking. Paste your server code.
Well known ports are port numbers that have been specifically designated for particular protocols, for example 80 is for HTTP and 443 is for HTTPS. Are you meant to be implementing a particular protocol? If you are I would suggest you use the port number for that protocol. Wikipedia has a list of well known port numbers here:
http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
If this is a professional assignment (as opposed to a some homework) then I would strongly recommend the Netty Server, which is basically a NIO client server framework. It significantly simplifies/streamlines the development of this sort.
Make sure to check their documentation as it provides examples implementing exactly the server/client functionality stated in the question.
If this is a homework then this example should provide all necessary details. Please also check Oracle resources.
EDIT: The code below throws no exception but has no output and hangs. It should output "Test message". In main(), we start a thread that's given a server socket listening on a random port. The main thread the tries to connect and communicate with the ServerSocket on that same random port, but is apparently failing. Why?
public class IntraProcSockTest {
private static int port;
private class Listener extends Thread {
public Listener() {
}
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(0);
port = serverSocket.getLocalPort();
Socket socket = serverSocket.accept();
BufferedReader in;
String fromClient;
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while ((fromClient = in.readLine()) != null) {
System.out.println("From client: " + fromClient);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public IntraProcSockTest() {
new Listener().start();
}
public static void main(String[] args) {
new IntraProcSockTest();
try {
Thread.sleep(5000);
Socket socket = new Socket("localhost", port);
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
socketOut.println("Test message");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
A process can connect to a socket created by itself, there is no problem. Show us the code that throws an exception and/or more details about the exception.
First of all, be careful not to specify a local port for the client socket (the one connecting to the other which is listening). Let the OS choose a random port. Remember that any socket is identified by four elements (remote host, local host, remote port, local port), if you bind both the server socket and the client socket on the same local port, let it be 4498, both sockets are defined as follows: (localhost, localhost, 4498, 4498) and this doesn't work. I suspect this might be your problem.
To avoid such problems, client sockets are often bound to a random port, chosen by the OS. Show us your code, expecially the part in which the client sockets gets created and connects to the server socket.
And about IPC, it is not always bad to use sockets as an inter-process or even intra-process communication technique. The performance is worse, obviously, and you might loose some code readability, but your software will be easily portable to a network (distributed) application. It's up to your plans, it's not like IPC sockets == bad.
To create a Socket connection in one thread you can.
ServerSocket ss = new ServerSocket(0); // open a random free port.
Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s = ss.accept();
ss.close();
final byte[] bytes = "Hello World!".getBytes();
final OutputStream out = c.getOutputStream();
out.write(bytes.length);
out.write(bytes);
final DataInputStream in = new DataInputStream(s.getInputStream());
int len = in.read();
final byte[] b = new byte[len];
in.readFully(b);
System.out.println(new String(b));
c.close();
s.close();
If all you want is IPC within a Process, a socket is not the fastest or simplest way to go. Try using a Pipe (NIO) or PipeInput/OutputStream (IO). Its faster and simpler.
Pipe pipe = Pipe.open();
SinkChannel sink = pipe.sink();
SourceChannel source = pipe.source();
or
PipedOutputStream output = new PipedOutputStream();
PipedInputStream input = new PipedOutputStream(output);
BTW: You can connect a client and server Socket in the same thread, however
Using an Exchanger is 10x faster, and using a ring buffer is faster again.
If you want convenience, using an ExecutorService is the best way to deleagte work to a background pool of threads. This can still perform millions of tasks per second.