1 网络基础
1.1 什么是网络
把分布在不同地理区域的计算机、外部硬件设备用通信线路互连成一个规模大、功能强的网络系统,使系统的各个终端可以方便地互相传递信息,共享硬件、软件、数据信息等资源。
按照覆盖范围大小,网络可以分为:
1)局域网(Local Area Network,LAN)
是指在某一区域内由多台计算机互联而成的计算机组。一般是几千米以内(如学校、工厂、公司)的封闭型网络。局域网可以实现文件管理、应用软件共享、打印机共享、工作组内的日程安排、电子邮件等功能。
2)城域网(Metropolitan Area Network,MAN)
是在一个城市范围内建立的计算机通信网。其传输媒介主要采用光缆。
3)广域网(Wide Area Network,WAN)
也称远程网,所覆盖的范围从几十公里到几千公里,能够连接多个城市或国家。广域网的通信子网主要使用分组交换技术,可以利用公用分组交换网、卫星通信网和无线分组交换网。如因特网(Internet)是世界范围内最大的广域网。
1.2 网络通信原理
1)IP地址:唯一标识网络上的每一台计算机
2)端口号:端口号是网络应用程序的区分标识,有了端口,计算机就可以知道将收到的数据传给哪一个应用程序。端口号的范围从0~65535。其中0~1024是系统使用或保留的端口
主机怎么区分不同的网络服务或网络应用程序呢?只靠IP地址行吗?实际上是通过“IP地址+端口号”来区分
3)网络通信协议:不同的计算机之间必须使用相同的通信协议才能进行通信。
比如找人聊天
要找的人在哪住 (IP地址)
具体的门牌号 (端口)
用什么语言聊天?说英文你懂吗?不懂是吧,那我们还是都说中文吧(协议)
1.3 网络模型 了解
1.3.1 OSI参考模型
OSI(Open System Interconnect),即开放式系统互联,是ISO组织在1985年研究的网络互联模型。该体系结构标准定义了网络互联的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层和应用层)。
应用层:负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)。
表示层:负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
会话层:负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)。
传输层:负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)。
网络层:负责定义了能够标识所有网络节点的逻辑地址。(IP地址)。
链路层:在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)。
物理层:为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
1.3.2 TCP/IP模型
TCP/IP模型是因特网使用的参考模型,基于TCP/IP的参考模型将协议分成四个层次。
该模型中最重要的两个协议是TCP和IP协议。
应用层:负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
传输层:负责传送文本数据,主要协议是TCP、UDP协议。
网络层:负责分配地址和传送二进制数据,主要协议是IP协议。
接口层:负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等。
2 网络通信协议
要使计算机连成的网络能够相互通信,需要对数据传输速率、传输代码、代码结构、传输控制步骤、出错控制等制定一组标准,这一组共同遵守的通信标准就是网络通信协议。不同的计算机之间必须使用相同的通信协议才能进行通信。
TCP/IP(Transmission Control Protocol/Internet Protocol 传输控制协议/网际协议)协议是使用最为广泛的传输层协议。TCP负责数据的打包,收集、还原,并发现是否存在传输问题。IP规定每个数据包应该去的地方。
UDP(User Datagram Protocol)用户数据报协议
UDP | TCP | |
连接可靠性 | 啥都不管就发 | “三次握手” 比较可靠 |
数据大小限制 | 数据报 不能超过64K | IO流 无限制 |
传输效率 | 占用资源少,传输快 | 占用资源大,传输慢 |
2.1 Socket套接字编程
套接字是网络编程中的一种通信机制
两个应用程序可以通过一个双向的网络通信链路实现数据交换,这个双向链路的一端称为一个Socket。
Socket在应用程序中创建,通过绑定机制告诉自己所对应的IP地址和端口号。
一个程序将一段信息写入Socket中,该Socket将这段信息发送给另一端的Socket,另一端的Socket接收后,再由应用程序提取其中的数据。
2.2 java.net包
Java语言支持网络通信编程,提供了java.net包供程序开发人员使用,该包常用的类有:
1)InetAddress类,用于表示或存储计算机IP地址
方法 | 描述 |
public static InetAddress getLocalHost() | 获得存有本机IP的InetAddress对象 |
public static InetAddress getByName(String host) | 获得存有其他电脑IP地址的InetAddress对象 |
public String getHostName() | 从InetAddress对象中获得主机名 |
public String getHostAddress() | 从InetAddress对象中获得IP地址 |
2)UDP协议相关
DatagramPacket类,用于表示封装数据的报文类
DatagramSocket类,用于表示收发数据的某一端的Socket
3)TCP协议相关
ServerSocket类,用于表示服务器端Socket
Socket类,用于表示客户端Socket
2.3 UDP编程
UDP(User Datagram Protocol)用户数据报协议,是一种无连接的传输层协议,提供简单、不可靠信息传送服务。
UDP不能保证数据的可靠传输,虽然不用先建立连接,但效率高
UDP网络程序由消息发送方与消息接收方两部分组成,实现起来比较简单
2.3.1 UDP编程使用的类
1)DatagramPacket类
用于表示封装数据的报文类
方 法 | 描 述 |
public DatagramPacket(byte[] buf,int length) | 构造DatagramPacket对象时,用来接收长度为 length 的数据并存到byte数组中 |
public DatagramPacket(byte[] buf,int length,InetAddress address,int port) | 构造DatagramPacket对象时,用来将长度为 length 的数据发送到指定主机上的指定端口号 |
public InetAddress getAddress() | 获得另一端Socket的地址 |
public int getPort() | 获得另一端Socket的端口号 |
2)DatagramSocket类
用于表示收发数据的某一端的Socket
方法 | 描述 |
public DatagramSocket() | 构造DatagramSocket对象,不指定监听的端口,一般用于发送端 |
public DatagramSocket(int port) | 构造DatagramSocket对象,同时指定监听的端口,一般用于接收端 |
public void send (DatagramPacket p) | 发送数据报 |
public void receive(DatagramPacket p) | 接收数据报,在接收到数据报之前一直阻塞 |
public void close() | 关闭此Socket |
public InetAddress getLocalAddress() | 获得套接字的本地IP地址对象 |
public int getLocalPort() | 获得套接字本地端口号 |
2.3.2 发送端和接收端处理流程
1)发送端
1.创建DatagramSocket对象用来发送数据
2.准备好数据
3.创建DatagramPacket数据报对象用来存储数据
4.发送
5.关闭DatagramSocket对象
2)接收端
1.创建DatagramSocket对象用来接收数据
2.创建DatagramPacket数据报对象用来存储数据
3.接收
4.读取数据
5.关闭DatagramSocket对象
2.3.3 演示代码
接收端
public class UDPReceiver {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//接收数据的DatagramSocket,接收端需要指定端口号
DatagramSocket ds = new DatagramSocket(8888);
//接收数据处理
byte[] receBuff = new byte[1024];
DatagramPacket pd = new DatagramPacket(receBuff, receBuff.length);
//接收数据
ds.receive(pd);//阻塞,直到收到数据
//从DatagramPacket对象中获取接收的数据
System.out.println(new String(pd.getData(), 0, pd.getLength()));
//关闭socket
ds.close();
}
}
发送端
public class UDPSender {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//建立DatagramSocket对象
DatagramSocket ds = new DatagramSocket();
//设置发送的信息
String str = "Hello! I'm client";
InetAddress ia = InetAddress.getByName("127.0.0.1");
//新建发送数据的DatagramPacket对象
//四个参数的构造函数:发送数据的字节数组表示,数据的长度,发送到某台机器的InetAddress对象,端口号
DatagramPacket dp = new DatagramPacket(
str.getBytes(),
str.getBytes().length,
ia, 8888);
//发送数据
ds.send(dp);
//关闭socket
ds.close();
}
}
2.4 TCP编程
TCP是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接,对发送数据的大小无限制。但是占用资源大,效率低。
2.4.1 TCP编程使用的类
1)ServerSocket类
用于表示服务器端Socket
方法 | 描述 |
public ServerSocket(int port) | 创建ServerSocket实例,指定端口 |
public Socket accept() | 创建一个Socket(手机)并等待和监听客户端连接请求,在没收到客户端连接请求前,此方法一直阻塞 |
public void close() | 关闭ServerSocket,一般不关闭 |
2)Socket类
用于表示客户端Socket
方法 | 描述 |
public Socket(String host , int port) | 构造Socket对象,同时指定要连接服务器的主机名和端口号 |
public Socket(InetAddress addr , int port) | 构造Socket对象,同时指定要连接服务器的IP地址和端口号 |
public InputStream getInputStream() | 获得套接字的输入流,相当于接收消息,可阻塞 |
public OutputStream getOutputStream() | 获得套接字的输出流,相当于发送消息,可阻塞 |
public void close() | 关闭此Socket |
2.4.2 开发流程
1.服务器程序创建一个ServerSocket,然后调用accept方法等待客户端来连接
2.客户端程序创建一个Socket并请求与服务器建立连接
3.服务器接收客户的连接请求,accept方法创建一个新的Socket与该客户建立专线连接
4.刚才建立了连接的两个Socket开始双向通信
2.4.3 代码演示
服务端
public class TCPServer {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 服务端使用的socket ,创建一个监听
ServerSocket listen = new ServerSocket(8888);
// 等待连接,会阻塞。连接连接后,会返回一个socket对象
Socket s = listen.accept();
// 得到输入流,是为了读取客户端传输的数据
InputStream in = s.getInputStream();
byte[] recv = new byte[1024];
int len = in.read(recv);
System.out.println(new String(recv, 0, len));
// 向客户端写数据,获取输出流
OutputStream out = s.getOutputStream();
out.write("no money".getBytes());
// 关闭连接
// in.close();
// out.close();
s.close();
}
}
客户端
public class TCPClient {
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
// 建立客户端socket,用来连接服务端
Socket s = new Socket("127.0.0.1", 8888);
// 获得输出流,向服务端写入数据
OutputStream out = s.getOutputStream();
out.write("nihao".getBytes());
// out.close();//网咯通信过程中,关闭流,相当于关闭socket,可能会引起异常
InputStream in = s.getInputStream();
byte[] buff = new byte[1024];
int len = in.read(buff);
System.out.println(new String(buff, 0, len));
// in.close();
// 关闭连接
s.close();// socket关闭,输入输出流也就关闭了
}
}
2.4.4 实现文件上传
客户端读取文件内容,以IO流的形式,将数据发送给服务端;
服务端接收数据,以IO流的形式将数据存储到服务端的文件中
1)客户端:
package com.qfedu.upload;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 1. 读取文件
FileInputStream in = new FileInputStream("D:/a.txt");
// 2. 启动Socket
Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 8848);
// 3. 通过Socket获取OutputStream对象,发送数据给服务器
OutputStream outputStream = socket.getOutputStream();
int length = -1;
byte[] buf = new byte[1024];
// 4. 读取数据,发送数据
while ((length = in.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}
// 5. 关闭资源
socket.close();
in.close();
}
}
2)服务端
package com.qfedu.upload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 1. 开启Socket服务端
ServerSocket serverSocket = new ServerSocket(8848);
Socket socket = serverSocket.accept();
// 2. 创建文件输出流对象,保存文件
FileOutputStream out = new FileOutputStream("D:/aa.txt");
// 3. 通过Socket获取对应的输入流对象
InputStream inputStream = socket.getInputStream();
// 4. 读取数据后写入文件
int length = -1;
byte[] buf = new byte[1024];
while ((length = inputStream.read(buf)) != -1) {
out.write(buf, 0, length);
}
// 5. 关闭资源
out.close();
socket.close();
}
}
附录
命令
ipconfig
查看本地网络配置
ping
用来检测一帧数据从当前主机传送到目的主机所需要的时间。来确定两台计算机之间的网络是否连通。
TCP三次握手和四次挥手 (了解)
三次握手
为了保证客户端和服务器端的可靠连接,TCP建立连接时必须要进行三次会话,也叫TCP三次握手,进行三次握手的目的是为了确认双方的接收能力和发送能力是否正常。
第一次握手:客户端发送一个syn包给服务器,并进入同步已发送(SYN_SEND)状态,等待服务器确认。这个时候SYN=1,seq=x。
第二次握手:服务器收到客户端发来的syn包,然后进行确认,同时自己也发送一个SYN+ACK包给客户端,然后服务器进入同步收到(SYN_RECV)状态。这个时候SYN=1,ACK=1,seq=y,ack=x+1。
第三次握手:客户端收到服务器的SYN+ACK包后,向服务器发送确认包ACK,这个包发送完毕后,客户端和服务器进入到已建立连接(ESTABLISHED)状态,完成三次握手,开始传输数据。这个时候ACK=1,seq=x+1,ack=y+1。
四次挥手
终止TCP连接需要四次挥手
第一次挥手:当数据传输结束以后,客户端的应用进程发出连接释放报文段,并停止发送数据,其首部:FIN=1,seq=u。
第二次挥手:服务器端收到连接释放报文段之后,发出确认报文,其首部:ACK=1,seq=v,ack=u+1。此时本次连接就进入了半关闭状态,客户端不再向服务器发送数据。而服务器端仍会继续发送。
第三次挥手:若服务器已经没有要向客户端发送的数据,其应用进程就通知服务器释放TCP连接。这个阶段服务器所发出的最后一个报文的首部应为:FIN=1,ACK=1,seq=w,ack=u+1。
第四次挥手:客户端收到连接释放报文段之后,必须发出确认:ACK=1,seq=u+1,ack=w+1。 再经过2MSL(Maximum Segment Lifetime最长报文寿命)后,本次TCP连接真正结束,通信双方完成了他们的告别。