python-socket

python之socket编程

socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”向网络发出请求或者应答网络请求。socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

一些常用功能

sk.bind((“ip’”port))

在默认的AF_INET下这样以元组的形式存在

sk.listen(backlog)

开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量
backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5
这个值不能无限大,因为需要在内核中维护连接队列

sk.setblocking(bool)

是否阻塞(默认为True),如果设置False,那么accept和recv时一旦无数据,就会报错

sk.accept()

接收连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据,address是连接客户端的地址
接收TCP客户端的连接(阻塞)等待连接的到来

sk.connect(address)

连接到address处的套接字,一般,address的格式为元组(hostname,port),如果连接出错,返回socket,error错误

sk.connect_ex(address

同上的sk.connect只不过会有返回值,连接成功时返回0,连接失败时返回编码

sk.close()

闭套接字

sk.recv(bufsize[,flag])

接收套接字的数据,数据以字符串形式返回,bufsize指定最多可以接收的数量,flag提供有关消息的其他信息,通常可以忽略

sk.recvfrom(bufsize[.flag])

recv()类似,但返回值是(data,address)其中data是包含接收数据的字符串,address是发送数据的套接字地址

sock.send(string[,flag])

将string中的数据发送到连接的套接字,返回值是要发送的字节数量,该数量可能小于string的字节大小,即:可能未将指定内容全部发送

sk.sendall(string[,flag])

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有的数据,成功返回None,失败则抛出异常
内部通过递归调用send,将所有内容发送出去

sk.sendto(string[,flag],address)

将数据发送到套接字,address是形式为(ip地址,port)的元组,指定远程地址,返回值时发送的字节数,该函数主要用于UDP协议

sk.settimeout(timeout)

设置套接字操作的超时期,timeout是一个浮点数,但是为秒
值为None表示没有超时期,一般超时期应该在刚创建套接字时设置,因为他们可能用于连接的操作

sk.getpeername()

返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)

sk.fileno()

套接字的文件描述符

一个socket例子

机器人对话

服务端
#!/usr/bin/python
# -*-coding:utf-8-*-
# Author:Gsuhy

import socketserver

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        conn = self.request
        conn.sendall(bytes("hello,我是Gsuhy",encoding="utf-8"))
        while True:
            ret_bytes = conn.recv(1024)
            ret_str = str(ret_bytes,encoding="utf-8")
            if ret_str == 'q':
                break
            conn.sendall(bytes(ret_str + "你好!",encoding="utf-8"))

if __name__ == "__main__":
    server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Myserver)
    server.serve_forever()

----------------------
客户端
#!/usr/bin/python
# -*-coding:utf-8-*-
# Author:Gsuhy

import socket

obj = socket.socket()
obj.connect(('127.0.0.1',8080))

ret_bytes = obj.recv(1204)
ret_str = str(ret_bytes,encoding="utf-8")
print(ret_str)

while True:
    inp = input("你要干什么??? \n>>>")
    if inp =="q":
        obj.sendall(bytes(inp,encoding="utf-8"))
        break
    else:
        obj.sendall(bytes(inp,encoding="utf-8"))
        ret_bytes = obj.recv(1204)
        ret_str = str(ret_bytes, encoding="utf-8")
        print(ret_str)

obj.close()
----------------------
先运行服务端,再运行客户端
output:
hello,我是Gsuhy
你要干什么???
>>>123123
123123你好!
你要干什么???
>>>

IO多路复用

I/O(input/output),即输入/输出端口。每个设备都会有一个专用的I/O地址,用来处理自己的输入输出信息首先什么是I/O:
I/O分为磁盘io和网络io,这里说的是网络io

IO多路复用:

I/O多路复用指:通过一种机制,可以监视多个描述符(socket),一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

Linux

Linux中的 select,poll,epoll 都是IO多路复用的机制。
Linux下网络I/O使用socket套接字来通信,普通I/O模型只能监听一个socket,而I/O多路复用可同时监听多个socket.
I/O多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理.

Python

Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。

socketserver

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。

ThreadingTCPServer

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

ThreadingTCPServer基础

使用ThreadingTCPServer

  • 创建一个继承自SocketServer.BaseRequestHandle的类
  • 类中必须定义一个名称为Handle的方法
  • 启动ThreadingTCPServer

ThreadingTCPServer内部调用流程

  • 启动服务端程序
  • 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
  • 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类MyRequestHandle赋值给 self.RequestHandlerClass
  • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 …
  • 当客户端连接到达服务器
  • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
  • 执行 ThreadingMixIn.process_request_thread 方法
  • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)

   转载规则


《python-socket》 Gsuhy 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录