Download Socket

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Networking in Java
Java Fundamentals
Dmitri Gabbasov
Tartu 2016
The java.net package
●
●
●
●
●
●
●
java.net.Socket
represents a TCP connection to a remote endpoint
java.net.ServerSocket
represents a TCP endpoint that others can connect to
java.net.DatagramSocket
represents a UDP endpoint for transmitting data without a connection
java.net.URI
provides means to syntactically manipulate URIs
java.net.URL
provides means to transmit data over specific application layer protocols
java.net.InetAddress
represents an IP address
java.net.NetworkInterface
provides means to enumerate network interfaces and their IP addresses
Network layers (the TCP/IP model)
Application
HTTP
FTP
Transport
TCP
UDP
Internet
IPv4
IPv6
Link
Ethernet
SMTP
DNS
SSH
TCP — Transmission Control Protocol
●
Connection oriented (client - server)
●
Provides the ability to transmit streaming data
●
Guarantees reliable, ordered delivery
●
Controls flow and congestion
UDP — User Datagram Protocol
●
Connectionless
●
Transmits data in packets (datagrams)
●
No guarantee of ordering or delivery
●
Low latency
Sockets
●
A socket is an endpoint for communication between two machines
●
A socket address is a combination of an IP address and a port number
●
A socket has typically two associated socket addresses — the local address
and the remote address
java.net.Socket
●
Socket()
create an unconnected socket
●
Socket(InetAddress address, int port)
create a socket and connect to the specified IP address and port
●
Socket(String host, int port)
create a socket and connect to the specified host and port
●
void connect(SocketAddress endpoint)
connect an unconnected socket
●
InputStream getInputStream()
get the stream used for reading bytes from the socket
●
OutputStream getOutputStream()
get the stream used for writing bytes to the socket
java.net.Socket example #1
Socket s = new Socket(InetAddress.getLoopbackAddress(), 8080);
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
byte[] request = {1, 1, 2, 3, 5, 8};
out.write(request);
byte[] response = new byte[10];
in.read(response);
System.out.println("Client got: " + Arrays.toString(response));
s.close();
java.net.Socket example #1 (v2)
try (
Socket s = new Socket(InetAddress.getLoopbackAddress(), 8080);
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
) {
byte[] request = {1, 1, 2, 3, 5, 8};
out.write(request);
byte[] response = new byte[10];
in.read(response);
System.out.println("Client got: " + Arrays.toString(response));
}
java.net.ServerSocket
●
ServerSocket()
create an unbound server socket
●
ServerSocket(int port)
create a server socket and bind it to the given port
●
void bind(SocketAddress endpoint)
bind an unbound server socket to a specific endpoint (address + port)
●
Socket accept()
listen for a connection and accept it
java.net.ServerSocket example #1
try (
ServerSocket server = new ServerSocket(8080);
Socket client = server.accept();
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
) {
byte[] request = new byte[10];
int n = in.read(request);
System.out.println("Server got: " + Arrays.toString(request));
for (int i = 0; i < n; i++)
request[i]++;
out.write(request);
}
Example #1 output
Server got: [1, 1, 2, 3, 5, 8, 0, 0, 0, 0]
Client got: [2, 2, 3, 4, 6, 9, 0, 0, 0, 0]
java.net.Socket example #2
try (
Socket s = new Socket(InetAddress.getLoopbackAddress(), 8080);
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream(), UTF_8));
BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream(), UTF_8))
) {
writer.write("Ping\n");
writer.flush();
String response = reader.readLine();
System.out.println("Client got: " + response);
}
java.net.ServerSocket example #2
try (
ServerSocket server = new ServerSocket(8080);
Socket client = server.accept();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(client.getOutputStream(), UTF_8));
BufferedReader reader = new BufferedReader(
new InputStreamReader(client.getInputStream(), UTF_8))
) {
String request = reader.readLine();
System.out.println("Server got: " + request);
writer.write("Pong\n");
writer.flush();
}
Example #2 output
Server got: Ping
Client got: Pong
Accepting multiple connections
●
The server needs to be able to work with several clients simultaneously
●
This can be achieved by using multiple threads
try (ServerSocket server = new ServerSocket(8080)) {
ExecutorService executor = Executors.newCachedThreadPool();
while (true) {
Socket client = server.accept();
executor.execute(() -> {
OutputStream out = client.getOutputStream();
InputStream in = client.getInputStream();
// perform I/O on the client
});
}
executor.shutdown();
executor.awaitTermination(5, TimeUnit.MINUTES);
}
java.net.DatagramSocket
●
●
●
●
●
●
●
DatagramSocket()
create a datagram socket and bind it to any available port
DatagramSocket(int port)
create a datagram socket and bind it to the given port
DatagramSocket(SocketAddress addr)
create a datagram socket and bind it to the given address and port;
passing null creates an unbound socket
void bind(SocketAddress addr)
bind the socket to the given address and port
void connect(InetAddress address, int port)
“connect” the socket to the given address and port
void send(DatagramPacket packet)
send a datagram packet from this socket
void receive(DatagramPacket packet)
receive a datagram packet from this socket
java.net.DatagramSocket example (endpoint #1)
try (DatagramSocket socket = new DatagramSocket()) {
byte[] data = {1, 1, 2, 3, 5, 8};
DatagramPacket request = new DatagramPacket(data, data.length);
request.setAddress(InetAddress.getLoopbackAddress());
request.setPort(8888);
socket.send(request);
DatagramPacket response = new DatagramPacket(new byte[10], 10);
socket.receive(response);
System.out.println(
"Endpoint #1 got: " + Arrays.toString(response.getData()) +
" from " + response.getSocketAddress());
}
java.net.DatagramSocket example (endpoint #2)
try (DatagramSocket socket = new DatagramSocket(8888)) {
DatagramPacket request = new DatagramPacket(new byte[10], 10);
socket.receive(request);
byte[] data = Arrays.copyOf(
request.getData(), request.getLength());
System.out.println(
"Endpoint #2 got: " + Arrays.toString(data) +
" from " + request.getSocketAddress());
for (int i = 0; i < data.length; i++)
data[i]++;
DatagramPacket response = new DatagramPacket(data, data.length);
response.setSocketAddress(request.getSocketAddress());
socket.send(response);
}
java.net.DatagramSocket example output
Endpoint #2 got: [1, 1, 2, 3, 5, 8] from /127.0.0.1:53908
Endpoint #1 got: [2, 2, 3, 4, 6, 9, 0, 0, 0, 0] from /127.0.0.1:8888
Socket channels (java.nio.channels)
●
Access the same socket from different threads
●
Manage multiple sockets in one thread
●
Use special buffers for read/write operations
Socket channels example
Selector selector = Selector.open();
for (int i = 0; i < 100; i++) {
SocketChannel client = SocketChannel.open();
client.configureBlocking(false);
client.register(selector, OP_CONNECT | OP_READ | OP_WRITE);
client.connect(...);
}
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
for (SelectionKey key : selectedKeys) {
SocketChannel channel = (SocketChannel) key.channel();
if (key.isConnectable()) {
// client connected
}
if (key.isWritable()) {
// write to the socket
}
if (key.isReadable()) {
// read from the socket
}
}
}
java.nio.ByteBuffer
●
ByteBuffer.allocate(int capacity)
creates a buffer with the given capacity
●
ByteBuffer.wrap(byte[] array)
creates a buffer with the given underlying array
●
int capacity()
returns the capacity of the buffer
●
int position()
returns the current position of the buffer
●
int limit()
returns the limit of this buffer
●
int remaining()
returns the number of bytes between the current position and the limit
java.nio.ByteBuffer
Position
●
●
Limit
Capacity
Buffer clear()
clears the buffer — sets the limit to the capacity and the position to 0
Buffer flip()
flips the buffer — sets the limit to the current position and sets the position to 0
●
Buffer rewind()
rewinds the buffer — leaves the limit unchanged and sets the position to 0
Using ByteBuffers with channels
// Each client should have a unique buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
// ...
SocketChannel channel = (SocketChannel) key.channel();
if (key.isReadable()) {
channel.read(buffer);
// check the number of bytes in the buffer using
// buffer.position() and act accordingly
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
// data now contains the bytes that were in the buffer
buffer.clear();
}
Communicating through higher level protocols
●
TCP/UDP is fairly low level
●
It can get complicated very fast
●
You will likely be reinventing the wheel a lot of times
●
You are probably better off using a higher level protocol
●
You can either
○ use an existing one or
○ develop your own
Application layer protocols
●
An application layer protocol defines the rules for formatting certain messages
●
It helps solve some complex communication issues
○ authentication
○ authorization
○ metadata
○ message structure
●
Some well known protocols:
○ HTTP — web pages, REST APIs
○ FTP — file transfer
○ SMTP — sending email
○ RTP — real-time audio/video streaming
○ SSH — secure operation of remote services
HTTP
●
One of the most well-known and versatile application layer protocols
●
Initially designed to transmit hypertext (web pages)
●
HTTP has a simple request-response model
○ Client sends a request
○ Server sends a response
○ Rinse and repeat
●
The protocol is stateless, however state is often implemented on top of HTTP
Making an HTTP request by hand
try (
Socket s = new Socket("freegeoip.net", 80);
Writer writer = new OutputStreamWriter(s.getOutputStream(), UTF_8);
BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream(), UTF_8));
) {
writer.write("" +
"GET /json/ HTTP/1.1\r\n" +
"Host: freegeoip.net\r\n" +
"Connection: close\r\n" +
"\r\n");
writer.flush();
String line;
while ((line = reader.readLine()) != null)
System.out.println(line);
}
Making an HTTP request by hand (output)
HTTP/1.1 200 OK
Content-Type: application/json
Vary: Origin
X-Database-Date: Wed, 07 Sep 2016 19:05:53 GMT
X-Ratelimit-Limit: 10000
X-Ratelimit-Remaining: 9993
X-Ratelimit-Reset: 2383
Date: Mon, 03 Oct 2016 06:58:53 GMT
Content-Length: 221
Connection: close
{"ip":"213.180.18.27","country_code":"EE","country_name":"Estonia"
,"region_code":"78","region_name":"Tartu","city":"Tartu","zip_code
":"","time_zone":"Europe/Tallinn","latitude":58.3661,"longitude":2
6.7361,"metro_code":0}
java.net.URL
●
URL(String spec)
creates a URL from the given string
●
URLConnection openConnection()
returns an object representing the connection to the resource referred to by
this URL
●
InputStream openStream()
opens a connection to this URL and returns an input stream for reading from
that connection
java.net.URL example
URL url = new URL("http://freegeoip.net/json/");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream(), UTF_8))) {
String line;
while ((line = reader.readLine()) != null)
System.out.println(line);
}
Output:
{"ip":"213.180.18.27","country_code":"EE","country_name":"Estonia"
,"region_code":"78","region_name":"Tartu","city":"Tartu","zip_code
":"","time_zone":"Europe/Tallinn","latitude":58.3661,"longitude":2
6.7361,"metro_code":0}
java.net.URL example (POST)
URL url = new URL("http://www.asciitohex.com/");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty(
"Content-Type", "application/x-www-form-urlencoded");
try (OutputStreamWriter writer = new OutputStreamWriter(
connection.getOutputStream(), UTF_8)) {
writer.write("b64=SmF2YSBGdW5kYW1lbnRhbHM%3D");
writer.flush();
}
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream(), UTF_8))) {
String line;
while ((line = reader.readLine()) != null)
System.out.println(line);
}
java.net.URL example output (POST)
<!doctype html>
<html lang="en">
...
<textarea name="ascii" id="ascii">Java Fundamentals</textarea>
...
Apache HttpComponents
String response = Request.Get("http://freegeoip.net/json/")
.execute().returnContent().asString();
System.out.println(response);
String response = Request.Post("http://www.asciitohex.com/")
.bodyForm(Form.form()
.add("b64", "SmF2YSBGdW5kYW1lbnRhbHM=").build())
.execute().returnContent().asString();
System.out.println(response);
Jetty
Allows to easily embed an HTTP server into any application.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.3.12.v20160915</version>
</dependency>
Embedded Jetty
class MyHandler extends AbstractHandler {
@Override
public void handle(String path, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Use request.getPathInfo() to access the path
// and request.getQueryString() to access the query string
baseRequest.setHandled(true);
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("Hello");
}
}
Server server = new Server(8080);
server.setHandler(new MyHandler());
server.start();
server.join();
Homework
Implement a simple chat client-server application.
●
●
●
●
●
●
The client has been written for you, you need to write the server
The server must be able to handle multiple connected clients
Whenever a client connects to the server, it first sends its name, the server
must keep track of the names
Whenever the server receives a message from a client, it must prefix the
message with the name of the client and send this prefixed message to all
other connected clients
The server must also send “X has joined” and “X has left” messages to all
clients (a client joins when he connects, and leaves when he disconnects)
The server must have an HTTP endpoint (on port 8080) that returns the
names of all currently connected clients (just a basic list, one name per line)
You’ll find the client here: https://github.com/JavaFundamentalsZT/jf-hw-net
Homework
Here is some sample output from a client.
Enter name: chip
Connecting…
Connected, you can type your messages now
dale has joined
hey dale
dale: hi
let's go get some apples
dale: sure, why not
dale: let's meet at your place, I'll be there in 10
dale has left
/q