一、IP 地址

1、概念:标识网络中设备的一个地址

2、作用:标识网络中唯一的一台设备

3、表现形式

  • IPV4:目前使用,由点分十进制组成
  • IPV6:未来使用,由冒号十六进制组成

4、查看网卡信息命令

  • Linux 和 mac OS:ifconfig
  • Windows:ipconfig

192.168.XXX.XXX:设备在网络中的IP地址

127.0.0.1:本机地址(如果和自己的电脑通信就可以使用该地址),对应域名为 localhost

5、检查网络命令

  • 检查是否能上公网:ping 公网域名
  • 检查是否在同一个局域网内:ping 当前局域网的IP地址
  • 检查本地网卡是否正常:ping 127.0.0.1

img

二、端口和端口号

1、概念:每运行一个网络程序都会有一个端口,每一个端口都会有一个对应的端口号,端口号可以标识唯一的一个端口,端口号一共有65536个

2、端口号的分类

  • 知名端口号:指众所周知的端口号,固定分配给一些服务,范围:0到1023

    • https 默认端口号:443
    • http 默认端口号:80
    • SMTP(简单邮件传输协议)默认端口号:25
    • FTP(文件传输协议)默认端口号:21
  • 动态端口号:一般开发应用程序使用端口号称为动态端口号,范围:1024到65535

如果程序没有设置端口号,操作系统会在动态端口号范围内随机生成一个给程序使用,当这个程序退出时,所占用的这个端口号就会被释放

三、TCP

1、传输协议:数据在发送之前需要选择一个对应的传输协议,保证程序之间按照指定的传输规则进行数据的通信

2、TCP (Transmission Control Protocol):简称传输控制协议,它是一种面向连接的、稳定可靠的、基于字节流的传输层通信协议,常用于对数据进行准确无误的传输,例:文件下载,浏览器上网

3、TCP 通信步骤:创建链接→传输数据→关闭连接

4、TCP 的特点

  • 面向连接:通信双方必须先建立好连接才能进行数据的传输,数据传输完成后,双方必须断开此连接,以释放系统资源

  • 可靠传输

    • TCP 采用发送应答机制
    • 超时重传
    • 错误校验
    • 流量控制和阻塞管理

四、socket

1、概念:socket(套接字)是进程之间通信一个工具,进程之间想要进行网络通信和网络数据的传输需要基于 socket来完成, socket 就是进程间网络数据通信的工具

2、作用:负责进程之间的网络数据传输

3、使用场景:只要跟网络相关的应用程序或者软件都使用到了 socket

五、TCP 网络应用开发流程

1、服务端程序

  • 概念:运行在服务器设备上的程序,等待接受连接请求,专门为客户端提供数据服务
  • 步骤说明
    1. 创建服务端端套接字对象
    2. 绑定端口号
    3. 设置监听
    4. 等待接受客户端的连接请求
    5. 接收数据
    6. 发送数据
    7. 关闭套接字

2、客户端程序

  • 概念:运行在用户设备上的程序,主动发起建立连接请求
  • 步骤说明
    1. 创建客户端套接字对象
    2. 和服务端套接字建立连接
    3. 发送数据
    4. 接收数据
    5. 关闭客户端套接字img

六、socket之send和recv原理剖析

  • 当创建一个TCP socket对象时会有一个发送缓冲区和一个接收缓冲区(内存空间)
  • send发送数据会写入到发送缓冲区,recv接收数据是从接收缓冲区来读取,发送数据和接收数据最终是由操作系统控制网卡来完成

img

七、服务端开发

1. 创建服务端 socket 对象

  • 创建服务端 socket 对象:socket.socket(AddressFamily,Type)
  • 创建服务端 socket 常用参数
参数 说明
AddressFamily IP地址类型(socket.AF_INET:IPV4)
Type 传输协议类型(socket.SOCK_STREAM:TCP传输协议类型)

2. 服务端 socket 对象常用方法

  • 常用方法
