文章目录
对IP的介绍
概念:标识网络设备的地址
说明:分为IPv4(点分十进制)和IPv6(冒号十六进制)
ping 网址
- 是否能上网
ping ip
- 检查是否再同一个局域网内
ping 127.0.0.1
- 检查本地网卡是否正常
目前IPv4使用的较多,IPv6使用的较少
端口
概念:传输数据的通道,每个应用程序都有一个端口号
端口号分类:
1)知名端口号:0-1023(21-ftp、80-http、25-SMTP)
2)动态端口号:开发应用程序使用端口号(1024-65535)
当运行一个程序默认会有一个端口号,退出时,相应的端口号会被释放
TCP介绍
网络程序间的通信流程
由之前学习可知,传输数据知道ip及端口即可。但是注意,数据再发送之前需要选择一个对应的传输协议,保证程序之间按指定的传输规则进行数据的通信,这个传输协议就是TCP
TCP概念
(创建连接 - 传输数据 - 关闭连接) 是传输控制协议,是面向连接的、可靠的、基于字节流的传输层通信协议。
TCP特点
1)面向连接:传之前建好连接,传后断,释放资源。
2)可靠传输:TCP采用发送应答 机制、超时重传、错误校验、流量控制和阻塞管理(会先写到缓存区)。
socket介绍
概念:是进程之间通信一个工具(相当于插座),进程之间进行通信需要基于socket。
作用:负责进程之间的网络数据传输,搬运工。
下面由一张图来解释TCP客户端与服务端开发
TCP客户端开发流程
TCP客户端程序开发(用户设备上的程序) --> TCP服务端程序开发(服务器上的,提供数据)
TCP的三次握手
向服务器发送请建立连接的数据包 --> 服务器确认准备完成发送给客户端 --> 客户端再次确认准备完成发送给服务器
客户端
创建客户端套接字对象 --> 和服务器套接字建立连接 --> 发送数据 --> 接收数据 --> 关闭客户端套接字
服务器
创建服务端套接字对象 --> 绑定端口号 --> 设置监听 --> 等待接收客户端的连接请求 --> 接收数据 --> 发送数据 --> 关闭套接字
TCP应用程序的注意点
1.当TCP客户端程序想要和TCP服务端程序进行通信的时候必须要先建立连接
2.TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的
3.TCP服务端程序必须绑定端口号,否则客户端找不到这个TCP服务端程序
4.
listen
后的套接字是被动套接字只负责接收新的客户端的连接请求,不能收发消息
5.当TCP客户端程序和TCP服务端程序连接成功后,TCP服务器端程序会产生一个新的套接字收发,客户端消息使用该套接字
6.关闭
accept
返回的套接字意味看和这个客户端已经通信完毕
7.关闭
listen
后的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信
8.当客户端的套接字调用
close
后,服务器端的recv
会解阻塞,返回的数据长度为0服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的recv
也会解阻塞,返回的数据长度也为0
socket之send和recv的刨析原理
缓冲区
当创建TCPsocket对象时,会有一个发送缓冲区和接收缓冲区,缓冲区时内存的一片空间
send原理刨析
send是直接将数据发送出去嘛?
不是的,是必须通过网卡发送数据。应用程序是无法通过网卡发送数据,需要调用操作系统接口 意思是,应用程序把发送的数据先写到发送缓冲区,再由操作系统控制网卡把发送缓冲区的数据发送给服务器网卡
recv原理刨析
同样要调用操作系统接口,从接收缓冲区获取客户发送的数据
下面再结合一张图来理解
小结
发送数据和接收数据最终都是由操作系统控制网卡来完成
如何用Python对TCP客户端与服务端进行开发呢
首先介绍socket这个类
socket
类:
创建客户端socket对象 - socket.socket(AddressFamily,Type)
AddressFamily:ip地址的类型
Type:传输协议类型
客户端方法:
connect((host,port)):表示和服务器套接字建立连接,host-服务器ip地址,port-应用程序端口
send(data):发送数据,data二进制数据
recv(buffersize):接收数据,buffersize每次接收数据的长度
服务端方法:
bind((host,type)):ip、端口
listen(backlog):backlog表示最大等待建立连接的个数,
accpet():等待接收客户端的连接请求
send(data):发送数据,data二进制数据
recv(buffersize):接收数据,buffersize每次接收数据的长度
对客户端程序的开发
import socket
def Client():
"""
tcp客户端程序开发
不需要绑定端口号
"""
# 1、创建TCP套字接 # AF_INET代表ipv4、SOCK_STREAM代表tcp协议
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2、和服务器建立连接 注意端口不能加引号
tcp_client_socket.connect(("ip", 端口))
# 3、向服务器发送数据
tcp_client_socket.send("hello".encode())
# 4、接收服务器的数据 1024接收最大字节数
data = tcp_client_socket.recv(1024)
print(data.decode())
# 5、关闭套字接
tcp_client_socket.close()
if __name__ == '__main__':
Client()
服务端程序开发
import socket
def Server():
"""
说明:服务端程序退出,端口号不会立即释放,要1-2分钟
可更换服务端端口号
设置端口号复用,让服务端程序退出后端口号立即释放
setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
"""
# 1、创建套字接
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 保证程序退出时,端口号立即释放
# SOL_SOCKET:当前套接字 SO_REUSEADDR:表示复用套接字 True:确定复用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2、绑定端口
tcp_server_socket.bind(("ip",9090))
# 3、设置监听
# listen后的套接字时被动套接字,只负责接收新的客户端的连接请求,不能收发消息
# listen后的套接字关闭后,会导致新的客户端不能连接服务器
tcp_server_socket.listen(128)
# 4、等待客户端连接请求.返回元组(新的套接字,客户端对应的ip,端口号)
# TCP使用新的套接字进行收发
new_client, ip_port = tcp_server_socket.accept()
# 5、接收数据
recv_data = new_client.recv(1024)
# 6、发送数据
new_client.send("我是你的咯咯咯".encode())
new_client.close()
# 7、关闭套字接
tcp_server_socket.close()
if __name__ == '__main__':
Server()
多线程实现可以接受多次数据
def handle_client_request(ip_port,new_client):
"""
处理客户端请求
"""
print("客户端的ip和端口号:", ip_port)
# 循环接收客户端消息
while True:
recv_data = new_client.recv(1024)
if len(recv_data) > 0:
print("接收的数据长度:", len(recv_data))
print("接受{}的数据是:{},长度为".find(ip_port, recv_data.decode(),len(recv_data)))
new_client.send("我是你的咯咯咯".encode())
else:
print("{}客户端下线".format(ip_port))
break
new_client.close()
def Server_to_Clients():
"""
多人版多线程
"""
t_thread = []
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:
new_client, ip_port= tcp_server_socket.accept()
# 再此处以建立成功
# 创建子线程,负责接收客户端的消息
t = threading.Thread(target=handle_client_request, args=(ip_port,new_client))
# 设置守护主线程,主线程进出子线程直接销毁
t.start()
tcp_server_socket.close()
if __name__ == '__main__':
Server_to_Clients()
醉后
以上是根据网络上的视频以及书籍上的知识所学的,如以上内容对概念的阐述有误或使用有误希望各位大佬指点。