Socket, HTTP&HTML
导包
import java.net.*;
import java.io.*;
Get IP
InetAddress inetAddress = InetAddress.getByName(null);
InetAddress inetAddress = InetAddress.getByName("localhost");
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
Define Socket
Socket socket = new Socket(InetAddress.getByName(null), 8080);
ServerSocket serverSocket = new ServerSocket(8080);
Input
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Output
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream)), true);
Sockets
IO流
a Socket is an abstraction of a network interface
Socket API 可用来:
- Send data (bytes)
- Receive data (bytes)
基本概念
流 —— 连接数据或将数据连接到目的地,是一连串的字节流
-
input: 读入数据
-
output:发送数据/写入数据
流可以用来写入任何类型的数据
打开流后要记得关闭
∵A stream is an expensive resource, and there is a limit on the number of streams that you can have open at one time. You should not have more than one stream open on the same file
Java的两种流
byte stream
InputStream
OutputStream
- 高效率
character stream
Reader
Writer
- 需要翻译器
![image-20211012130058601](https://i-blog.csdnimg.cn/blog_migrate/9828146759d751d7f76c9ad3f766da69.png)
![image-20211012130107428](https://i-blog.csdnimg.cn/blog_migrate/6ca36c5e6d2e07c2d3df04f2e5d96433.png)
Socket
基本概念
网络接口的抽象概念,通过Socket API (Application Programming interface) 创建与远程电脑的相连,实现传输数据和接收数据
使用时需要导包:import java.net.*;
需要学会如何写远程机上的文件
Socket是流
- 依靠流操作进行Socket的操作
- Java可以一次处理多个连接,多线程
接收消息缓存器
BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
利用br.readLine()
接收消息,返回值为 String
发送消息
PrintWriter
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(myClient.getOutputStream())), true);
利用printWriter.println()
来发送消息,参数可以是String
也可以是int
MyClient
TCP发送消息
import java.net.*;
import java.io.*;
public class MyClient {
public static void main(String[] args) throws IOException{
Socket myClient = new Socket(InetAddress.getByName(null),8080);
System.out.println("Addr=" + InetAddress.getByName(null));
try{
System.out.println("Socket = " + myClient);
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(myClient.getOutputStream())), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
for(int i = 0; i < 10; i++){
out.println("howdy " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} finally {
myClient.close();
}
}
}
Server
TCP接收消息
import java.net.*;
import java.io.*;
public class MyServer {
public static void main(String[] args) throws IOException{
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept();
System.out.println("Started:" + serverSocket);
try{
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
while (true) {
String str = br.readLine();
if(str.equals("END")) break;
System.out.println((char)Integer.parseInt(str));
out.println(str);
}
} finally {
socket.close();
serverSocket.close();
}
}
}
多线程Socket
ServeOne
import java.net.*;
import java.io.*;
public class ServeOne extends Thread{
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public ServeOne(Socket socket) throws IOException{
this.socket = socket;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), ture);
start();
}
public void run(){
try{
} catch(IOException e){ System.err.println("IO Excpetion");}
finally{
try { socket.close(); }
catch (IOException) { System.err.println("Socket not closed"); }
}
}
}
MultiServer
public class MultiServer{
static final int PORT = 8080;
public static void main(String[] args){
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server started");
try{
while(true){
Socket socket = s.accpet();
try{
new ServerOne(socket);
} catch (IOExcpetion){ socket.close(); }
finally{
serverSocket.close();
}
}
}
}
}
ClientThread
import java.net.*;
import java.io.*;
public class ClientThread extends Thread{
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = couter++;
private static int threadCount = 0;
public static int ThreadCount(){
return threadCount;
}
public ClientThread(InetAddress addr){
System.out.println("Making client" + id);
threadCout++;
try{
socket = new Socket(addr, MultServer.PORT);
} catch (IOException e){
System.err.prinln("Socket Failed");
}
try{
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
start();
} catch(IOExcpetion e){
try{
socket.close();
} catch(IOEcpetion e2){ System.err.println("Socket not closed"); }
}
}
public void run(){
try{
for (int i = 0; i < 5; i++){
out.println("Client " + id + ": " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} catch (IOException e){
System.err.println("IOExcpetion")
} finally{
try{
socket.close();
} catch (IOException e){
System.err.println("Socket not closed");
}
threadCount--;
}
}
}
MultiClient
public class MultiClient{
static final in MAX_THREAD = 40;
public static void main(String[] args) throws IOExcpetion, InterruptedExcption{
InetAddress addr = InetAddress.getByName(null);
while(true){
if (ClientThread.ThreadCount() < MAX_THREAD){
new ClientThread(addr);
}
Thread.currentThread.sleep(100);
}
}
}
IP
每一台电脑都有一个 Unique Identifier —— IP,在网络上唯一标识机器:
- 域名 Domain name
- IP (Internet Protocol) address
127.0.0.1
是本机的IP
每一个IP地址用32-bit number来表示
DNS
域名系统 Domain Name System
负责将域名与其IP地址相匹配
![image-20211012130906237](https://i-blog.csdnimg.cn/blog_migrate/2437de0228844f8cea9fb03b40851a19.png)
本地域名解析
CMD 终端命令
nslookup www.eecs.qmul.ac.uk
Java中获取IP
导包:import java.net.*;
跑异常:Exception
InetAddress
用来存储IP地址,并将其表示为域名或IP地址的形式
static InetAddress.getByName(String)
:存储域名String的IP地址
String getHostName()
:获取域名
String getHostAddress()
:获取IP地址
import java.net.*;
public class InetAddressTest {
public static void main(String[] args) throws Exception {
// 从来。
InetAddress ia;
ia = InetAddress.getLocalHost();// 获得本地主机的InetAddresss对象
// 输出本地主机Ip地址
System.out.println("本地主机IP地址:" + ia.getHostAddress());
// 输出本地主机名
System.out.println("本地主机名:" + ia.getHostName());
// 输出本地主机ip地址
System.out.println("本地主机Ip地址:" + ia.getHostAddress());
// 获得百度网主机的InetAdderss 对象
ia = InetAddress.getByName("www.baidu.com");// 获得主机名指定的InetAddress对象
// 输出百度网主机IP地址
System.out.println("百度网主机ip:" + ia.getHostAddress());
// 输出百度网主机名
System.out.println("百度网主机名:" + ia.getHostName());
}
private static InetAddress InetAddress(String string) {
// TODO Auto-generated method stub
return null;
}
}
本地主机IP地址:27.18.219.15
本地主机名:2012-0101-0949
本地主机Ip地址:27.18.219.15
百度网主机ip:115.239.210.27
百度网主机名:www.baidu.com
服务器模型
Server:听取客户机的请求
Client:发送请求
![image-20211012132159611](https://i-blog.csdnimg.cn/blog_migrate/7126d99b632f7dfd9474d3a9641bd6d4.png)
获取本机地址
Java 程序获取本地地址的对象
InetAddress addr = InetAddress.getByName(null);
InetAddress.getByName("localhost");
InetAddress.getByAddress("127.0.0.1");
端口
ip地址不足以去标识唯一的服务器(一个机器上可以有多个服务)上的每一个服务
Port:
- 对机器上运行的service的特别标识符
- 数值范围:0-65536
端口不是机器上的物理地址,而是软件的抽象
系统服务端口
端口: 0~1023
网络代理端口
8080
通常标识为IP地址:端口号
形式
127.0.0.1:8080
localhost:8080
常用端口
HTTP
基本介绍
什么是HTTP
Hyper Text Transfer Protocol
什么是Web Page
一个URL包含了对象:HTML file,JPEG image
Server and Client
Server: Wait for request. Services requests and provides a response
Client: initiates a request
Browser & Server-side Program
Client (Browser): Send a request for the resource/document addressable by ONE URL
Server: 发送携带文件的response,或者检验用户发送内容的合法性
client-server模式的应用
在全部地方都有应用,许多协议都是为client-server模式服务的:RMI, HTTP, SMTP, TCP
HTTP
Context of HTTP
HTTP 是应用层的协议
依赖与其他层的协议来实现:TCP (Transport layer),IP(Network Layer),MAC(Datalink Layer)
OSI 模型
![image-20211104135957498](https://i-blog.csdnimg.cn/blog_migrate/b157262ef6eef0daa08c469782c3b44d.png)
HTTP and TCP
HTTP是建立在TCP上的
Socket socket = new Socket("10.0.0.1",80)
,利用80端口传输
TCP回顾
TCP = Transmission Control Protocol
Connection-Oriented
三次握手建立连接
四次分手断开连接
Reliable
Byte stream broken up into chunk called segments
![image-20211104140222740](https://i-blog.csdnimg.cn/blog_migrate/6581aecaaaeb5ab7a21f87a5e9a07e86.png)
Detecting Error
Byte Stream Service
TCP是利用字节流来传输数据的
TCP格式
每一个TCP segment有 20 bytes 的header以及data
![image-20211104140343355](https://i-blog.csdnimg.cn/blog_migrate/46537381b148b79cbf06160e9a82938a.png)
TCP port
系统应用使用 0~1023 端口
Web使用80端口
URL
Uniform Resource Locator
格式:
![image-20211104140506901](https://i-blog.csdnimg.cn/blog_migrate/47b98278753d962a8327a75bc8ea8daf.png)
filename#section
指向目录下的特定路径
- 如果忽略,将指向
index.html
Section属性值的是HTML文件中的named anchor,使用name属性来标记
<A name="123">...</A>
http://sunsite.unc.edu/javafaq/javafaq.html#abc123
其余使用URL的protocol
![image-20211104140729401](https://i-blog.csdnimg.cn/blog_migrate/bcc94e2d27e9263a54041a31f0e7423c.png)
HTTP协议Detail
HTTP指明了
- 客户端和服务器如何建立连接
- 客户端如何向服务器请求数据
- 服务器如何回应请求
- 如何关闭连接
是stateless的协议:不记住任何从前的连接
Initiating a connection
HTTP/1.0, HTTP/1.1, HTTP/2.0 都是用TCP来建立连接的
浏览器和服务器都是使用 (TCP) socket 接口
- 客户端写HTTP请求到Socket中并且读取socket中的http response
- 服务端从Socket中读取HTTP请求并写response
连接的端口可以通过URL来指定
- 如果没有指定,默认为80端口
HTTP step by step
- 发送TCP connection
- HTTP 客户端发送请求给服务器,请求中包含 path name
- HTTP 服务器从socket中接收到请求
- 从数据库中检索请求
- 封装object进入HTTP response message中
- 发送response给Client
- HTTP 服务器告诉TCP关闭连接
- 客户端接收到消息,关闭TCP连接
HTTP methods: GET and POST
两个HTTP请求方法:
GET
-
请求URL中包含的查询字符串
-
幂等:多个请求与单个请求具有相同的效果
-
可缓存的
POST
-
放置在 body of the HTTP request 中的查询字符串
-
非幂等:POST两次就是两次
-
当例如想要改变服务器端的数据时使用
GET的例子
![image-20211104141928085](https://i-blog.csdnimg.cn/blog_migrate/2b9086f33c8d3b883fe2cd7dd5f970b5.png)
HTTP request message format
![image-20211104143306890](https://i-blog.csdnimg.cn/blog_migrate/fb54041bf41e45130c6bb928e2a99cc9.png)
HTTP response
![image-20211104143343404](https://i-blog.csdnimg.cn/blog_migrate/19b585cb395ba2fb7d5ca041a0c4c568.png)
HTTP response message format
![image-20211104143420581](https://i-blog.csdnimg.cn/blog_migrate/f6768187ed3731b1f8d9e2ded640c1a5.png)
Pipeline
从**HTTP 1.1才开始有**,允许一次HTTP连接中发送多次请求
HTTP method
![image-20211104143613260](https://i-blog.csdnimg.cn/blog_migrate/7b27be3c2c160d6b5e0e4a5b6c85841f.png)
重要的Header
Cache-Control
- Holds instructions for caching in requests and response
Etag
- 对特定版本的资源的标识符
Vary
- 允许定义是否为后续请求返回缓存的响应
Data
- 显示被响应时的时间戳
Expires
- 显示resouce被浏览时的时间戳
Pragma
- 通常使用在解除Caching
More HTTP header
Content-Length:显示资源有多少字节
Content-Encoding:显示资源如何编码
Content-type:MIME type of object例如text/html
Set-Cookie header
Cookies包含了四个需要考虑部分
- Response message中的cookie header line
- Request message中的cookie header line
- 用于保存用户的host信息,通常被browser保存
- 网页背后的数据库
![image-20211104144711468](https://i-blog.csdnimg.cn/blog_migrate/75c1fbc0b6e18686d53f41e9749d75b0.png)
HTTPS
HTTP Secure
- 用TLS协议跑,不用TCP
- Port 443
全部的payload(Header及Payload)都是encrypted
授权服务器
HTTPS URL
https://xxxxxx
HTTPs的问题
增加开销(overhead)
- 只要必要时使用
增加了连接建立时间:
- TCP setup + TLS handshake
增加了页面加载的时间
HTTP 2.0
目的减少页面加载时间
基于谷歌SPDY打造
- 谷歌打造的,应用在谷歌的服务器上
Multiplexing
- 不同的资源可以平行的request喝fetched,防止了head of line的blocking
Universal encryption
- 全部默认为加密
Server push/hint
- 服务器可以在收到request之前push resource
- 可以提醒client fetch resources
Content prioritisation
- 可以给resources赋优先度