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继续阻塞,等待其他的数据。所以聊天的时候好好聊,别发空数据。
 


发表评论