Python开发之路-socket server
1.socket server实现并发
- 服务端:
- import socketserver
- class Myserver(socketserver.BaseRequestHandler): #来一个链接产生一个实例
- def handle(self): #定义了一个通信循环的功能
- print(\'conn是:\',self.request) #相当于conn 既accept接收到的连接
- print(self.client_address) #相当于addr 既accept接收到的addr地址
- while True:
- try:
- #收消息
- data = self.request.recv(1024)
- if not data: break
- print(\'收到客户端的消息是:\',data,self.client_address)
- #发消息
- self.request.sendall(data.upper())
- except Exception as e:
- print(e)
- break
- if __name__ == \'__main__\':
- s = socketserver.ThreadingTCPServer((\'127.0.0.1\',8000),Myserver) #多线程的TCP服务端 第一个参数是IP和端口 第二个参数相当于把通信循环加进去了
- s.serve_forever() #这两项相当于实现了链接循环 只要有链接进来 直接进入通信循环 执行myserver下的handle方法
UDP版本:
- #UDP版本
class Myserver(socketserver.BaseRequestHandler): #来一个链接产生一个实例
def handle(self): #定义了一个通信循环的功能
while True:
data = self.request[0]
print(data)
self.request[1].sendto(self.request[0].upper(),self.client_address)
2.socketserver模块
socketserver中两大类:第一类:server类,处理链接 第二类:request类,处理通信
server类:
request类:
继承关系:
- +------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
Forking:进程
Threading:线程
对于TCP来说,self.request = conn
对于UDP来说,self.request = (data_bytes,UDP的套接字对象)
FTP:文件传输协议
3.认证客户端链接的合法性
利用hmac+加盐的方式来实现
客户端:
- #_*_coding:utf-8_*_
- __author__ = \'Linhaifeng\'
- from socket import *
- import hmac,os
- secret_key=b\'linhaifeng bang bang bang\'
- def conn_auth(conn):
- \'\'\'
- 认证客户端链接
- :param conn:
- :return:
- \'\'\'
- print(\'开始验证新链接的合法性\')
- msg=os.urandom(32)
- conn.sendall(msg)
- h=hmac.new(secret_key,msg) #将盐和随机产生的32位数组合生成一个新值
- digest=h.digest() #将新值转化为数字
- respone=conn.recv(len(digest)) #接收与数字同等长度的值
- return hmac.compare_digest(respone,digest) #将接收到的值和自己的值做比较,返回一个True或False
- def data_handler(conn,bufsize=1024):
- if not conn_auth(conn):
- print(\'该链接不合法,关闭\')
- conn.close()
- return
- print(\'链接合法,开始通信\')
- while True:
- data=conn.recv(bufsize)
- if not data:break
- conn.sendall(data.upper())
- def server_handler(ip_port,bufsize,backlog=5):
- \'\'\'
- 只处理链接
- :param ip_port:
- :return:
- \'\'\'
- tcp_socket_server=socket(AF_INET,SOCK_STREAM)
- tcp_socket_server.bind(ip_port)
- tcp_socket_server.listen(backlog)
- while True:
- conn,addr=tcp_socket_server.accept()
- print(\'新连接[%s:%s]\' %(addr[0],addr[1]))
- data_handler(conn,bufsize)
- if __name__ == \'__main__\':
- ip_port=(\'127.0.0.1\',9999)
- bufsize=1024
- server_handler(ip_port,bufsize)
客户端:
- #_*_coding:utf-8_*_
- __author__ = \'Linhaifeng\'
- from socket import *
- import hmac,os
- secret_key=b\'linhaifeng bang bang bang\'
- def conn_auth(conn):
- \'\'\'
- 验证客户端到服务器的链接
- :param conn:
- :return:
- \'\'\'
- msg=conn.recv(32)
- h=hmac.new(secret_key,msg)
- digest=h.digest()
- conn.sendall(digest)
- def client_handler(ip_port,bufsize=1024):
- tcp_socket_client=socket(AF_INET,SOCK_STREAM)
- tcp_socket_client.connect(ip_port)
- conn_auth(tcp_socket_client)
- while True:
- data=input(\'>>: \').strip()
- if not data:continue
- if data == \'quit\':break
- tcp_socket_client.sendall(data.encode(\'utf-8\'))
- respone=tcp_socket_client.recv(bufsize)
- print(respone.decode(\'utf-8\'))
- tcp_socket_client.close()
- if __name__ == \'__main__\':
- ip_port=(\'127.0.0.1\',9999)
- bufsize=1024
- client_handler(ip_port,bufsize)
客户端