序
这一模块中主要学习Web后端开发,JavaEE的核心内容包含了很多内容,我们把它分为7个章节来进行学习:
- 网络编程基础 ——(一)
- Http协议——(二)
- JavaEE体系概况
- 服务器技术
- Servlet开发web应用
- JSP开发web应用
- 整合开发
前三个章节理论性偏强,但是如果我们想要学好这一块,想要出拳有力,马步扎得稳是必然的。我会将主要需要了解的知识点罗列出来,希望能看到我这一个系列博客的小伙伴们能够细细去理解这前三章的知识。而从第四章节开始,我们就开始真正动手去实现Web应用的开发。
01 网络编程基础
web开发与网络编程
- web的本意是蜘蛛网和网的意思,在网页设计中我们称为网页。现在广泛译作网络、互联网等技术领域。表现为三种形式:
- 超文本(hypertext)
- 超媒体(hypermedia)
- 超文本传输协议(HTTP)
- web开发是一种特定条件下的网络编程
- C/S架构与B/S架构
- web开发的目的及意义
- 根本目的:实现端对端的信息交互(通信)
- 特点:为B/S架构而生
- 终极目的:超级APP
网络七层模型
经历了漫长的发展,互联网逐渐成为了通信的主要力量,如同传统的通信业务一样,人们建立了一套利用互联网进行可靠通信的模型。成为OSI七层模型:
OSI七层模型 | 邮递信件体系 |
---|---|
第七层:应用层 实现终端的信息交换。 | 读取信件内容。 |
第六层:表示层 信息解释的前段操作,如加密,解密,压缩等。 | 信件已经送达,拆开信封。 |
第五层:会话层 按照在应用进程之间约定的原则,按照正确的顺序收发数据,进行各种形态的对话。 | 信件已到达,快递小哥开始安排送件,并联系收件方如何接货。 |
第四层:传输层 端开放系统之间的数据传送控制层。主要功能是端开放系统之间数据的收妥确认。 | 选择运输方式,空运,陆运,汽运等。 |
第三层:网络层 控制子网的运行,如逻辑编址,分组传输,路由选择。 | 送达集散中心,规划传递路径。 |
第二层:数据链路层 物理寻址,数据链路的建立、拆除,对数据的检错、纠错是数据链路层的基本任务。 | 网点揽收分拣,并检查地址有没有填写,是否能送达。 |
第一层:物理层 提供用于建立、保持和断开物理连接的机械的、电气的、功能的和过程的条件。 | 建立各个投递和接收网点,形成物理传输网络。 |
通信协议
- 物理层:
- 以太网,调制解调器,电力线通信(PLC),SONET/SDH,G.709,光导纤维,同轴电缆,双绞线等。
- 数据链路层:
- Wi-Fi(IEEE 802.11),WiMAX(IEEE 802.16),ARP,RARP,ATM,DTM,令牌环,以太网,FDDI,帧中继,GPRS,EVDO,HSPA,HDLC,PPP,L2TP,PPTP,ISDN,STP等。
- 网络层协议:
- IP(IPv4,IPv6),ICMP,ICMPv6,IGMP,IS-IS,IPsec等。
- 传输层协议:
- TCP,UDP,TLS,DCCP,SCTP,RSVP,OSPF等。
- 应用层协议:
- DHCP,DNS,FTP,Gopher,HTTP,IMAP4,IRC,NNTP,XMPP,POP3,SIP,SMTP,SNMP,SSH,TELNET,RPC,RTCP,RTP,RTSP,SDP,SOAP,GTP,STUN,NTP,SSDP,BGP,RIP,ED2K等。
我们现在举两个简单的例子,回顾一下两个典型的传输层协议的编程——TCP编程和UDP编程。
TCP服务端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP协议服务器,面向连接,发送消息之前,双方需要建立稳定可靠的连接(类似打电话)<br/>
* 传输层协议:解决双方链路连接上的问题,消息格式没有明确定义
* @author 青葉
*
*/
public class TCPServer {
//建立ServerSocekt,并设置其端口号
private ServerSocket serverSocket;
public static final int port = 8899;
public TCPServer() {
try {
serverSocket = new ServerSocket(port);
System.out.println("服务器在" + port + "端口上启动成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 处理消息
*/
public void handleMsg() {
//建立服务器端的Socket
Socket socket;
OutputStream outputStream;
try {
System.out.println("等待客户端连接...");
socket = serverSocket.accept();
System.out.println("客户端接入成功!");
//接收客户端消息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(bufferedReader.readLine());
//向客户端传递消息
outputStream = socket.getOutputStream();
outputStream.write("hello".getBytes());
outputStream.flush();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TCPServer myServer = new TCPServer();
myServer.handleMsg();
}
}
TCP客户端:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
/**
* TCP协议客户端
* @author 青葉
*
*/
public class TCPClient {
public static final String IP = "127.0.0.1";
public static final int port = 8899;
private Socket socket;
public TCPClient() {
try {
socket = new Socket(IP, port);
System.out.println("客户端启动成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void handleMsg() {
InputStream inputStream;
OutputStream outputStream;
try {
//向服务器发送消息
outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("你好服务器!" + "\n");
bufferedWriter.flush();
//接收服务器消息
inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(bufferedReader.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TCPClient myClient = new TCPClient();
myClient.handleMsg();
}
}
在TCP编程这里,大家一定要注意的一点是发送消息时的时序问题,getInputStream会导致当前线程挂起,如果时序弄错,两边都在getInputStream,就变成你等我,我等你,两边互不相让,谁都执行不下去。还有一点是在服务端接收客户端消息的时候,buffer.readLine方法是读取一行的信息,所以这一行中“\n”这个字符必不可少。如果少了“\n”,readLine接收不到结束消息,会造成这一行永远都读不完。其实这个“\n”的思想,在这里就已经可以理解为一个我们自定义的简单的关于字符串的应用层协议了。
UDP客户端:
/**
* UDP服务器实现,面向数据报,不需要稳定的连接(类似短信)
* @author 青葉
*
*/
public class UDPServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(12345);
while (true) {
byte data[] = new byte[1024];
//创建一个空的DatagramPacket对象
DatagramPacket packet = new DatagramPacket(data, data.length);
//使用receive方法接收客户端所发送的数据,如果客户端没有发送数据,该进程就停滞在此处
socket.receive(packet);
String result = new String(packet.getData(), packet.getOffset(), packet.getLength());
System.out.println("result ---> " + result);
}
}
}
UDP客户端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP客户端
* @author 青葉
*
*/
public class UDPClient {
@SuppressWarnings("resource")
public static void main(String[] args) {
try {
//首先创建一个DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
//创建一个InetAddress
InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
String str = "hello"; //即将传输的数据
byte data[] = str.getBytes(); //把传输内容分解成字节
//创建一个DatagramPacket对象,并指定要将这个数据包发送到网络当中的哪一个地址及其编口号
DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, 12345);
//调用socket对象的send方法,发送数据
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们最后举一个应用层协议的小案例——HttpClient。它的主要步骤以及实现代码如下:
- 导入必要的jar包
- commons-codec-1.9.jar
- commons-logging-1.2.jar
- httpclient-4.5.3.jar
- httpcore-4.4.6.jar
- 创建HttpClient对象
- 创建请求对象
- 处理响应对象
import java.io.IOException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class HTTP {
public static void main(String[] args) {
//创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建Http请求对象
HttpPost httpPost = new HttpPost("http://www.baidu.com");
//处理响应对象
try {
//获取响应消息
CloseableHttpResponse response = httpClient.execute(httpPost);
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
归根结底这个案例其实还是对底层协议进行了包装,HTTP协议是建立在TCP协议之上的,所以它底层都逃离不了这些Socket编程。
网络编程基础就到这里,下一章节我们来详细学习HTTP协议的内容。