python day9 socket编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python day9 socket编程相关的知识,希望对你有一定的参考价值。
首先说一下TCP/IP 协议,OS七层
应用模型:
socket 软件抽象层(不负责发送数据,真正发送数据的是socket后面的协议)
socket
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
socket和file的区别:
- file模块是针对某个指定文件进行【打开】【读写】【关闭】
- socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】
举个打电话的例子如图:
import socket ip_port = (‘127.0.0.1‘,9999) #买手机 s= socket.socket() #封装好了TCP协议 ,生成套接字 #买手机卡 s.bind(ip_port) #绑定ip+协议+端口:用来唯一标示一个进程,ip_port必须是元组形式 #开机 s.listen(5) #定义可以挂起链接数(最大128个连接,队列等待) while True: #等待电话 conn,addr = s.accept() #返回两个对象(conn=通信链路,addr是客户端ip+port)accetp(接受客户端请求过程是一个阻塞过程 while True: #(用来接收一个连接重复发消息) try: #(捕捉客户端异常关闭ctrl+c) #收消息 recv_data = conn.recv(1024) #接受1024字节 收消息,阻塞 print(str(recv_data,encoding=‘utf-8‘)) if len(recv_data) == 0:break #客户端如果退出,服务端将受到空消息,退出 #发消息 send_data = recv_data.upper() conn.send(send_data) except Exception: break #挂电话 conn.close()
import socket ip_port = (‘127.0.0.1‘,9999) #买手机 s= socket.socket() #封装好TCP协议的 #拨号 s .connect(ip_port) while True: #发送消息 send_data = input(">>:").strip() if send_data == ‘exit‘:break if len(send_data) == 0:continue s.send(bytes(send_data,encoding=‘utf8‘)) #2.0可以发字符串,3.0只能发字节 #收消息 recv_data = s.recv(1024) print(str(recv_data,encoding=‘utf-8‘)) #挂断 s.close()
解决粘包问题:
服务端:1、send 数据长度
4、recv 收到确认信息,开始下一步
客户端:2、recv 获取数据长度
3、send 发送确认信息
5、recv 循环接收
import socket import subprocess ip_port = (‘127.0.0.1‘,9999) s= socket.socket() #封装好了TCP协议 ,生成套接字 s.bind(ip_port) #绑定ip+协议+端口:用来唯一标示一个进程,ip_port必须是元组形式 s.listen(5) #定义可以挂起链接数(最大128个连接,队列等待) while True: conn,addr = s.accept() #返回两个对象(conn=通信链路)accetp过程是一个阻塞过程 while True: try: recv_data = conn.recv(1024) #接受1024字节 print(str(recv_data,encoding=‘utf-8‘)) if len(recv_data) == 0:break p = subprocess.Popen(str(recv_data,encoding=‘utf-8‘),shell=True,stdout=subprocess.PIPE) #执行系统命令,Windows平台命令的标准输出是gbk编码,需要转换 res = p.stdout.read() #获取标准输出 if len(res) == 0: #执行错误命令,标准输出为空 send_data = ‘cmd error‘ else: send_data = str(res,encoding=‘gbk‘) #解码 win系统的是gbk编码 gpk------>str------->utf8 send_data1 = bytes(send_data,encoding=‘utf-8‘) ready_tag = ‘Ready|%s‘ % len(send_data1) conn.send(bytes(ready_tag,encoding=‘utf-8‘)) #发送数据长度 feedback = conn.recv(1024) #start 接受确认信息 feedback = str(feedback,encoding=‘utf-8‘) if feedback.startswith("Start"): conn.send(bytes(send_data,encoding=‘utf-8‘)) #发送数据 #conn.send(bytes(send_data,encoding=‘utf-8‘)) #编码 except Exception: break conn.close()
import socket ip_port = (‘127.0.0.1‘,9999) s= socket.socket() #封装好TCP协议的 s .connect(ip_port) #链接服务端,如果服务端已经有一个链接,那么挂起 while True: #基于connect建立的链接循环发消息 send_data = input(">>:").strip() if send_data == ‘exit‘:break if len(send_data) == 0:continue s.send(bytes(send_data,encoding=‘utf8‘)) #2.0可以发字符串,3.0只能发字节 #解决粘包问题 ready_tag = s.recv(1024) #收取带数据长度的字节Ready|len ready_tag = str(ready_tag,encoding=‘utf-8‘) if ready_tag.startswith(‘Ready‘): #Ready|9998 msg_size = int(ready_tag.split(‘|‘)[-1]) #获取待接收数据长度 start_tag = ‘Start‘ s.send(bytes(start_tag,encoding=‘utf-8‘)) #基于已经收到的待接收数据长度,循环接收数据 recv_size = 0 recv_msg = b‘‘ while recv_size < msg_size: recv_data = s.recv(1024) recv_msg += recv_data recv_size += len(recv_data) print(‘MSG SIZE %s RECE SIZE %s ‘ % (msg_size,recv_size)) print(str(recv_msg,encoding=‘utf-8‘)) s.close()
总结:
1、python3.5的socket只能收发字节(2.7可以收发字符串)
2、只客户端退出,服务器端不退出
3、accept() 和recv()是阻塞的,阻塞的前提是基于链接正常(socket 除了accpet会阻塞,recv也会阻塞,如果发的是空就会阻塞)
4、listen(n)n代表:能刮起的链接数,如果n=1,代表可以链接一个,挂起一个,第三个拒绝。
5、服务端出现端口冲突:修改监听端口号
socket 多并发
import socketserver import subprocess class MyServer(socketserver.BaseRequestHandler): def handle(self): #conn = self.request self.request.sendall(bytes(‘欢迎致电10086,请输入0转人工服务‘,encoding=‘utf-8‘)) while True: data = self.request.recv(1024) if len(data) == 0:break print("[%s]says:%s"%(self.client_address,data.decode())) #self.request.sendall(data.upper()) cmd = subprocess.Popen(data.decode(),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) cmd_res = cmd.stdout.read() if not cmd_res: cmd_res = cmd.stderr.read() if len(cmd_res.strip()) == 0: cmd_res = bytes("cmd no msg",encoding=‘utf-8‘) self.request.sendall(cmd_res) if __name__ == ‘__main__‘: server = socketserver.ThreadingTCPServer((‘0.0.0.0‘,8009),MyServer) server.serve_forever() #永远接收
import socket ip_port = (‘127.0.0.1‘,8009) #买手机 s= socket.socket() #封装好TCP协议的 #拨号 s .connect(ip_port) welcome_msg = s.recv(1024) print("from server:",welcome_msg.decode()) while True: send_data = input(">>:").strip() if len(send_data) == 0:continue s.send(bytes(send_data,encoding=‘utf8‘)) #2.0可以发字符串,3.0只能发字节 #收消息 recv_data = s.recv(1024) print(str(recv_data,encoding=‘utf-8‘)) #挂断 s.close()
以上是关于python day9 socket编程的主要内容,如果未能解决你的问题,请参考以下文章