python基础9.1.socket网络编程 --> 实现代码与示例
Socket编程2.0
Socket通信流程图示例

描述
# 流程描述: # # 1 服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket # # 2 服务器为socket绑定ip地址和端口号 # # 3 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开 # # 4 客户端创建socket # # 5 客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket # # 6 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直等到客户端返回连接信息后才返回,开始接收下一个客户端连接请求 # # 7 客户端连接成功,向服务器发送连接状态信息 # # 8 服务器accept方法返回,连接成功 # # 9 客户端向socket写入信息(或服务端向socket写入信息) # # 10 服务器读取信息(客户端读取信息) # # 11 客户端关闭 # # 12 服务器端关闭
参数
SOCK_STREAM : TCP
SOCK_DGARM : UDP
family = AF_INET : 服务器之间通信
family = AF_INET6 : 服务器之间通信
family = AF_UNIX : unix不同进程之间通信
server下的方法:
bind()
listen()
accept()
recv()
send()
sendall()
close()
client下的方法:
cinnect()
recv()
send()
sendall()
close()
<socket.socket fd=640, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000), raddr=('127.0.0.1', 52981)>
------------
('127.0.0.1', 52981)
(<socket.socket fd=684, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000), raddr=('127.0.0.1', 53398)>, ('127.0.0.1', 53398))
部分方法及参数
sk.bind(address) #s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。 sk.listen(backlog) #开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。 #backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5 #这个值不能无限大,因为要在内核中维护连接队列 sk.setblocking(bool) #是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。 sk.accept() #接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。 #接收TCP 客户的连接(阻塞式)等待连接的到来 sk.connect(address) #连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 sk.connect_ex(address) #同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061 sk.close() #关闭套接字 sk.recv(bufsize[,flag]) #接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。 sk.recvfrom(bufsize[.flag]) #与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 sk.send(string[,flag]) #将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。 sk.sendall(string[,flag]) #将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 #内部通过递归调用send,将所有内容发送出去。 sk.sendto(string[,flag],address) #将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。 sk.settimeout(timeout) #设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s ) sk.getpeername() #返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 sk.getsockname() #返回套接字自己的地址。通常是一个元组(ipaddr,port) sk.fileno() #套接字的文件描述符
TCP协议简单操作
# 粘包现象 # 只出现在tcp协议中,因为tcp协议 多条消息之间没有边界,并且还有一大堆优化算法 # 发送端 : 两条消息都很短,发送的间隔时间也非常短 # 接收端 : 多条消息由于没有及时接收,而在接收方的缓存短堆在一起导致的粘包 # 解决粘包问题的本质 :设置边界 一接一发
基本连接方式:
import socket # 创建socket sk = socket.socket() # 为socket绑定ip和端口号 address = ('127.0.0.1',8000) sk.bind(address) # 监听设置端口等待客户端的请求 sk.listen(3) # accept阻塞,直到有客户端连接进来 conn,addr = sk.accept() # 接收并显示接受到的内容 date = conn.recv(1024) print(str(date,'utf8')) # 关闭该用户的连接 conn.close()
import socket # 创建socket sk = socket.socket() # 连接到指定计算机的端口 ip_port = ('127.0.0.1',8000) sk.connect(ip_port) # 以bytes类型发送数据 inp = input('>>>') sk.send(bytes(inp, 'utf8')) # 关闭连接 sk.close()
进阶版本:
import socket sk = socket.socket() ip_port = ('127.0.0.1',8000) sk.bind(ip_port) sk.listen(3) while True: conn, addr = sk.accept() print(f'用户{addr[0]}接入,占用端口{addr[1]}') while True: date = input('>>>') conn.send(bytes(date,'utf8')) msg = conn.recv(1024) print(f'ID{addr[0]}: ',str(msg,'utf8')) conn.close()
import socket sk = socket.socket() ip_port = ('127.0.0.1',8000) sk.connect(ip_port) while True: msg = sk.recv(1024) print(str(msg,'utf8')) date = input('>>>') sk.send(bytes(date,'utf8'))
实现远程指令版本:
import socket import subprocess import time sk = socket.socket() ip_pots = ('127.0.0.1',8001) sk.bind(ip_pots) sk.listen(3) while True: conn,addr = sk.accept() print('用户已经连接,IP:%s -- 端口:%s'%(addr[0],addr[1])) while True: try: date = conn.recv(1024) except Exception: break if not conn:break obj = subprocess.Popen(str(date,'utf8'),shell=True,stdout=subprocess.PIPE) cmd_result = obj.stdout.read() result_len = bytes(str(len(cmd_result)),'utf8') print('发送字节流>>>:',result_len) conn.sendall(result_len) #粘包现象 # time.sleep(0.2) #lowb版解决办法 不建议 影响效率 dapa = conn.recv(1024) #建议使用方法 print(str(dapa, 'gbk'),'\nprocessing......\nsend up!') conn.sendall(cmd_result)
import socket sk = socket.socket() ip_post = ('127.0.0.1',8001) sk.connect(ip_post) print('Sever连接成功,请发送指令') while True: inp = input('>>>') if inp == 'exit': print('已经断开连接') break sk.send(bytes(inp, 'utf8')) result_len = int(str(sk.recv(1024),'utf8')) print('收到字节流>>>:',result_len) sk.sendall(bytes('accept up!','utf8')) date = bytes() while len(date) != result_len: dat = sk.recv(1024) date += dat print(str(date, 'gbk'))
文件传输版本
import socket sk = socket.socket() ip_port = ('127.0.0.1',8012) sk.bind(ip_port) sk.listen(3) conn,addr = sk.accept() date = conn.recv(1024).decode('utf8') filename,filesize = date.strip().split('|') file = open(filename,'wb') sumber = 0 while sumber != int(filesize): size = conn.recv(1024) file.write(size) sumber += len(size) print(filesize, '-->', sumber) file.close() conn.close() sk.close()
import socket import os FILEPATH = r'C:\Users\Admin-yue\Documents\1.mp4' sk = socket.socket() # ip_port = ('127.0.0.1',8012) sk.connect(ip_port) f1 = open(FILEPATH,'rb') filename = os.path.basename(FILEPATH) filesize = os.stat(FILEPATH).st_size file = filename+'|'+str(filesize) sk.send(bytes(file,'utf8')) sumber = 0 while sumber != filesize: size = f1.read(1024) sk.send(size) sumber += len(size) f1.close() sk.close()
TCP粘包处理方案
import json import struct import socket # 接收 sk = socket.socket() sk.bind(('127.0.0.1',9001)) sk.listen() conn,_ =sk.accept() msg_len = conn.recv(4) # 只接受四个长度 dic_len = struct.unpack('i',msg_len)[0] # 抓换成int型 msg = conn.recv(dic_len).decode('utf-8') msg = json.loads(msg) with open(msg['filename'],'wb') as f: while msg['filesize'] > 0: content = conn.recv(1024) msg['filesize'] -= len(content) f.write(content) conn.close() sk.close()
import os import json import struct import socket # 发送 sk = socket.socket() # sk.connect(('192.168.14.109',9012)) sk.connect(('127.0.0.1',9001)) # 文件名\文件大小 abs_path = r'D:\python22期\day28 课上视频\3.网络基础概念.mp4' filename = os.path.basename(abs_path) filesize = os.path.getsize(abs_path) # 数据在网络中传输使用json dic = {'filename':filename,'filesize':filesize} str_dic = json.dumps(dic) b_dic = str_dic.encode('utf-8') mlen = struct.pack('i',len(b_dic)) sk.send(mlen) # 4个字节 表示字典转成字节之后的长度 sk.send(b_dic) # 具体的字典数据 with open(abs_path,mode = 'rb') as f: while filesize>0: content = f.read(1024) filesize -= len(content) sk.send(content) sk.close()
SocketServer实现并发效果
import time import socketserver class Myserver(socketserver.BaseRequestHandler): def handle(self): conn = self.request while True: try: content = conn.recv(1024).decode('utf-8') conn.send(content.upper().encode('utf-8')) time.sleep(0.5) except ConnectionResetError: break server = socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver) server.serve_forever()
import socket sk = socket.socket() sk.connect(('127.0.0.1',9001)) while True: sk.send(b'hello') content = sk.recv(1024).decode('utf-8') print(content)
Struct模块
import struct sumber = 'asd' a= struct.pack('i',len(sumber.encode())) print(a,type(a)) # b'\x03\x00\x00\x00' <class 'bytes'> b = struct.unpack('i',a)[0] print(b,type(b)) # 3 <class 'int'>
UDP协议的简单操作
基础操作
import socket sk = socket.socket(type = socket.SOCK_DGRAM) ip_port = ('127.0.0.1',8000) sk.bind(ip_port) msg,addr = sk.recvfrom(1024) print(msg) sk.sendto(b'reas',addr)
import socket sk = socket.socket(type=socket.SOCK_DGRAM) ip_port = ('127.0.0.1',8000) sk.sendto(b'asd',ip_port) msg = sk.recv(1024) print(msg)
进阶版本
import socket import struct sk = socket.socket(type=socket.SOCK_DGRAM) ip_port = ('192.168.14.183',9001) sk.bind(ip_port) myname = input('为自己起个名字:') while True: name,ioi= sk.recvfrom(1024) conn,addr = sk.recvfrom(1024) date = str(name,'utf8')+':'+str(conn,'utf8') print(date) set = input('>>>') date1 = myname+':'+set sk.sendto(bytes(date1,'utf8'),addr)
import socket sk = socket.socket(type=socket.SOCK_DGRAM) ip_port = ('192.111.23.1',8101) username = input('为自己创建一个昵称:') while True: date = input('>>>') sk.sendto(bytes(username, 'utf8'), ip_port) sk.sendto(bytes(date,'utf8'),ip_port) date = sk.recv(1024) date = str(date,'utf8') print(date)

浙公网安备 33010602011771号