一、网络基础
1.1、计算机网络
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
目的
数据交换、资源共享、信息传递
1.2、网络通信的要素
如何实现网络上的通信?
(1)通信双方地址:
- ip
- 端口号
(2)规则:网络通信的协议:
TCP/IP参考模型:
HTTP:超文本传输协议
FTP:文件上传协议
1.3 、IP
ip地址:inetAddress,为实现网络中不同计算机之间的通信,每台机器都必须有一个唯一的标识。
- 唯一定位一台网络上计算机
- 127.0.0.1:本机loaclhost
1.4、端口
端口表示计算机上的一个程序的进程
- 不同的进程有不同的端口号!用来区分软件!
- 被规定0-65535
1.5、通信协议
通信协议是指双方实体完成通信或服务所必须遵循的规则和约定
(1)TCP协议
- TCP:用户传输协议
- 建立连接(打电话)
- TCP是面向连接的协议,因此每个TCP连接都有3个阶段:连接建立、数据传送和连接释放
- 三次握手与四次挥手
(2)UDP协议
- UDP:用户数据报协议,它是TCP/IP协议簇中无连接的运输层协议。
- 不连接(发短信)
(3)TCP与UDP的区别
- TCP基于连接,UDP是无连接的;
- 对系统资源的要求,TCP较多,UDP较少;
- UDP程序结构较简单;
- TCP是流模式,而UDP是数据报模式;
- TCP保证数据正确性,而UDP可能丢包;TCP保证数据顺序,而UDP不保证;
(4)HTTP协议
HTTP协议是基于TCP协议之上的请求/响应式协议,HTTP请求报文由请求行、首部行和实体主体组成,由浏览器发送给服务器。
Http协议定义了很多与服务器交互的方法,最基本的4种,分别是get,post,put,delete,
Get和Post请求模式的区别
- get一般用于获取/查询资源信息,而post一般用于更新资源信息。
- get提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&连接,如:https://www.baidu.com?nameasdjhasj&pswword=sjdsdsad,post方法是把数据放在HTTP包的body中
- get提交的数据大小有限制(URL的最大长度是2048个字符),(浏览器对URL的长度有限制),而post方式提交的数据没有限制
- get方式需要使用Request.QueryString来获取变量的值,而post方式通过Request.From;来获取变量的值
- get方式提交数据,会带来安全问题,比如一个登陆页面,通过get方式提交数据,用户名和密码会出现在URL中,如果页面可以缓存或者其他人可以访问这台机器,就可以从历史记录中获取该用户的用户名和密码了
HTTP和HTTPS的区别
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单来说就是HTTP的安全版
- https协议需要到ca申请证书,一般免费证书很少,需要缴费。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;https协议是有ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
二、Java中网络相关API的应用
2.1、InetAddress类
InetAddress类的对象用于IP地址和域名,该类提供以下方法:
getByName(String s):获得一个InetAddress 类的对象,该对象中含有主机的IP地址和域名;
String getHostName():获取InetAddress对象的域名;
String getHostAddress():获取InetAddress对象的IP地址;
getLocalHost():获得一个InetAddress对象,该对象含有本地机的域名和IP地址。
代码体现
public class Test01 {
/**
* InetAddress类的练习
* @param args
*/
public static void main(String[] args) throws UnknownHostException {
//获取本机的InetAddress实例
InetAddress inetaddress = InetAddress.getLocalHost();
System.out.println("计算机名:"+inetaddress.getHostName());
System.out.println("IP地址:"+inetaddress.getHostAddress());
System.out.println(inetaddress);
System.out.println("--------------------------------------------");
//根据计算机名获取InetAddress实例
InetAddress address = InetAddress.getByName("XXX");
System.out.println("计算机名:"+address.getHostName());
System.out.println("IP地址:"+address.getHostAddress());
}
}
2.2、URL类
统一资源标识符(Uniform Resource Identifier ,URL)是采用一种特定语法标识一个资源的字符串。所标识的资源可能是服务器上的一个文件。Java的URL网络类可以让你通过URL去练级网络服务器并获取资源。
URL的格式如下:
protocol://host:port/path?query#fragment
protocol(协议)可以是HTTP,HTTPS,FTP和File,port为端口号,path为文件路径及文件名。
代码体现
public class Test02 {
/*
* URL类的联系
*/
public static void main(String[] args) {
try {
//创建一个URL实例
URL url1 = new URL("http://www.baidu.com");
//?后面表示参数,#后面表示锚点
URL url2 = new URL(url1,"/index.html?username=tom#test");
System.out.println("协议:"+url2.getProtocol());
System.out.println("主机:"+url2.getHost());
//如果未指定端口号,则使用默认的端口号,此时getPort()方法返回值为-1
System.out.println("端口"+url2.getPort());
System.out.println("文件路径:"+url2.getPath());
System.out.println("文件名:"+url2.getFile());
System.out.println("相对路径:"+url2.getRef());
System.out.println("查询字符串:"+url2.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
三、Socket通信
3.1、 Socket概述
Socket 也叫“套接字”,是两台机器间通信的端点,也就是成对存在才能通信。
TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
Socket,实际上是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,它只是提供了一个针对TCP或者UDP编程的接口。socket是对端口通信开发的工具,它要更底层一些。
3.2、通过Socket实现TCP编程
TCP协议是面向连接,有序可靠的,以字节流的方式发送数据
1、基于TCP协议实现网络通信的类:
- 服务器端的ServerSocket类
- 客户端的Socket类
2、Socket通信实现步骤:
- 服务器端
(1)创建ServerSocket对象,绑定监听端口
(2)通过accept()方法监听客户端请求
(3)建立连接后,通过输入流读取客户端发送的请求信息
(4)通过输出流向客户端发送响应信息
(5)关闭相关资源
- 客户端
(1)创建Socket对象,指明需要连接的服务器的地址和端口号
(2)建立连接后。通过输出流向服务端发送请求信息
(3)通过输入流获取服务端响应的信息
(4)关闭相关资源
代码体现:
/*
* 基于TCP协议的Socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
//1、创建一个服务器端Socket,即SeverScoket,制定绑定的端口,并监听此端口
ServerSocket serverScoket = new ServerSocket(2221);
//2、调用accept()方法开始监听,等待客户端的连接
Socket socket = serverScoket.accept();
//3、获取输入流,并读取客户信息
InputStream is = socket.getInputStream();//字节输入流
InputStreamReader isr = new InputStreamReader(is);//将字节流转化为字符流
BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
String info = null;
while((info=br.readLine())!=null){
System.out.println("我是服务器,客户端说:"+info);
}
socket.shutdownInput();//关闭输入流
//4、获取输出流,向客户端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
pw.write("您好!欢迎登陆");
pw.flush();
socket.shutdownOutput();//关闭输出流
//5、关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverScoket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 基于TCP协议的Socket通信,实现用户登录
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
//1、创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("127.0.0.1",2221);
//2、获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
pw.write("用户名:admin;密码:123");
pw.flush();
socket.shutdownOutput();//关闭输出流
//3、获取输入流,并读取客户信息
InputStream is = socket.getInputStream();//字节输入流
InputStreamReader isr = new InputStreamReader(is);//将字节流转化为字符流
BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
String info = null;
while((info=br.readLine())!=null){
System.out.println("我是客户端,服务器端说:"+info);
}
socket.shutdownInput();//关闭输入流
//4、关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、多线程服务器
应用多线程来实现服务器与多客户端之间的通信
实现步骤:
(1)服务器端创建ServerSocket对象,循环使用accept()方法监听客户端请求
(2)客户端创建Socket对象,并请求与服务端连接
(3)服务器端接收客户端请求,创建Socket与该客户建立专线连接
(4)建立连接的两个Socket在一个单独的线程上对话
(5)服务器端继续等待新的连接
代码体现:
/*
* 服务器线程处理类
*/
public class ServerThread extends Thread {
//和本线程相关的Socket
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
//线程执行的操作,返回客户端的请求
public void run(){
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
PrintWriter pw = null;
try {
//获取输入流,并读取客户信息
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String info = null;
while((info=br.readLine())!=null){
System.out.println("我是服务器,客户端说:"+info);
}
socket.shutdownInput();//关闭输入流
//获取输出流,向客户端发送信息
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.write("您好!欢迎登陆");
pw.flush();
socket.shutdownOutput();//关闭输出流
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
//关闭资源
if (pw !=null)
pw.close();
if (os !=null)
os.close();
if (br !=null)
br.close();
if (isr !=null)
isr.close();
if (is !=null)
is.close();
if (socket !=null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 基于TCP协议的Socket通信,实现用户登录
* 服务器端
*/
public class Server {
public static void main(String[] args) {
try {
//创建一个服务器端Socket,即SeverScoket,制定绑定的端口,并监听
ServerSocket serverScoket = new ServerSocket(2221);
Socket socket = null;
//记录客户端的数量
int count = 0;
System.out.println("服务器即将启动,等待客户端的连接");
//循环监听等待客户端的连接
while(true){
//调用accept()方法开始监听,等待客户端的连接
socket = serverScoket.accept();
//创建一个新的线程
ServerThread serverThread = new ServerThread(socket);
//启动线程
serverThread.start();
count++;//统计客户端的数量
System.out.println("客户端的数量:"+count);
InetAddress inetAdderss = socket.getInetAddress();
System.out.println("当前客户端的IP:"+inetAdderss.getHostAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 基于TCP协议的Socket通信,实现用户登录
* 客户端
*/
public class Client2 {
public static void main(String[] args) {
try {
//1、创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("127.0.0.1",2221);
//2、获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
pw.write("用户名:tom;密码:123");
pw.flush();
socket.shutdownOutput();//关闭输出流
//3、获取输入流,并读取客户信息
InputStream is = socket.getInputStream();//字节输入流
InputStreamReader isr = new InputStreamReader(is);//将字节流转化为字符流
BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
String info = null;
while((info=br.readLine())!=null){
System.out.println("我是客户端,服务器端说:"+info);
}
socket.shutdownInput();//关闭输入流
//4、关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3、通过Socket实现UDP编程
UDP协议是无连接,不可靠无序的,以数据报作为数据传输的载体
1、基于UDP协议实现网络通信的类:
- DatagramPacket:数据报包
- DatagramSocket:进行服务区端与客户端通信的类
2、Socket通信实现步骤:
- 服务器端
(1)创建DatagramSocket对象,指定端口号
(2)创建DatagramPacket
(3)接收客户端发送的数据信息
(4)读取数据
- 客户端
(1)定义发送信息
(2)创建DatagramPacket,包含将要发送的信息
(3)创建DatagramSocket
(4)发送数据
(5)关闭相关资源
代码体现:
/*
* 服务器端,实现基于UDP的用户登录
*/
public class UDPServer {
public static void main(String[] args) throws IOException {
/*
* 向客户端接收数据
*/
//1、创建服务器端DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(2222);
//2、创建数据报,用于接收客户端发送的数据
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
//3、接收客户端发送的数据
System.out.println("服务器端已经启动,等待客户端发送数据");
socket.receive(packet);//此方法在接受到数据报之前会一直阻塞
//4、读取数据
String info = new String(data,0,packet.getLength());
System.out.println("我是服务器,客户端说:"+info);
/*
* 向客户端响应数据
*/
//1、定义客户端的地址,端口号,数据
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "您好!欢迎登录".getBytes();
//2、创建数据报,包含相应的数据信息
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
//3、响应客户端
socket.send(packet2);
//4、关闭资源
socket.close();
}
}
/*
* 客户端,实现基于UDP的用户登录
*/
public class UDPClient {
public static void main(String[] args) throws IOException {
/*
* 向服务器端发送数据
*/
//1、定义客户端的地址,端口号,数据
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 2222;
byte[] data = "用户名:admin;密码:123".getBytes();
//2、创建数据报,包含相应的数据信息
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
//3、创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
//4、向服务器端发送数据报
socket.send(packet);
/*
* 接收服务器端响应的数据
*/
//1、创建数据报,用于接收客户端发送的数据
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
//2、接收客户端发送的数据
socket.receive(packet2);//此方法在接受到数据报之前会一直阻塞
//3、读取数据
String reply = new String(data2,0,packet2.getLength());
System.out.println("我是客户端,服务器端说:"+reply);
//4、关闭资源
socket.close();
}
}