1.网络有什么好处
网络可以实现多个计算机相互通信、数据传递、资源共享... 如何多个计算机相互通信?
发送请求(URL(网址)): 统一资源定位符
一个完整URL主要包含:
协议://ip地址:端口号/目标资源
比如: http://192.168.1.222:9999/XXX
- 如果访问目标资源是首页 index.html index.jsp App.vue 是可以省略的
- 如果访问程序端口号是80 也可以省略
- 如果协议是Http协议 一般浏览器都会支持 也可以省略
- 所以剩下ip地址就可以正常 访问目标服务器
- 由于IP是路由器动态分配的 所以容易改变
- 由于IP地址是由几个数字构成的 也不好记忆
- 所以可以将几组IP地址 绑定一个域名 比如baidu.com
2.网络通信协议
协议:表示网络传输中 大家都要一起遵循的规范 无论是发送数据还是接收数据都有统一的标准 这样更加便于计算机的通信
- http协议:底层实现是基于TCP协议,超文本传输协议
- https协议:基于Http协议的加密版本 在网络传输时底层实现加密算法 防止外部攻击的
- ftp协议:用于上传文件的服务器 后期传递文件 不是在本地磁盘(数据库)而是通过文件服务器 或者云服务器
- TCP协议:网络传输协议
- UDP协议:用户数据报协议
2.1 TCP和UDP协议区别 (面试常考)
- TCP面向连接的,UDP协议没有连接
- TCP是可靠的(发送数据和接收数据都要负责),UDP是不可靠的(类似于广播,只管发送 不管你是否接收到了)
- TCP是面向字节流传输的可以传输任何内容(底层还实现了缓冲区 等缓冲区存储满了 才一口气以流的形式进行发送) 而UDP是面向报文传输(交给UDP无论是多长的报文 无需等待以数据包的形式进行发送)
2.2 TCP三次握手 ---面试题(具体可参考图解网络)
注:SYN:请求连接数据包,ACK:确认数据包
- 第一次握手:浏览器向服务器发送一个建立连接的请求(SYN请求连接数据包)
- 第二次握手:服务器告诉浏览器 同意连接请求 同时服务器也向浏览器建立连接的请求(ACK确认数据包+SYN请求连接数据包)
- 第三次握手:浏览器也要告诉服务器 同意连接(ACK确认数据包)
2.3 TCP四次挥手 ---面试题(具体可参考图解网络)
注:FIN断开连接数据包,ACK:确认数据包
- 第一次挥手:浏览器打算断开连接,向服务器发送一个FIN数据包
- 第二次挥手:服务器接收到了对方发送的FIN数据包 就向浏览器发送ACK确认数据包
- 第三次挥手:服务器也打算断开连接,向浏览器发送一个FIN数据包
- 第四次挥手:浏览器接收了对方发送的FIN数据包 向服务器发送ACK确认包
3.IP地址
ip地址目的就是快速找到是哪一台计算机(类似于家庭地址),是由32位二进制数构成,会分成四组 每组8位 由于不好记忆 通常会转换成十进制,由于IP地址也不好记忆,一般公司会把自己公司的项目绑定一个域名
4.端口
端口目的是用来区分同一台计算机不用的应用程序,所以说每个应用程序一定会有不同的端口号,端口号取值范围:165535 一般来说11024是系统默认端口号 一定不要使用 否则会出现端口被占用的错误
常用程序端口号:http默认端口80 ftp默认端口21 mysql默认端口3306 oracle默认端口1521 redis默认端口6379 tomcat默认端口8080
5.Socket
socket时表示在网络运行过程中可以进行双向通信 基于C/S 是基于客户端(client)和服务端(server)双向通信 可以通过客户端服务端发送数据,反过来也是可以的 通过IP地址+端口来访问服务端 这样就可以创建Socket对象进行通信了
5.1 Socket工作原理 ---选择题
- 创建服务端对象(ServerSocket)和客户端对象(Socket)其实两个类就可以实现
- 服务段提供端口号 便于客户端连接
ServerSocket server=new ServerSocket(端口号)
Socket client=server.accept();//等待客户端连接(线程阻塞)
- 客户端 通过ip地址+端口号 连接服务端
Socket client=new Socket(ip地址,端口号);
- 通过IO流(字节流输入和输出)进行通信
//负责读取对方给我写入的数据
InputStream is=client.getInputStream();
//负责向对方写入数据
OutputStream os=client.getOutputStream();
- 关闭资源
is.close();
out.close();
client.close();
server.close();
5.2 Socket应用场景
- 可以向服务器和客户端传递数据(String 文件 对象)
- 实现聊天功能
- 实现多人聊天
6.Socket代码案例
- 测试服务端和客户端连接
//测试服务端
public class TestServer {
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(9999);
while(true) {
System.out.println("开始执行一次");
Socket client = server.accept(); //阻塞
System.out.println(client);
}
}
}
//测试客户端
class TestClient{
public static void main(String[] args) throws IOException {
Socket client=new Socket("192.168.0.114",9999);
}
}
- 测试客户端和服务端发送数据
//实现: socket接收数据
public class Server1 {
public static void main(String[] args) throws IOException {
//1.创建对象
ServerSocket server=new ServerSocket(9999);
while(true){
try {
//2.等待客户端连接
Socket client = server.accept();
System.out.println(client + "连接成功");
//3.获取输入输出流
InputStream is = client.getInputStream();
OutputStream os = client.getOutputStream();
String message = "你连接成功了\n";
os.write(message.getBytes());
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String result = br.readLine();//bug 读取一行
System.out.println(client.getInetAddress() + "客户端:" + result);
}catch (Exception e){
}
}
}
}
class Client1{
public static void main(String[] args) throws IOException {
//1.创建对象
Socket client=new Socket("192.168.0.114",9999);
//2.创建输入输出流
BufferedReader br=new BufferedReader(
new InputStreamReader(
client.getInputStream()));
OutputStream os=client.getOutputStream();
String result=br.readLine();
System.out.println("服务端:"+result);
os.write("我是客户端\n".getBytes());
}
}
- 测试多线程使用Socket
//socket通过多线程接收数据
public class Server2 {
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(9999);
while(true) {
Socket client = server.accept();
System.out.println(client + "连接成功");
//通过线程负责每个客户端的读任务 给所有进入服务端的对象进行写入
new ServerThread(client).start();
}
}
}
//客户端数据 通过Scanner动态写入
class Client2{
public static void main(String[] args) throws IOException {
Socket client=new Socket("192.168.0.114",9999);
OutputStream os=client.getOutputStream();
//System.in 系统输入流 读取控制台的输入的数据
//Scanner是基于它的封装
BufferedReader br=new BufferedReader(
new InputStreamReader(System.in)
);
//添加一个客户端线程:负责接收服务端返回的数据
while(true) {
System.out.println("请输入你要向服务端写入的内容:");
String msg=br.readLine();
os.write((msg+"\n").getBytes());
}
}
}
//服务端线程: 目的是监控每一个人数据读写
class ServerThread extends Thread{
Socket client;
public ServerThread(Socket client){
this.client=client;
}
public void run() {
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(
client.getInputStream()));
while(true) {
String clientMsg = br.readLine();
System.out.println(client.getInetAddress() + ":" + clientMsg);
}
}catch (Exception e){
}
}
}
- 通过Socket模拟多人聊天室
//模拟多人聊天室
public class Server3{
//用于保存进入聊天室客户端对象
static List<Socket> list=new ArrayList<>();
public static void main(String[] args) throws IOException {
//创建服务端对象
ServerSocket server=new ServerSocket(9999);
//死循环 等待无数个客户端连接 保存进入聊天室的客户端对象
System.out.println("****多人聊天室开启成功****");
while(true){
Socket client=server.accept();
list.add(client);//类似于进入群聊
System.out.println("聊天室"+list.size()+"人");
//创建每个客户端的线程单独处理每人的任务
new ServerThread3(client).start();
}
}
}
class ServerThread3 extends Thread{
Socket client;
public ServerThread3(Socket client){
this.client=client;
}
//创建每个客户端的线程 去监听每个客户端写入的数据
//将读取到的消息 群发其他客户端(除了当前哪个客户端)
public void run() {
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(client.getInputStream())
);
while(true){
String msg=br.readLine();
if(msg!=null){
System.out.println(msg);
if(msg.contains("esc")){ //退出聊天室
Server3.list.remove(client);
System.out.println("聊天室的人数:"+Server3.list.size());
break;
}
//向其他客户端写入数据
for(Socket s:Server3.list){
if(s!=client){ //对象只需要比较地址
try {
s.getOutputStream().write((msg + "\n").getBytes());
}catch (SocketException e){
//System.out.println(s+"退出了");
}
}
}
}
}
}catch (Exception e){
}
}
}
//向服务端写入数据(控制台输入),接收服务端返回的数据
class Client3{
public static void main(String[] args) throws IOException {
Socket client=new Socket("localhost",9999);
//开启客户端线程 监听服务端消息
new ClientThread3(client).start();
//1.控制台输入
BufferedReader br=new BufferedReader(
new InputStreamReader(System.in)
);
//2.向服务端写
OutputStream os=client.getOutputStream();
System.out.println("请输入你的姓名");
String name=br.readLine();
while(true){
System.out.println("请输入内容:esc退出聊天室");
String msg=br.readLine();
if (msg != null) {
if("esc".equals(msg)){
os.write((name+"退出聊天室\n").getBytes());
break;
}else{
os.write((name+"说:"+msg+"\n").getBytes());
}
}
}
System.out.println("退出聊天室");
}
}
//3.监听服务端写入的数据(单独写个线程处理)
class ClientThread3 extends Thread{
Socket client;
public ClientThread3(Socket client){
this.client=client;
}
public void run() {
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(client.getInputStream())
);
while (true) {
String msg = br.readLine();
if (msg != null) System.out.println(msg);
}
}catch (Exception e){
}
}
}