一、IP地址
1.IP地址的概念
- IP 地址是
标识网络中设备的一个地址 ,好比现实生活中的家庭地址 - 网络中的设备效果图:
2.IP地址的表现形式
- IP 地址分为两类:
IPv4 和 IPv6 - IPv4 是
目前 使用的ip地址 - IPv6 是
未来 使用的ip地址 - IPv4 是由
点分十进制 组成 - IPv6 是由
冒号十六进制 组成
3.IP地址的作用
- IP 地址的作用是
标识网络中唯一的一台设备 ,也就是说通过IP地址能够找到网络中某台设备 - IP地址作用效果图:
4.查看IP地址
- Linux 和 mac OS 使用
ifconfig 这个命令 - Windows 使用
ipconfig 这个命令 - ifconfig 和 ipconfig 都是查看网卡信息,网卡信息包括设备的IP地址
- 192.168.1.107是设备在网络中的IP地址
127.0.0.1 表示本机地址,提示:如果和自己的电脑通信就可以使用该地址- 127.0.0.1该地址对应的域名是
localhost ,域名是 ip 地址的别名,通过域名能解析出一个对应的ip地址
5.检查网络是否正常
- 检查网络是否正常使用
ping 命令 - 检查网络是否正常效果图:
- ping www.baidu.com 检查是否能上
公网 - ping 当前局域网的ip地址 检查是否在同一个
局域网 内 - ping 127.0.0.1 检查
本地网卡 是否正常
二、端口和端口号
1.什么是端口
端口 是传输数据的通道,好比教室的门,是数据传输必经之路- 那么如何准确找到对应的端口呢?
其实,每一个端口都有一个对应的端口号 ,好比每个教室的门都有一个门牌号,想要找到端口通过端口号即可
2.什么是端口号
- 操作系统为了统一管理这么多端口,就对端口进行了编号,这就是
端口号 ,端口号其实就是一个数字,好比我们现实生活中的门牌号 - 端口号有
65536 个 - 那么最终数据通信的流程是这样的,
通过ip地址找到对应的设备 ,通过端口号找到对应的端口 ,然后通过端口把数据传输给应用程序 - 最终通信流程效果图:
3.端口号的分类
- 知名端口号是指众所周知的端口号,范围从
0到1023 - 这些端口号一般
固定分配给一些服务 ,比如21端口分配给FTP(文件传输协议)服务,25端口分配给SMTP(简单邮件传输协议)服务,80端口分配给HTTP服务
- 程序员开发应用程序使用的端口号称为
动态端口号 , 范围是从1024到65535 - 如果程序员开发的程序没有设置端口号,操作系统会在动态端口号这个范围内
随机生成 一个给开发的应用程序使用 - 运行一个程序默认会有一个端口号,当这个程序退出时,所占用的这个端口号就会被
释放
三、TCP
1.TCP的概念
- TCP 的英文全拼(Transmission Control Protocol)简称
传输控制协议 ,它是一种面向连接的 、可靠的 、基于字节流的 传输层通信协议 - 面向连接的效果图:
2.TCP的通信步骤
- 1.创建连接
- 2.传输数据
- 3.关闭连接
- TCP 通信模型相当于生活中的’打电话’,在通信开始之前,一定要先建立好连接,才能发送数据,通信结束要关闭连接
3.TCP的特点
- 面向连接
- 通信双方必须先建立好连接才能进行数据的传输,数据传输完成后,双方必须断开此连接,以释放系统资源
- 可靠传输
- TCP 采用发送应答机制
- 超时重传
- 错误校验
- 流量控制和阻塞管理
四、socket
socket (简称 套接字 ) 是进程间网络数据通信的工具 ,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要基于这个 socket- socket 效果图:
五、TCP网络应用程序开发流程
- TCP 网络应用程序开发分为:
- 客户端程序是指运行在用户设备上的程序
- 服务端程序是指运行在服务器设备上的程序,专门为客户端提供数据服务
步骤说明:
- 创建客户端套接字对象
- 和服务端套接字建立连接
- 发送数据
- 接收数据
- 关闭客户端套接字
步骤说明:
- 创建服务端套接字对象
- 绑定端口号
- 设置监听
- 等待接受客户端的连接请求
- 接收数据
- 发送数据
- 关闭套接字
六、TCP客户端程序开发
1.socket类的介绍
- 导入 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是每次接收数据的长度
2.TCP客户端程序示例代码
import socket
if __name__ == '__main__':
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client_socket.connect(("192.168.131.62", 8080))
send_data = "你好服务端,我是客户端小黑!".encode("gbk")
tcp_client_socket.send(send_data)
recv_data = tcp_client_socket.recv(1024)
print(recv_data)
recv_content = recv_data.decode("gbk")
print("接收服务端的数据为:", recv_content)
tcp_client_socket.close()
b'hello'
接收服务端的数据为: hello
七、TCP服务端程序开发
1.socket类的介绍
- 导入 socket 模块
import socket - 创建服务端 socket 对象
socket.socket(AddressFamily, Type) - 参数说明:
- AddressFamily 表示IP地址类型, 分为IPv4和IPv6
- Type 表示传输协议类型
- 方法说明:
bind((host, port)) 表示绑定端口号, host 是 ip 地址,port 是端口号,ip 地址一般不指定,表示本机的任何一个ip地址都可以listen (backlog) 表示设置监听,backlog参数表示最大等待建立连接的个数accept() 表示等待接受客户端的连接请求send(data) 表示发送数据,data是二进制数据recv(buffersize) 表示接收数据, buffersize是每次接收数据的长度
2.TCP服务端程序示例代码
import socket
if __name__ == '__main__':
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
tcp_server_socket.bind(("", 8989))
tcp_server_socket.listen(128)
service_client_socket, ip_port = tcp_server_socket.accept()
print("客户端的ip地址和端口号:", ip_port)
recv_data = service_client_socket.recv(1024)
recv_data_length = len(recv_data)
print("接收数据的长度为:", recv_data_length)
recv_content = recv_data.decode("gbk")
print("接收客户端的数据为:", recv_content)
send_data = "ok, 问题正在处理中...".encode("gbk")
service_client_socket.send(send_data)
service_client_socket.close()
tcp_server_socket.close()
客户端的ip地址和端口号: ('172.16.47.209', 52472)
接收数据的长度为: 5
接收客户端的数据为: hello
八、TCP网络应用程序的注意点
- 当 TCP 客户端程序想要和 TCP 服务端程序进行通信的时候必须要
先建立连接 - TCP 客户端程序
一般不需要绑定端口号 ,因为客户端是主动发起建立连接的 - TCP 服务端程序
必须绑定端口号 ,否则客户端找不到这个 TCP 服务端程序 listen 后的套接字是被动套接字 ,只负责接收新的客户端的连接请求,不能收发消息- 当 TCP 客户端程序和 TCP 服务端程序连接成功后, TCP 服务器端程序会
产生一个新的套接字 ,收发客户端消息使用该套接字 - 关闭
accept 返回的套接字意味着和这个客户端已经通信完毕 - 关闭
listen 后的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信 - 当客户端的套接字调用
close 后,服务器端的 recv 会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的 recv 也会解阻塞,返回的数据长度也为0
九、案列-多任务版TCP服务端程序
1.需求
- 前面的TCP服务端程序只能服务于一个客户端,如何开发一个多任务版的TCP服务端程序能够服务于多个客户端呢?
- 完成多任务,可以使用
线程 ,比进程更加节省内存资源
2.实现步骤
- 编写一个TCP服务端程序,
循环等待 接受客户端的连接请求 - 当客户端和服务端建立连接成功,
创建子线程 ,使用子线程专门处理客户端的请求,防止主线程阻塞 - 把创建的子线程设置成为
守护主线程 ,防止主线程无法退出
3.多任务版TCP服务端程序的示例代码
import socket
import threading
def handle_client_request(service_client_socket, ip_port):
while True:
recv_data = service_client_socket.recv(1024)
if recv_data:
print(recv_data.decode("gbk"), ip_port)
service_client_socket.send("ok,问题正在处理中...".encode("gbk"))
else:
print("客户端下线了:", ip_port)
break
service_client_socket.close()
if __name__ == '__main__':
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
tcp_server_socket.bind(("", 9090))
tcp_server_socket.listen(128)
while True:
service_client_socket, ip_port = tcp_server_socket.accept()
print("客户端连接成功:", ip_port)
sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
sub_thread.setDaemon(True)
sub_thread.start()
客户端连接成功: ('172.16.47.209', 51528)
客户端连接成功: ('172.16.47.209', 51714)
hello1 ('172.16.47.209', 51528)
hello2 ('172.16.47.209', 51714)
十、socket之send和recv原理剖析
1.socket的发送和接收缓冲区
当创建一个TCP socket对象的时候会有一个发送缓冲区 和一个接收缓冲区 ,这个发送和接收缓冲区指的就是内存中的一片空间
2.send原理剖析
- send是不是直接把数据发给服务端?
- 不是,要想发数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,
应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡
3.recv原理剖析
- recv是不是直接从客户端接收数据?
- 不是,应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,
由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓存区获取客户端发送的数据
4.send和recv原理剖析图
不管是recv还是send,都不是直接接收到对方的数据和发送数据到对方,发送数据会写入到发送缓冲区,接收数据是从接收缓冲区来读取,发送数据和接收数据最终是由操作系统控制网卡来完成
|