今天是冬至,不知道大家有没有吃饺子啊!
每日分享:
冬至是北半球一年之中夜晚最长的一天,愿你在这个长夜能融化掉这一年所有的不快乐!!
目录:
- IP地址的介绍
- 端口和端口号的介绍
- TCP的介绍
- socket的介绍
- TCP网络应用程序开发流程
- TCP客户端程序开发
- TCP服务端程序开发
- TCP网络应用程序的注意点
- socket中send和recv原理剖析
IP地址就是标识网络设备(如电脑)的一个地址,就类似于家庭住址
2.IP地址的表现形式说明:
- IP地址分为两类:IPv4和IPv6
- IPv4是当前使用的ip地址
- IPv6是未来使用的ip地址
- ipv4是由点分割、十进制组成
- ipv6是由冒号分割、十六进制组成
ip地址的作用是标识网络中唯一的一台设备,也就是通过ip地址能够找到网络中的某台设备
4.查看ip地址- linux和mac OS使用ifconfig命令
- Windows使用ipconfig命令
使用命令ping
例:ping www.baidu.com
说明:
- ping www.baidu.com检查是否能上公网
- ping 当前局域网的ip地址 检查是否在同一个局域网内
- ping 127.0.0.1 检查本地网卡是否正常
- ip地址的作用是标识网络中唯一的一台设备
- ip地址的表现形式:ipv4、ipv6
- 查看网卡信息:ipconfig
- 检查网络:ping
每运行一个网络程序都会有一个端口,想要给对应的程序发送数据,找到对应的端口即可
1. 什么是端口端口是传输数据的通道,就好比是教室的门,是数据的必经之路
那么如何找到对应的端口?
每一个端口都会有一个对应的端口号,就好比每一个教室的门都有一个门牌号,可以通过端口号来找到端口
2. 什么是端口号操作系统为了统一管理这么多端口,就对端口进行了编号,这就是端口号,端口号其实就是一个数字,好比我们现实生活中的门牌号
端口号共有65536(2的16次方)个:(0~65535)
数据通信流程:通过ip地址找到对应的设备,通过端口号找到对应的端口,然后通过端口把数据传输给应用程序
3. 端口与端口号的关系端口号可以标识唯一的一个端口
4. 端口号的分类- 知名端口号
- 动态端口号
知名端口号是指众所周知的端口号,范围:0~1023
这些端口号一般固定分配给一些服务,比如21端口号分配给FTP(文件传输协议)服务,25端口号分配给SMTP(简单邮件传输协议)服务,80端口号分配给HTTP服务
动态端口号:一般程序员开发应用程序使用端口号称为动态端口号,范围:1024~65535
- 如果程序员开发的程序没有设置端口号,操作系统会在动态端口号这个范围内随机生成一个给开发的应用程序使用
- 当运行一个程序默认会有一个端口号,当这个程序退出时,所占用的这个端口号就会被释放
- 端口的作用就是给运行的应用程序提供传输数据的通道
- 端口号的作用就是用来区分和管理不同端口的,通过端口号能找到唯一的一个端口
- 端口号可以分为两类:知名端口号 和 动态端口号
- 知名端口号的范围:0~1023
- 动态端口号的范围:1024~65535
通过ip地址能够找到对应的设备,然后通过端口号找到对应的端口,在通过端口把数据传输给应用程序。但数据不能随便发送,在发送之前还需要选择一个对应的传输协议,保证程序之间按照指定的传输规则进行数据的通信,而这个传输协议就是我们今天学习的TCP
2. TCP的概念TCP(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议
TCP通信步骤:(类似于文件操作)
- 创建连接
- 传输数据
- 关闭连接
注意:
TCP通信模型相当于生活中的‘打电话’,在通信之前,一定要先建立好连接,才能发送数据,通信结束要关闭连接
3. TCP的特点- 面向连接
- 通信双方必须先建立好连接才能进行数据的传输,数据传输完成之后,双方必须断开此连接,以释放系统资源
- 可靠传输
- TCP采用发送应答机制
- 超时重传
- 错误校验
- 流量控制和阻塞管理
TCP是一个稳定、可靠的传输协议,常用于对数据进行准确无误的传输,比如:文件下载、浏览器上网
四、socket的介绍通信数据是通过socket来完成的
1. socket的概念socket(套接字)是进程之间通信的一个工具,就好比生活中的插座,所有的家用电器要想工作都是基于插座进行的,进程之间想要通过网络通信需要基于这个socket
2. socket的作用负责进程之间的网络数据传输,好比数据的搬运工
3. socket使用场景和网络相关的应用程序或软件都使用到了socket
4. 小结进程之间网络数据的传输可以通过socket来完成,socket就是进程间网络数据通信的工具
五、网络应用程序开发流程 1. TCP网络应用程序开发流程介绍TCP网络应用程序开发分为:
- TCP客户端程序开发
- TCP服务端程序开发
说明:
客户端程序是指运行在用户设备上的程序,服务端程序是指运行在服务器设备上的程序,专门为客户端提供数据服务
2. TCP客户端程序开发流程的介绍步骤:
- 创建客户端套接字对象
- 和服务端套接字建立连接
- 发送数据
- 接收数据
- 关闭客户端套接字
步骤:
- 创建服务端套接字对象
- 绑定端口号
- 设置监听
- 等待接收客户端的连接请求
- 接收数据
- 发送数据
- 关闭套接字
- TCP网络应用程序开发分为客户端程序开发和服务端程序开发
- 主动发起建立连接请求的是客户端程序
- 等待接收连接请求的是服务端程序
- 创建客户端套接字对象
- 和服务端套接字建立连接
- 发送数据
- 接收数据
- 关闭客户端套接字
导入socket模块:import socket
创建客户端socket对象:socket.socket(AddressFamily, Type)
参数说明:
- AddressFamily 表示ip地址类型,分为ipv4和ipv6
- Type 表示传输协议类型
方法说明:
- connect((host,port))表示和服务器套接字建立连接,host是服务器ip地址,port是应用程序的端口号
- send(data)表示发送数据,data是二进制数据
- recv(buffersize)表示接收数据,buffersize是每次接收数据的最大长度
在这之前我们需要一个软件:网络调试助手(充当服务端)
可以去网上搜索下载或者百度网盘提取链接:https://pan.baidu.com/s/1_lqcDOPI0n8zsPB6vx_JYw 提取码:2fxa
import socket
if __name__ == '__main__':
# 1.创建tcp客户端套接字
# AF_INET:ipv4 SOCK_STREAM:tcp传输协议
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.和服务端应用程序建立连接
tcp_client_socket.connect(("127.0.0.1", 8080))
# 3.准备发送的数据(win是gbk,linux是utf-8)
send_data = "你好服务端,我是客户端小白".encode('gbk')
# 4.发送数据
tcp_client_socket.send(send_data)
# 5.接收数据,每次接收数据最大字节数是1024
recv_data = tcp_client_socket.recv(1024)
# 6.返回的是服务端程序发送的二进制数据
print(recv_data)
# 7.对数据进行解码
recv_content = recv_data.decode('gbk')
print(recv_content)
# 8.关闭套接字
tcp_client_socket.close()
运行后如下图:
可以看到py程序并没有结束,它在等待服务器端返回给他数据:
可以看到我们成功接收到了数据 “你好!”
说明:
- str.encode(编码格式)表示把字符串编码成为二进制
- data.decode(编码格式)表示把二进制解码成为字符串
其中网络调试助手充当服务端程序:
1. 导入socket模块
2. 创建TCP套接字‘socket’
- 参数1:‘AF_INET’,表示ipv4地址类型
- 参数2:‘SOCK_STREAM’,表示TCP传输协议类型
3. 发送数据‘send’
- 参数1:要发送的二进制数据,字符串需要进行encode方法进行编码
4. 接收数据‘recv’
- 参数1:表示每次接收数据最大为多少,单位:字节
5. 关闭套接字‘socket’表示通信完成
七、TCP服务端程序开发 1. 服务端程序开发步骤- 创建服务端套接字对象
- 绑定端口号
- 设置监听
- 等待接受客户端的连接请求
- 接受数据
- 发送数据
- 关闭套接字
导入socket模块
import socket
创建服务端socket对象
socket.socket(AddressFamily, Type)
参数说明:
- AddressFamily表示IP地址类型,分为ipv4和ipv6
- Type表示传输协议类型
方法说明:
- bind((host,port))表示绑定端口,host是ip地址,port是端口号,ip地址一般不指定,表示本机的任何一个ip地址都可以
- listen(backing)表示设置监听,backing参数表示最大等待建立连接的个数
- accept()表示等待接收客户端的连接请求
- send(data)表示发送数据,data是二进制数据
- recv(buffersize)表示接收数据,buffersize是每次接收数据的最大长度
import socket
if __name__ == '__main__':
# 1.创建tcp服务端套接字
# AF_INET:ipv4 AF_INET6:ipv6 SOCK_STREAM:tcp协议
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,程序退出,端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2.绑定端口号
# 第一个参数表示ip地址,一般不用指定,表示本机的任何一个ip都可
# 第二个参数表示端口号
tcp_server_socket.bind(("", 8080))
# 3.设置监听
# 128(可自定义)表示最大等待建立连接的个数
tcp_server_socket.listen(128)
# 4.等待接收客户端的连接请求
# 每次客户端和服务端建立连接成功都会返回一个新的套接字
# tcp_server_socket只负责等待接收客户端的连接请求,收发消息不使用它
new_client, ip_port = tcp_server_socket.accept()
# 代码执行至此表示连接成功
print("客户端的ip和端口号:", ip_port)
# 5.接收客户端的数据
recv_data = new_client.recv(1024)
# 对二进制数据进行解码变成字符串
recv_content = recv_data.decode('gbk')
print("接收客户端的数据:", recv_content)
# 6.发送数据到客户端
send_content = '问题处理中...'
# 二进制编码
send_data = send_content.encode('gbk')
new_client.send(send_data)
# 结束本次服务
new_client.close()
# 7.关闭服务端套接字,表示服务端以后不在接收等待接收客户端的连接请求
tcp_server_socket.close()
结果:
当客户端和服务端建立连接之后,服务端程序退出后端口号不会立即释放,需要大概等待1~2分钟
解决:
- 更换服务端端口号
- 设置端口号复用
端口号复用代码:
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
参数1:表示当前套接字
参数2:设置端口号复用选项
参数3:设置端口号复用选项对应的值
在这,网络调试助手充当客户端程序
1. 导入socket模块
2. 创建TCP套接字‘socket’
- 参数1:‘AF_INET’,表示ipv4地址类型
- 参数2:‘SOCK_STREAM’,表示tcp传输协议类型
3. 绑定端口号‘bind’
- 参数:元组,(ip地址,端口号)
4. 设置监听‘listen’
- 参数:元组,最大等待建立连接的个数
5. 等待接收客户端的连接请求‘accept’
6. 发送数据‘send’
- 参数:要发送的二进制数据,字符串需要用encode方法进行编码
7. 接收数据‘recv’
- 参数:表示每次接收数据的最大的大小,单位是字节,解码用decode方法
8. 关闭套接字‘socket’表示通信完成
八、TCP网络应用程序的注意点- 当TCP客户端程序想要和TCP服务端程序进行通信的时候必须要先建立连接
- TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的
- TCP服务端程序必须绑定端口号,否则客户端找不到这个TCP服务端程序
- listen之后,之前的套接字就成了被动套接字,只负责接收新的客户端的连接请求,不能收发消息
- 当TCP客户端程序和TCP服务端程序连接成功后,TCP服务端程序会产生一个新的套接字,收发客户端消息使用该套接字
- 关闭accept返回的套接字意味着和这个客户端通信完毕
- listen后,关闭之前的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经连接成功的客户端还能正常通信
- 当客户端的套接字调用close后,服务器的recv会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的recv也会解阻塞,返回的数据长度也为0
当创建一个TCP socket对象的时候,会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存中的一片空间
2. send原理剖析send是不是直接把数据发送给服务端?
不是,想要发送数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡
3. recv原理剖析recv是不是直接从客户端接收数据?
不是,应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓冲区获取客户端发送的数据
4. send和recv原理剖析图说明:
- 发送数据是发送到发送缓冲区
- 接收数据是从接收缓冲区获取
不管是recv还是send都不是直接接收到对方的数据和发送数据到对方,发送数据会写入到发送缓冲区,接收数据是从接收缓冲区来读取,发送数据和接收数据最终是由操作系统控制网卡来完成