阅读 58

SOCKET编程进阶

socketserver 虽说用Python编写简单的网络程序很方便,但复杂一点的网络程序还是用现成的框架比较好。这样就可以专心事务逻辑,而不是套接字的各种细节。SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也是Python标准库中很多服务器框架的基础。 socketserver模块可以简化网络服务器的编写,Python把网络服务抽象成两个主要的类,一个是Server类,用于处理连接相关的网络操作,另外一个则是RequestHandler类,用于处理数据相关的操作。并且提供两个MixIn 类,用于扩展 Server,实现多进程或多线程。

Server类 它包含了种五种server类,BaseServer(不直接对外服务)。TCPServer使用TCP协议,UDPServer使用UDP协议,还有两个不常使用的,即UnixStreamServer和UnixDatagramServer,这两个类仅仅在unix环境下有用(AF_unix)。

创建一个socketserver 至少分以下几步

1.首先,您必须创建一个请求处理类,继承BaseRequestHandlerclass类并且重 写父类的handle()方法,该方法将处理传入的请求。
2.其次,你必须实例化一个上面类型中的一个类(如TCPServer)传递服务器的地址和你上面创建的请求处理类 给这个TCPServer。
3.然后,调用handle_request()或者serve_forever()方法来处理一个或多个请求。
ser.handle_request()  # 只处理一个请求,处理完就退出了
ser.serve_forever()   # 处理多个请求,永远执行。
4.最后,调用server_close()关闭socket。

复制代码

聊天并发实例

import socketserver
class MyServer(socketserver.BaseRequestHandler):
   def handle(self):
       print ("服务端启动...")
       while True:
           conn = self.request
           print (self.client_address)
           while True:
               client_data=conn.recv(1024)
               print (str(client_data,"utf8"))
               print ("waiting...")
               server_response=input(">>>")
               conn.sendall(bytes(server_response,"utf8"))
               # conn.sendall(client_data)
           conn.close()
           # print self.request,self.client_address,self.server
if __name__ == '__main__':
   server = socketserver.ThreadingTCPServer(('127.0.0.1',8098),MyServer)
   server.serve_forever()
##########################################
import socket
ip_port = ('127.0.0.1',8098)
sk = socket.socket()
sk.connect(ip_port)
print ("客户端启动:")
while True:
   inp = input('>>>')
   sk.sendall(bytes(inp,"utf8"))
   server_response=sk.recv(1024)
   print (str(server_response,"utf8"))
   if inp == 'exit':
       break
sk.close()
复制代码

解决大数据传送和粘包问题 粘包:相邻两次发送的数据粘在了一起

import socketserver
import subprocess
class Myserver(socketserver.BaseRequestHandler):
   def handle(self):
       while True:
           conn=self.request
           conn.sendall(bytes("欢迎登录","utf8"))
           while True:
               client_bytes=conn.recv(1024)
               if not client_bytes:break
               client_str=str(client_bytes,"utf8")
               print(client_str)
               command=client_str
               result_str=subprocess.getoutput(command)
               result_bytes = bytes(result_str,encoding='utf8')
               info_str="info|%d"%len(result_bytes)
               conn.sendall(bytes(info_str,"utf8"))
               # conn.recv(1024)
               conn.sendall(result_bytes)
           conn.close()
if __name__=="__main__":
   server=socketserver.ThreadingTCPServer(("127.0.0.1",9998),Myserver)
   server.serve_forever()
#####################################client
import socket
ip_port=("127.0.0.1",9998)
sk=socket.socket()
sk.connect(ip_port)
print("客户端启动...")
print(str(sk.recv(1024),"utf8"))
while True:
   inp=input("please input:").strip()
   sk.sendall(bytes(inp,"utf8"))
   basic_info_bytes=sk.recv(1024)
   print(str(basic_info_bytes,"utf8"))
   # sk.send(bytes('ok','utf8'))
   result_length=int(str(basic_info_bytes,"utf8").split("|")[1])
   print(result_length)
   has_received=0
   content_bytes=bytes()
   while has_received<result_length:
       fetch_bytes=sk.recv(1024)
       has_received+=len(fetch_bytes)
       content_bytes+=fetch_bytes
   cmd_result=str(content_bytes,"utf8")
   print(cmd_result)
sk.close()
复制代码

文件上传

import socket,os
ip_port=("127.0.0.1",8898)
sk=socket.socket()
sk.bind(ip_port)
sk.listen(5)
BASE_DIR=os.path.dirname(os.path.abspath(__file__))
while True:
   print("waiting connect")
   conn,addr=sk.accept()
   flag = True
   while flag:
           client_bytes=conn.recv(1024)
           client_str=str(client_bytes,"utf8")
           func,file_byte_size,filename=client_str.split("|",2)

           path=os.path.join(BASE_DIR,'yuan',filename)
           has_received=0
           file_byte_size=int(file_byte_size)

           f=open(path,"wb")
           while has_received<file_byte_size:
               data=conn.recv(1024)
               f.write(data)
               has_received+=len(data)
           print("ending")
           f.close()

#----------------------------------------------client
#----------------------------------------------
import socket
import re,os,sys
ip_port=("127.0.0.1",8898)
sk=socket.socket()
sk.connect(ip_port)
BASE_DIR=os.path.dirname(os.path.abspath(__file__))
print("客户端启动....")
while True:
   inp=input("please input:")
   if inp.startswith("post"):
       method,local_path=inp.split("|",1)
       local_path=os.path.join(BASE_DIR,local_path)
       file_byte_size=os.stat(local_path).st_size
       file_name=os.path.basename(local_path)
       post_info="post|%s|%s"%(file_byte_size,file_name)
       sk.sendall(bytes(post_info,"utf8"))
       has_sent=0
       file_obj=open(local_path,"rb")
       while has_sent<file_byte_size:
           data=file_obj.read(1024)
           sk.sendall(data)
           has_sent+=len(data)
       file_obj.close()
       print("上传成功")

注意:
       1  纸条就是conn
       2  一收一发(解决粘包的关键)
       3   client_data=conn.recv(1024)        
           if  那边send一个空数据  这边recv为空,则recv继续阻塞,等待其他的数据。所以聊天的时候好好聊,别发空数据。 

复制代码

识别图中二维码,欢迎关注python宝典

文章分类
后端