方法 说明 参数及说明
bind() 绑定 IP 和端口号,接收元组 host:IP 地址(默认表示本机任何一个 IP)port:端口号
listen() 监听 backlog:最大等待建立连接的个数
accept() 等待接受客户端的连接请求
send() 发送数据 data:二进制数据
recv() 接收数据 buffersize:每次接收数据的大小,单位是字节
close() 关闭 socket
setsockopt() 设置端口号复用 参数 1:当前套接字参数 2:设置端口号复用选项参数 3:设置端口号复用选项对应值
  • 当客户端和服务端建立连接后,服务端程序退出后端口号不会立即释放,需要等待大概1-2分钟,若需要立即释放,有两种方式:
    1. 更换服务端端口号
    2. 设置端口号复用(让服务端程序退出后端口号立即释放)
1
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

3. 代码示例

  • 单任务版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import socket

if __name__ == '__main__':
# 创建 TCP 服务端套接字
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(('192.168.0.101',9090))
# 设置监听,listen 的套接字只负责接收客户端连接请求,不能收发消息,收发消息使用返回的新套接字来完成
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 = '正在处理中..'.encode('gbk')
service_client_socket.send(send_data)
# 关闭服务与客户端的套接字, 终止和客户端通信的服务
service_client_socket.close()
# 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务
tcp_server_socket.close()
  • 多任务版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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:
recv_data_length = len(recv_data)
print('接收数据的长度为', recv_data_length)
recv_content = recv_data.decode('gbk')
print('接收客户端的数据为', recv_content)
# 发送数据
send_data = '正在处理中..'.encode('gbk')
service_client_socket.send(send_data)
else:
print('客户端下线了:',ip_port)
break
# 关闭服务与客户端的套接字, 终止和客户端通信的服务
service_client_socket.close()

if __name__ == '__main__':
# 创建 TCP 服务端套接字
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(('192.168.0.101',9090))
# 设置监听,listen 的套接字只负责接收客户端连接请求,不能收发消息,收发消息使用返回的新套接字来完成
while True:
tcp_server_socket.listen(128)
# 等待客户端的连接请求,只有客户端和服务端建立连接成功代码才会解阻塞,代码才能继续往下执行
service_client_socket,ip_port = tcp_server_socket.accept()
print('客户端的 IP 地址和端口号',ip_port)
# 当客户端和服务端建立连接成功以后,创建一个子线程,不同子线程负责接收不同客户端的消息
sub_thread = threading.Thread(target=handle_client_request,args=(service_client_socket,ip_port),)
sub_thread.daemon = True
sub_thread.start()

# 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务(可以不关闭,因为服务端程序需要一直运行)
# tcp_server_socket.close()
  • 运行结果

img

八、客户端开发

1. 创建客户端 socket 对象

  • 创建客户端 socket 对象:socket.socket(AddressFamily,Type)
  • 创建服务端 socket 常用参数
参数 说明
AddressFamily IP地址类型(socket.AF_INET:IPV4)
Type 传输协议类型(socket.SOCK_STREAM:TCP传输协议类型)

2. 客户端 socket 对象常用方法

  • 常用方法
方法 说明 参数及说明
connect() 和服务端套接字建立连接 host:服务器IP 地址port:端口号
send() 发送数据 data:二进制数据
recv() 接收数据 buffersize:每次接收数据的大小,单位是字节
close() 关闭 socket
setsockopt() 设置端口号复用 参数 1:当前套接字参数 2:设置端口号复用选项参数 3:设置端口号复用选项对应值

3. 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import socket

if __name__ == '__main__':
# 创建 TCP 客户端套接字
tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 请求连接服务端
tcp_client_socket.connect(('192.168.0.101',9090))
# 发送数据
send_data = '你好,hello'.encode('gbk')
tcp_client_socket.send(send_data)
# 接收数据
recv_data = tcp_client_socket.recv(1024)
recv_content = recv_data.decode('gbk')
print('接收服务端的数据为',recv_content)
# 关闭连接
tcp_client_socket.close()
  • 运行结果

img