网络编程

Socket介绍

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket是一种通用的网络编程接口,和网络层次没有一一对应关系。

Python中提供socket.py标准库,非常底层的接口库。
协议族:
AF表示Address Family,用于socket()第一个参数。

AF_INET IPV4
AF_INET IPV6

Socket有两种类型

  • SOCK_STREAM 面向连接的流套接字。TCP协议
  • SOCK_DGRAM 无连接的数据报文套接字,UDP协议

TCP编程

Socket编程,需要两端,一般来说一个服务端,一个客户端。

TCP服务端步骤:
1)创建Socket对象
2)绑定IP地址Address和端口Port。 bind()方法 端口对应的就是进程
3)开始监听,将在指定的IP端口上监听。listen()方法。
4)获取用于传送数据的Socket对象
socket.accept() -> (socket object, address info)
accept方法阻塞等待客户端建立连接,返回一个Socket对象和客户端地址的二元组。
地址是远程客户端的地址,IPV4它是一个二元组(clientaddr, port)
5)接收数据:recv(bufsize[, flags]) 使用缓冲区接收数据
发送数据:send(bytes) 发送数据
6)关闭资源

示例

import time
#TCP Server
sock = socket.socket() #默认IPv4,TCP 
ip = '127.0.0.1'
port = 9999 # 整数
addr = (ip, port)
sock.bind(addr) # 绑定IP和端口
sock.listen()  #监听
conn, addrinfo = sock.accept() #返回一个socket对象和一个远端地址,默认阻塞
data = conn.recv(1024) # 接收数据
print(data)
msg = '已接收到数据 {}'.format(data.decode())
conn.send(msg.encode()) #传送字节流数据
conn.close()
sock.close()

socket常用方法

方法描述
socket.recv(bufsize[, flags])获取数据,默认是阻塞方式
socket.recvfrom(bufsize[, flags])获取数据,返回一个二元组(bytes, address)
socket.recv_into(buffer[, nbytes[, flags]])获取到nbytes数据后,存储到buffer中。如果nbytes没有指定或0,将buffer大小的数据存入buffer中。返回接收的字节数
socket.recvfrom_into(buffer[, nbytes[, flags])获取数据,返回一个二元组(bytes, address)到buffer中。
socket.send(bytes[, flags)TCP发送数据
socket.sendall(bytes[, flags)TCP发送全部数据,成功返回None
s.sendto(string[,flags],address)UDP发送数据
socket.sendfile(file, offset=0, count=None)发送一个文件直到EOF,使用高性能的os.sendfile机制,返回发送的字节数。
socket.makefile(mode='r', buffering=None,* ,encoding=None, errors=None, newline=None)创建一个与该套接字相关联的文件对象。
  • makefile示例
import threading
import socket
import logging
import time
logging.basicConfig(level=logging.INFO, format='%(thread)d %(threadName)s %(message)s')

#TCP Server
sock = socket.socket() #默认IPV4 TCP
ip = '127.0.0.1'
port = 9999 # 整数
addr = (ip, port)
sock.bind(addr) # 绑定IP和端口
sock.listen()  #监听
conn, addrinfo = sock.accept() #返回一个socket对象和一个远端地址,默认阻塞

f = conn.makefile(mode='rw')
line = f.read(10)
print(line)
f.write('Return your msg:{}'.format(line))
f.flush()
f.close()

UDP服务端:

大致与TCP相似, 具体如下
1)创建socket对象
2)绑定IP和port
3)传输数据
接收数据:socket.recvfrom(bufsize[,flags])
发送数据: socket.sendto(string, address)
4)释放资源
UDP客户端:
1)创建socket对象
2)发送数据:socket.sendto(string, address) 发给某地址某信息
3)释放资源

Socketserver

socket编程过于底层,所以很多语言都对socket底层API进行了封装,Python的封装就是socketserver模块

SocketServer简化了网络服务器的编写。
它有4个同步类TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer
2个Mixin类ForkingMixin和ThreadingMixin来支持异步。
class ForingUDPServer(ForkingMixin, UDPServer): Pass
class ForingTCPServer(ForkingMixin, TCPServer): Pass
class ThreadingUDPServer(ThreadingMixin, UDPServer): pass
class ThreadingTCPServer(ThreadingMixin, TCPServer): pass

编程接口:

  • socketserver.BaseServer(server_address, RequestHandlerClass)

需要提供服务器绑定的地址信息,和用于处理请求的RequestHandlerClass类。

  • RequestHandlerClass类必须是BaseRequestHandlerClass的子类
  • BaseRequestHandlerClass

和用户连接(socket连接)的用户请求处理类,Server实例接收用户请求后,
最后会实例化这个类。
它被初始化后,送入3个构造参数:request、client_address、server
以后可以在BaseRequestHandlerClass类的实例上通过。
self.request是和客户端连接的socket对象
self.server是TCPServer的本身
self.client_address是客户端地址。
它会一次调用3个函数,子类可以覆盖。

BaseRequestHandlerClass: #要子类覆盖的方法
    def setup(self): #每一个连接初始化
        pass
    def handle(self): #每一次请求处理
        pass
    def finish(self): #每一个连接清理
        pass

示例

import socketserver
import threading
# 处理用户请求
class MyHandler(socketserver.BaseRequestHandler):

    def setup(self):
        super().setup()
        # TODO
        self.event = threading.Event()

    def handle(self):
        super().handle()
        print(self.server, self.client_address, self.request)
        # 循环,没有循环,连接处理直接断掉了
        while not self.event.is_set():
            data = self.request.recv(1024).decode()
            msg = "Your msg={}".format(data)
            print(msg)
            self.request.send(msg.encode())
            if not data:
                break

    def finish(self):
        super().finish()


#启动服务 服务器绑定地址
ADDR = ('127.0.0.1', 9999)
server = socketserver.ThreadingTCPServer(ADDR, MyHandler)
server.serve_forever()

server.shutdown()
server.server_close()

总结:
创建服务器的步骤
1.通过对BaseRequestHandler类进行子类化,并覆盖handle()方法来创建请求处理类,此方法将处理传入请求
2.必须实例化一个服务器类,将它传递服务器的地址和请求处理程序类。
3.调用服务器对象的handle_request()或者server_forever()方法
4.调用socket_close()关闭套接字。shutdown()方法等待停止forever()方法


leafgood
183 声望15 粉丝

踏入IT这个圈子,就成了一名玩家,想要走的更远,就要不断给自己技能加点才行。