day7-socket网络编程
1. socket模块提供访问BSD套接字接口,伯克利套接字(Berkeley sockets),也称为BSD Socket。伯克利套接字的应用编程接口(API)是采用C语言的进程间通信的库,经常用在计算机网络间的通信。
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
·socket address 是一个由地址和端口组成的元组('0.0.0.0',9999)
`Socket Families(地址簇) socket.AF_UNIX unix本机进程间通信 socket.AF_INET IPV4 socket.AF_INET6 IPV6
`Socket Types socket.SOCK_STREAM #for tcp socket.SOCK_DGRAM #for udp socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。 socket.SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
server = socket.socket()
server.bind(('localhost',9996)) #服务端绑定;
server.listen() #监听;
server.setblocking(bool) 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。
conn,addr = server.accept() 获取一个连接
data = conn.recv(1024) 接收数据;
conn.send(str(file_size).encode('UTF-8')) 发送数据;
conn.sendall(str(file_size).encode('UTF-8')) 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
conn.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )
conn.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)
2. 举例,简单的下载文件;
server:
import socket,os,hashlib server = socket.socket() server.bind(('localhost',9996)) server.listen() while True: conn,addr = server.accept() while True: data = conn.recv(1024) if not data: print('the client has been disconnect') break cmd,file_name = data.decode().split() if os.path.isfile(file_name): file_size = os.stat(file_name).st_size conn.send(str(file_size).encode('UTF-8')) recv_msg = conn.recv(1024) md5 = hashlib.md5() with open(file_name,'rb') as f: for line in f: md5.update(line) conn.send(line) print('123') conn.send(md5.hexdigest().encode()) print(md5.hexdigest().encode()) else: print('File not exists!!') conn.send(b'File not exists!!') server.close()
client:
import socket,os,hashlib client = socket.socket() client.connect(('localhost',9996)) while True: msg = input('>>:') if msg.startswith('get'): client.send(msg.encode('UTF-8')) file_size = client.recv(1024).decode() if file_size == 'File not exists!!': print(file_size) continue client.send(b'ready to receive') recv_size = 0 file_name = msg.split()[1] file_size = int(file_size) md5 = hashlib.md5() if file_size: with open(file_name+'.new','wb') as f: while recv_size < file_size: if file_size - recv_size > 1024: size = 1024 else: size = file_size - recv_size print('last size',size) # print('recv,total', recv_size, file_size) data = client.recv(size) md5.update(data) recv_size += len(data) # print('recv,total1', recv_size, file_size) f.write(data) f.flush() else: print('123') md5_server = client.recv(1024) print('get done') print('recv,total',recv_size,file_size) print('md5',md5.hexdigest(),md5_server) else: print('File size is zero!!!') else: continue client.close()
3. socketserver:
·常用的两种类型:
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
·本地通信,对应socket.AF_UNIX,不常用;
class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
·创建一个socketserver 至少分以下几步:
First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests. (创建一个handler类并重写handle()方法)
Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.(实例化,将地址和请求地址传给handle类,所有与客户端的交互都在handle方法中实现)
Then call the handle_request() orserve_forever() method of the server object to process one or many requests.
Finally, call server_close() to close the socket.
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): """ The request handler class for our server. It is instantiated once per connection to the server, and must override the handle() method to implement communication to the client. """ def handle(self): # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) # just send back the same data, but upper-cased self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 9999 # Create the server, binding to localhost on port 9999 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) # Activate the server; this will keep running until you # interrupt the program with Ctrl-C server.serve_forever()
·并发的话,可以使用以下方式:socketserver.TCPServer换成以下对应类型;
让你的socketserver并发起来, 必须选择使用以下一个多并发的类 class socketserver.ForkingTCPServer class socketserver.ForkingUDPServer class socketserver.ThreadingTCPServer class socketserver.ThreadingUDPServer

浙公网安备 33010602011771号