Socket抽象层(socket编程)
# Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单 的接口供应用层调用已实现进程在网络中通信
socket () 对象
bind () 函数来绑定
listen () 监听,等别人电话
accept()接收,已发送真实数据,真正等待客户端发信息
read()接收,真正拿到客户端信息 recv
write()send过程,发送,回应客户端
read()不会立刻断掉
close()断开
# socket抽象层把复杂的事已做比如(三次握手四次挥手),我们不需要操心,只需简单的 发送和接收
基于TCP协议的套接字(socket)编程
基于文件类型的套接字家族:
# 套接字家族的名字:AF_UNIX基于网络类型的套接字家族:
# 套接字家族的名字:AF_INET客户端先发送消息,需要服务端先运行起来
"""服务端代码:"""
import socket # 导入socket模块 from socket import AF_INET server=socket.socket(family=AF_INET, type=socket.SOCK_STREAM) # AF_INET, type=SOCK_DGRAM: 基于UDP协议的 server.bind(('127.0.0.1', 8000)) # 绑定IP地址和port # 绑定谁,谁就是服务端,可用你的客户端给他的服务端发信息 server.listen(3) # 服务端做监听,也称为是半链接池(服务端能够同时等待客户端的数量) sock, addr = server.accept() # sock:当前链接的客户端的链接, addr:就是客户端的地址:ip,port data=sock.recv(1024) # 接收的数据类型是bytes类型,二进制的 1024 代表接收的最多的字节数 print("接收客户端的数据:",data) sock.send(data.upper()) # 发送的数据是字节类型的 sock.close() # 关闭链接 server.close()
# sock, addr = server.accept() 代码会卡住,等待客户端开发链接和发送信息
"""客户端代码"""
import socket from socket import AF_INET client=socket.socket(family=AF_INET, type=socket.SOCK_STREAM) # socket.socket() client.connect(('127.0.0.1', 8000)) # 开始给服务端发送消息 client.send('hello'.encode('utf-8')) # 接收服务端发来的消息 data=client.recv(1024) print("服务端发来的消息:", data) client.close()
加上通信和通信循环
"""服务端""" import socket from socket import AF_INET server=socket.socket(family=AF_INET, type=socket.SOCK_STREAM) server.bind(('127.0.0.1', 8000)) server.listen(3) while True: sock, addr = server.accept() while True: try: data=sock.recv(1024) print("接收客户端的数据:",data) sock.send(data.upper()) except Exception as e: print(e) # 答应出错误 break sock.close() server.close()
"""客户端""" import socket from socket import AF_INET client=socket.socket(family=AF_INET, type=socket.SOCK_STREAM) client.connect(('127.0.0.1', 8000)) while True: send_data = input('请输入你要发送给服务端的数据:') client.send(send_data.encode('utf-8')) data=client.recv(1024) # 接收服务端发来的消息 print("服务端发来的消息:", data) client.close()
1、在accept()用while True循环,可支持多个客户端的数据(一个服务端)
2、当前:客户端只能说一句话
在send()用while循环,把发送的信息用input写活,可以多次发送信息了
3、问题:客户端还可以发送信息,但是此时服务端接收一个就已经close
在第一个close之前再一次循环,accept下
4、客户端发送的数据是空时,一个客户端出现了问题,整个服务器都将会报错
用异常捕捉,try
基于UDP协议的套接字编程
"""服务端"""
import socket server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议-》UDP server.bind(('127.0.0.1', 8080)) while True: """client_addr: 客户端的地址""" data, client_addr = server.recvfrom(1024) # 接收的最大字节数 print('===>', data, client_addr) server.sendto(data.upper(), client_addr) server.close()
"""客户端"""
import socket client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议-》UDP while True: msg = input('>>: ').strip() # msg='' client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080)) data, server_addr = client.recvfrom(1024) print(data) client.close()
粘包现象
import subprocess res = subprocess.Propen(tasklist,shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE) # shell脚本(linux) # tasklist命令,其实它是一个shell语言,bash解释器 # 正确stderr=subprocess.PIPE,错误stdout=subprocess.PIPE
# 粘包:管道里的数据没有取完,造成数据的丢失,但是可以多次取
# 在内存一定的情况下解决粘包问题:
1、知道服务端发过来字节的大小/每次接收的字节大小=总次数
2、struct模块
import struct res = struct.pack('i',1024) # 1024给打包 print(res) # b'\x00\xo4\xoo... 二进制 print(len(res)) # 4 不管输入多大,固定长度还是4
# 解包
res1 = struct.unpack('i',res) print(res1[0]) # 1024
过程:1、把服务端发过来字节打包,长度4
2、客户端 sock.recv(4) 只接4个
3、unpack('i',res) 解包/大小
4、得到总次数
TCP的流式协议
sock,addr = sever.accept() print('jerry',encode('utf-8'))
在短时间内,短时间客户端可发送多个数据,服务端可以一次性接收完