I'm really confused about how and why this example of client-server connection works.
I have two classes, NetworkClient
and NetworkServer
.
NetworkClient
creates a socket and connects it to the server:
class NetworkClient {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("localhost", 3141);
OutputStream out = socket.getOutputStream();
PrintStream ps = new PrintStream(out, true);
InputStream in = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
ps.println("Es begab sich aber zu der Zeit,");
System.out.println("client sent: Es begab sich aber zu der Zeit,");
System.out.println("client received: "+reader.readLine());
}
//some other code
}
}
And NetworkServer
accepts that socket:
public class NetworkServer {
private final ServerSocket srv;
public NetworkServer(int port) throws IOException {
srv = new ServerSocket(port);
}
private void connectAndTalk() {
Socket socket = null;
try {
socket = srv.accept();
communicate(socket);
}
// some code
}
private void communicate(Socket socket) throws IOException, InterruptedException {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream out = new PrintStream(socket.getOutputStream());
String s;
do {
s = in.readLine();
System.out.println("server received: "+s);
if(s.equals("Es begab sich aber zu der Zeit,")) {
TimeUnit.SECONDS.sleep(4);
out.println("dass ein Gebot ausging vom Kaiser Augustus,");
}
// some code
The client writes to his output stream and reads from his input.
Why does the server read from the client's input and not from the output stream? And, analogously, why does the server write to the client's output stream? Why doesn't it look like this?
private void communicate(Socket socket) throws IOException, InterruptedException {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getOutputStream()));
PrintStream out = new PrintStream(socket.getInputStream());
Imagine a conversation between two people, person C and person S.
This needs:
As you can see above, there are 4 elements required to enabled this two way communication.
The metaphor is:
OutputStream
of person C.InputStream
of person C.OutputStream
of person S.InputStream
of person S.Socket
. It holds its two streams (mouth and ears).Socket
. It holds its two streams (mouth and ears).The communication involves two people. Likewise there exist two separate Java-wise instances of Socket
: one at client and one at server, each with a pair of InputStream
/OutputStream
. This enables two way communication. "Person C speaks using its mouth" is translated to "client-side Socket
sends data using its OutputStream
". Person C decides what to say to the other end of the communication, hence they write to their OutputStream
that data. The other end of the communication does not know what data is going to be sent by C, so they read their InputStream
to figure out.
Why does the server read from the client's input and not from the output stream? And, analogously, why does the server write to the client's output stream?
There are some obvious rules (let me say it this way) which dictate the communication:
Socket
can only receive from its own InputStream
. A person cannot hear from any mouth, nor can they hear from any other individual's ears, ie each Socket
cannot receive from any OutputStream
, nor can it receive from the other endpoint's InputStream
.Socket
can only send using its own OutputStream
. A person cannot speak from any ear, nor can they speak from any other individual's mouth, ie each Socket
cannot send using any InputStream
, nor can it send from the other endpoint's OutputStream
.Server side code:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(final String[] args) throws IOException {
try (final ServerSocket serverSocket = new ServerSocket(12345);
final Socket sPerson = serverSocket.accept()) { //This is one of the Sockets in the two way communication.
final OutputStream sPersonMouth = sPerson.getOutputStream();
final InputStream sPersonEars = sPerson.getInputStream();
sPersonMouth.write(3);
System.out.println("Sent 3 to client!");
System.out.println("Received from client: " + sPersonEars.read());
}
}
}
Server side output:
Sent 3 to client! Received from client: 2
Client side code:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(final String[] args) throws IOException {
try (final Socket cPerson = new Socket("localhost", 12345)) { //This is one of the Sockets in the two way communication.
final OutputStream cPersonMouth = cPerson.getOutputStream();
final InputStream cPersonEars = cPerson.getInputStream();
cPersonMouth.write(2);
System.out.println("Sent 2 to server!");
System.out.println("Received from server: " + cPersonEars.read());
}
}
}
Client side output:
Sent 2 to server! Received from server: 3
The above code illustrates the metaphor through corresponding variable names.
This is answer is just a metaphorical example of what @RemyLebeau is saying...