一:了解
1.了解一下网络:
局域网(LAN),一个上课的机房,多个连在同一个路由器上的设备,就是在一个局域网中---打游戏 (局域网内的主机之间能方便的进行网络通信,又称为内网;局域网和局域网之间在没有连接的情况下,是无法通信的)
广域网(WAN) ,-更大的局域网,---格局打开不仅可以打游戏,看网页,看视频,买东西...(通过路由器,将多个局域网连接起来,在物理上组成很大范围的网络,就形成了广域网。广域网内部的局域网都属于其子网。)
2.网络通信基础:
咱们直接举一个例子:
网友见面: 在北方的小明去找在南方的小芳,并且约在一家咖啡馆,但是咖啡馆男生女生人也很多,所以约定~~他俩都穿红衣服见面---好,三个问题来了---这句话表明了: 从哪里去哪里,谁找谁,怎么发现对方—nice! 所以
~所以 对于为了进行网络通信:我们需要什么呢? 明确三点
~首先,从哪里访问哪里? 北方到南方 -定位网络主机-IP地址 源IP 目的IP
~其次,谁要访问谁? 小明找小芳 -定位主机中的进程-端口号 源端口 目的端口
~然后,怎么访问? 穿红衣 -协议
~~~补充一下:从北方去南方找人的的人很多,那么怎么具体对应到小明小芳~就是端口号
对于上述三点的详细介绍:
IP地址:
- IP地址用于定位主机的网络地址。
- (特殊IP):127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1本机环回主要用于本机到本机的网络通信
- IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(4个字节),如:01100100.00000100.00000101.00000110。通常用“点分十进制”的方式来表示,即 a.b.c.d 的形式(a,b,c,d都是0~255之间的十进制整数)。如:100.4.5.6。
端口号:
- 在网络通信中,IP地址用于标识主机网络地址,端口号可以标识主机中发送数据、接收数据的进程。简单说:端口号用于定位主机中的进程
- 端口号是0~65535范围的数字,在网络通信中,进程可以通过绑定一个端口号,来发送及接收网络数据
协议:
- 协议,网络协议的简称,网络协议是网络通信经过的所有网络设备都必须共同遵从的一组约定、规则。如怎么样建立连接、怎么样互相识别等。只有遵守这个约定,计算机之间才能相互通信交流。
- 协议最终体现为在网络上传输的数据包的格式
3.重点了解一下协议:
知名协议端口: 系统端口号范围为 0 ~ 65535,其中:0 ~ 1023 为知名端口号,这些端口预留给服务端程序绑定广泛使用的应用层协议
协议分层:
- 原因:场景太复杂->分类太多->协议太多->按功能分类->协议分层
- 约定:上层协议调用上层协议,下层给上层提供服务,不可以各层调用
- 好处:封装->理解成本降低,用什么学什么 && 方便维护->尤其可针对某层协议可以进行替换
- 总结: 简单来说,是为了让程序猿更方便, 因为协议过于庞大,所以进行分层,需要哪里,学哪里
两种典型的协议分层:
- OSI 七层 功能:主要的功能使就是帮助不同类型的主机实现数据传输 但是 既复杂又不实用:所以 OSI 七层模型没有实现
- TCP/IP 五层: TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇。TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
4.TCP/IP 五层介绍:
概念过于枯燥,所以!!!
我们继续唠唠小明和小芳~~~ 他们两个见面了,对对方都很满意,之后,两个人总聊天~快到小芳生日了,小明,就去淘宝下单了520色号口红~~~
- 商家看到了订单,写好了,发件人的信息,收件人小芳的信息,就发货了—传输层:端到端的传输
- 包裹交给了快递公司,他们规划好路径 —网络层:点到点的传输
- 快递小哥1把包裹运到相邻地点的集散中心, 快递小哥2再运……快递小哥N把包裹运到了小芳家~~~ —数据链路层:相邻节点之间的传输
- 忘记说啦~小明早早就想着准备礼物,所以时间充裕,他没选择飞机运输,就普通快递陆运的~物理层:底层的基础设施
- 而我们的小芳~只需要收口红,康康什么时候用口红~~~ 应用层:应用程序
okk这里是正儿八经的概念:
- 应用层:负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。我们的网络编程主要就是针对应用层。
- 传输层:负责两台主机之间的数据传输。如传输控制协议 (TCP),能够确保数据可靠的从源主机发送到目标主机。
- 网络层:负责地址管理和路由选择。例如在IP协议中,通过IP地址来标识一台主机,并通过路由表的方式规划出两台主机之间的数据传输的线路(路由)。路由器(Router)工作在网路层。
- 数据链路层:负责设备之间的数据帧的传送和识别。例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作。有以太网、令牌环网,无线LAN等标准。交换机(Switch)工作在数据链路层。
- 物理层:负责光/电信号的传递方式。比如现在以太网通用的网线(双绞 线)、早期以太网采用的的同轴电缆(现在主要用于有线电视)、光纤,现在的wifi无线网使用电磁波等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等。集线器(Hub)工作在物理层。
5.封装和分用
数据从上到下, 层层添加信息的过程, 称''封装'', 分用即为封装的逆过程
称谓: 不同的协议层对数据包有不同的称谓,在传输层叫做段,在网络层叫做数据报,在链路层叫做帧。
这个栗子不是很好举~那先给张图
肯定肯定看不懂,没关系,建议你去搜寻一下,协议~~咳咳TCP我更过的 !
二:编程
- 利用代码完成网络编程:
- )Socket套接字
就是 操作系统给应用程序提供的API
应用程序可以通过socket API来进行网络编程
网络传输层有很多种协议:最知名TCP UDP—工作特性差别大,操作系统提供了两组API
2)简单说一下TCP, UDP区别:
TCP | UDP |
有连接 | 无连接 |
可靠传输 | 不可靠传输 |
面向字节流 | 面向数据报 |
全双工 | 全双工 |
浅浅解释一下~~~还是小明与小芳
有连接: 小明给小芳打电话~~有连接,因为小芳需要接通
无连接: 小明给小芳发短信~~无连接,因为小芳不需要接通
可靠传输: 小明知道小芳接没接到电话
不可靠传输: 小明不知道小芳收没收到短信
面向字节流~数据报~: IO说过~
全双工: 同一时间,只能小明给小芳打电话,或者小芳给小明打电话~~
半双工: 同一时间,小明可以给小芳发消息, 小芳也可以给小明发消息~
3)代码UDP的socket 客户端-服务器 介绍&代码
i)要掌握的两个类: DatagramSocket, DatagramPacket
构造方法 | 方法 | |
DatagramSocket | DatagramSocket() 无参 一般用户客户端 | void receive(DatagramPacket p) 接收数据报 |
DatagramSocket(int port) 有参(端口号)一般用于服务器 | void send(DatagramPacket p) 发送数据报 | |
void close | ||
DatagramPacket | DatagramPacket(byte[]buf.int length) 构造一DatagramPacke接收数据报 | InetAddress 从接收(发送)的数据报中,获取发送(接收)端主机IP地址 |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造一DatagramPacke发送数据报 | int getPort() 从接收(发送)的数据报中,获取发送(接收)端主机的端口号 | |
byte[] getData() 获取数据报中的数据 |
没错! 你肯定看不懂这两个有什么区别~
来让我举个栗子, socket是菜鸟驿站,而你的packet就是包裹,你要去菜鸟驿站才能邮寄包裹~
ii)最简单UDP版本的客户端-服务器—回显服务器
(⊙﹏⊙)里面有一些注释,这个代码不详细说了, 但是便于理解,我还是 举栗子!!!!
- 服务器嘛~咱们当成菜鸟驿站~
- 你说这菜鸟驿站开的话,是不是要选个位置(构造方法的端口号)(这是必须要选好的,固定的—指定参数),
- 那这驿站是提供服务的哎~所以,是不是需要早早开门,晚点关门,让我在任意时间都能邮寄领取快递啊~~
- 那如果我是来取快递的,驿站应该干嘛呢~~知道我是来取件的,去寻找我的包裹,在返回给我,~~
- 那驿站肯定还要核实一下我的信息吧?不然,怎么知道这个是我的呢?那拿什么核对我的信息呢?包裹上的单子,和我手机上的单子咯~~~
- 客户端嘛~就是咱们咯~
- 我去取快递~所以要去菜鸟驿站啊(IP)~~~那这么多菜鸟驿站,我去哪呢,就是刚刚那个呀(刚才的构造方法中的端口号)()这是可以更改的,咱们可以换地方,也可以去吃饭~~—未指定参数)~
- 去取快递了~要知道我的包裹的取件码~,然后告诉工作人员,工作人员去干服务器干的事情…我拿到我的包裹~~
那我再来带你们走一下流程吧~~~小明决定去找小芳~,他选了离小芳家很近的地方,开了一个菜鸟驿站~~~每天早早上班,晚晚收工, 这天,小芳来去快递,她告诉小明,她的取件码~小明立马去给她找包裹~~~找到之后,核实信息,给了小芳,小芳say,谢谢~小明把取件记录写上~ 然后???然后,两个人吃晚饭去了!!!!我在这里继续更博客…
Okk~~没错,你带入一下,这个代码其实就是这个流程~
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpEchoServer {
private DatagramSocket socket = null;
// 服务器要绑定的端口
public UdpEchoServer(int port) throws SocketException {
socket = new DatagramSocket(port);
}
//启动服务器
public void start() throws IOException {
System.out.println("服务器启动~");
// 循环一次,处理一个请求 true是因为,不知道什么时候会接收到请求
while (true) {
// 1. 读取请求并解析
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
socket.receive(requestPacket);//receive参数是输出型参数,所以构造一个空的DatagramPacket对象,读取出网卡的数据
// DatagramPacket转为一个字符串,方便打印
String request = new String(requestPacket.getData(),0,requestPacket.getLength());
// 2. 根据请求计算响应
String response = process(request);
// 3. 把响应写回客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
requestPacket.getSocketAddress());//response.getBytes().length要有--单位(字节);response.length--单位(字符)--都是应该还好ascii一样,但是有中文就bug了
socket.send(responsePacket);
// 4. 打印一个日志,记录一下服务器的情况 客户端的IP地址,客户端的端口号
System.out.printf("[%s:%d] req:%s ; resp:%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
request,response);
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer server = new UdpEchoServer(9090);// 可以随便绑一个
server.start();
}
}
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpEchoClient {
private DatagramSocket socket = null;
private String serverIP;
private int serverPort;
public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
socket = new DatagramSocket();
this.serverIP = serverIP;
this.serverPort = serverPort;
}
public void start() throws IOException {
Scanner scanner = new Scanner(System.in);
while (true) {
// 1.从控制台读取用户输入的内容
System.out.print("-> ");
String request = scanner.next();
// 2.构造一个UDP请求, 发送给服务器
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
InetAddress.getByName(this.serverIP),this.serverPort);
socket.send(requestPacket);
// 3.从服务器读取 UDP响应数据,并解析
DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(),0,responsePacket.getLength());
// 4.把服务器的响应显示到控制台上
System.out.println(response);
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
client.start();
}
}
4)代码TCP的socket 客户端-服务器 介绍
i)要掌握的两个类: ServerSocket, Socket
构造方法 | 方法 | |
ServerSocket 服务器用-监听端口 | ServerSocket(int port) 绑定端口 | Socket accept() 接受客户端的连接 |
void close() | ||
Socket 服务器,客户端都可-传输数据 | Socket(String host, int port) 尝试和指定服务器建立连接 | InetAddress getInetAddress() 获取对方IP地址和端口 |
InputStream getInputStream() 返回输入流 | ||
OutputStream getOutputStream() 返回输出流 |
ii)补充知识点~长连接,短连接
短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是短连接只能一次收发数据
长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TcpEchoServer {
ServerSocket listenSocket = null;
public TcpEchoServer(int port) throws IOException {
// listenSocket是去发宣传单的
listenSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动~");
ExecutorService service = Executors.newCachedThreadPool();
while (true){
// 1.先调用accept接受请求
// 被宣传单吸引过来的,来给他进行详细产品介绍clientSocket
Socket clientSocket = listenSocket.accept();
// 2.处理连接
//多线程
// Thread t = new Thread(()-> {
// try {
// processConnect(clientSocket);
// } catch (IOException e) {
// e.printStackTrace();
// }
// });
// t.start();
//线程池
service.submit(new Runnable() {
@Override
public void run() {
try {
processConnect(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
private void processConnect(Socket clientSocket) throws IOException {
System.out.printf("[%s:%d] 客户端上线了,建立连接成功 \n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
// 处理请求
try (InputStream inputStream = clientSocket.getInputStream();//读
OutputStream outputStream = clientSocket.getOutputStream()){ //写
while (true) {
// 1.读取请求&解析
Scanner scanner = new Scanner(inputStream);
if(!scanner.hasNext()){
System.out.printf("[%s:%d] 客户端下线了,断开连接 ",clientSocket.getInetAddress().toString(),clientSocket.getPort());
break;
}
String request = scanner.next();
// 2.根据请求计算响应
String response = process(request);
// 3.把响应写回给客户端
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(response);
printWriter.flush();
System.out.printf("[%s:%d] req:%s resp:%s\n ",clientSocket.getInetAddress().toString(),clientSocket.getPort(),
request,response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 发一次广告,可能会来多个clientSocket, 那人都走了的时候,把不需要的clientSocket去除掉~~换个思路,去实习,活多的时候多找几个人,没活了在辞退掉~
clientSocket.close();
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer server = new TcpEchoServer(9090);
server.start();
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoClient {
private Socket socket = null;
public TcpEchoClient(String serverIp, int serverPort) throws IOException {
socket = new Socket(serverIp,serverPort);
}
public void start(){
Scanner scanner = new Scanner(System.in);
try (InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()) {
while (true){
// 1.从控制台读取数据 构造请求
System.out.print("-> ");
String request = scanner.next();
// 2.发送请求给服务器
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(request);
printWriter.flush();
// 3.从服务器上读取响应
Scanner responseScanner = new Scanner(inputStream);
String response = responseScanner.next();
// 4.打在控制台上
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
client.start();
}
}
三:五层详细说~其实重点就是TCP/UDP
这个我更过啦~~~但是可以浅浅的拿出我的思维导图~
应用层:
传输层: TCP/UDP
网络层: