欢迎关注个人主页:逸狼
创造不易,可以点点赞吗~
如有错误,欢迎指出~
⽹络编程,指⽹络上的主机,通过不同的进程,以编程的⽅式实现⽹络通信(或称为⽹络数据传 输)。
Socket套接字,是由系统提供⽤于⽹络通信的技术,是基于TCP/IP协议的⽹络通信的基本操作单元。 基于Socket套接字的⽹络程序开发就是⽹络编程。
操作系统给应用程序(传输层给应用层)提供的api,就叫做socket api(这里学习Java版本的),有两组不同的api,分别为UDP和TCP两套版本
- UDP 无连接 不可靠传输 面向数据报 全双工
- TCP 有连接 可靠传输 面向字节流 全双工
- 有/无连接: 通信双方若保存了通信对端的信息(IP和端口),就是有连接,不保存就是无连接
- 可靠/不可靠传输:尽可能考虑能够到达对方就是可靠传输,完全不考虑就是不可靠传输.这个在代码中没办法直接体现,它是在内核中实现好的功能
- TCP内置了一些机制(感知到对方是否收到; 重传机制,在对方没收到时进行重试)可以保证可靠传输( 但是可靠传输要付出代价 ,TCP协议设计要比UDP复杂很多,也会损失一些传输数据的效率)
- UDP没有可靠性机制
- 面向字节流/数据报 :参数单位是字节的就是面向字节流,单位是数据包的就是面向数据报
- TCP是面向字节流的,传输过程和文件流/水流是一样的特点
- UDP是面向数据报的,传输数据的基本单位就是UDP数据报,一次发送/接收必须是完整的数据报
- 全/半双工:一个通信链路,可以发送数据,也可以接收数据就是全双工; 只能发送或只能接收就是半双工 这里写的代码都是全双工的,不考虑半双工
通过代码不好直接操作网卡(网卡有很多不同的型号,之间提供的api都会有差别),操作系统就把网卡概念封装成socket,应用程序员就不必关注硬件的差异和细节,统一操作socket对象就能间接操作网卡; socket 可以认为是操作系统中广义文件下里的一种文件类型,这样的文件就是网卡这种硬件设备的抽象表现形式
代码部分需要实现两个程序
socket相当于网卡的遥控器,网络编程必须要操作网卡,就需要用到socket对象DatagramSocket


下面通过写一个"回显服务器(echo server)"(客户端发的请求和服务器返回的响应一致)代码示例加以理解
UDP服务器

对于一个系统来说,同一时刻,同一个协议下,一个端口号,只能被一个进程绑定(端口号就是用来区分进程的,如果有多个进程尝试绑定一个端口号,后来的进程就会绑定失败),但是一个进程可以同时绑定多个端口号(通过创建多个socket对象来实现)
比如:9090端口在udp下被一个进程绑定了,还可以在TCP下被另一个进程绑定

receive


DatagramSocket 这个对象中,不持有对方(客户端) 的 ip 和端口的. 所以进行 send 的时候,就需要在 send 的数据包里,把要发给谁这样的信息,写进去,才能够正确的把数据进行返回

socket在使用完之后需要关闭,此处代码中,socket生命周期整个进程一样长,就算没有close,进程关闭时也会释放文件描述符表里的所有内容,相当于close了
UDP客户端

- 服务器这边创建socket时一定要指定端口号,因为客户端是通过端口号来找到服务器的,且客户端是主动发起的一方.
- 客户端这边创建socket时就最好不要指定端口号(不指定不代表没有,客户端的端口号是系统自动分配的一个端口,让系统自动分配一个端口,就能确保分配的是一个无人使用的端口).如果在客户端指定了端口号,由于客户端是在用户的电脑运行的,万一代码指定的端口和用户电脑上运行的其他程序的端口冲突,就会产生bug

服务器和客户端代码执行流程

TCP socket api核心类有两个
- ServerSocket 专门给服务器使用的socket对象
- Socket 给客户端使用,也可以给服务器使用

TCP是有连接的,建立连接的过程类似于"打电话",ServerSocket类里的accept相当于"接电话"("客户端打电话,服务器接电话")

下面通过编写TCP回显服务器来举例展示
TCP服务器
accept

约定换行符

TCP客户端

容易产生bug的点
刷新缓冲区
PrintWrite这样的类以及很多IO流中的类都是"自带缓冲区的",引入缓冲区后,进行写数据操作不会立即触发IO,而是放到内存缓冲区中,等到缓冲区赞了一波,在进行统一发送;
所以当要发送的数据较少时 ,没办法攒够数据发送,停在了缓冲区,所以要引入PrintWrite类里的flush操作 来主动 "刷新缓冲区"
clientSocket要自动关闭close
像ServerSocket,DatagramSocket他们的生命周期都是跟随整个进程的(进程结束,会自动关闭),而服务器代码中clientSocket是"连接级别"的数据,随着客户端断开连接,这个socket就不再使用了(即使是同一个客户端,断开之后,重新连接,也和旧的socket不是同一个),这样的socket应该主动关闭以防止 文件资源泄漏.
多个客户端连接同一个服务器

此处单线程下无法处理多个客户端本质是服务器代码里 双重while循环导致的,进入了里层的while循环时,外层while无法执行了 ,所以这里要比双层while循环改成一异while,分别执行-->使用多线程解决.主线程用于accept来获取多个连接 ,每个连接都可以启动一个新的线程
虽然创建线程比创建进程 更轻量,但是也架不住短时间内 ,创建销毁大量的线程
使用线程池 可以解决短时间客户端涌入,并且每个客户端请求都很快 的问题

- 长连接: 客户端连上服务器后,一个连接中会多次发出请求,接收多个响应(当前回显服务器就属于这种模式)
- 短连接: 客户端连上服务器后,一个连接只能发一个请求,接受一个响应,然后就断开连接了(可能会频繁和服务器建立/断开连接)
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/11359.html
