套接字工作流程
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
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 参数
s.bind(address) 绑定(host,port)
s.listen(backlog) 开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量
s.accept() 接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
s.connect(address) address的格式为元组(hostname,port)
s.setblocking(bool) 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。
s.close() 关闭套接字
s.recv(bufsize) bufsize指定最多可以接收的数量
s.send(string) 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。
s.sendall(string) 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
内部通过递归调用send,将所有内容发送出去。
s.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在
刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )
s.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)
服务端
- 创建socket对象
- 绑定IP和端口 绑定 bind()
- 开始监听链接 监听 listen()
- 阻塞 , 等待客户端成功连接 阻塞 accept()
- 接收请求数据 接收 recv()
- 处理并发送请求数据 发送 send()
- 关闭 close()
客户端
- 创建socket对象
- 连接服务端 , 按照IP和端口连接 连接 connet()
- 发送请求数据 发送 send()
- 接收请求数据 接收 recv()
- 关闭 close()
简单socket
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 重用ip和端口 ,但其它client只是挂起状态。只有一个能交互
import socket # 创建socket对象 sock = socket.socket() # 绑定IP和端口,参数是一个元组(ip,port) sock.bind(('localhost', 8080)) # 开始监听,最大挂起5个 sock.listen(5) # 阻塞,等待连接 conn,addr = sock.accept() # 接收请求数据,接收大小为1024字节 content = conn.recv(1024) print(content.decode()) # 发送请求结果,必须以bytes类型 conn.send(b'jieshouwanbi') # 关闭链接 conn.close()
import socket # 创建socket对象 sock = socket.socket() # 建立链接 sock.connect(('localhost', 8080)) # 发送请求数据,必须以bytes类型 sock.send(b"hello") # 接收请求结果 content = sock.recv(1024) print(content.decode()) # 关闭套接字 sock.close()
SSH
1 import socket ,os 2 server = socket.socket() #创建socket对象 3 server.bind(('localhost',9999) ) #绑定ip和port 4 server.listen() #开始监听 5 6 while True: 7 conn, addr = server.accept() #阻塞 等待连接 8 print("new conn:",addr) 9 while True: 10 print("等待新指令") 11 data = conn.recv(1024) #接收客户端发过来的命令 12 if not data: 13 break 14 print("执行指令:",data) 15 cmd_res = os.popen(data.decode()).read() #执行客户端发过来的命令,返回信息长度(接收字符串,执行结果也是字符串) 16 print("before send",len(cmd_res)) #信息的长度 17 if len(cmd_res) ==0: 18 cmd_res = "cmd has no output..." 19 20 conn.send( str(len(cmd_res.encode())).encode("utf-8") ) #先发命令执行的结果信息大小给客户端 21 client_ack = conn.recv(1024) #防止粘包,客户端ack 22 conn.send(cmd_res.encode("utf-8")) #发送信息 23 print("send done") 24 25 server.close()