SOCKET编程
本节内容:
1. Socket语法及相关
2. SocketServer实现多并发 
SOCKET语法及相关
socket概念
socket本质上就是在2台⽹络互通的电脑之间,架设⼀个通道,两台电脑通过这个通道来实现数据的互相传递。我们知道⽹络通信都是基于 ip+port ⽅能定位到⽬标的具体机器上的具体服务,操作系统有0-65535个端⼝,每个端⼝都可以独⽴对外提供服务,如果把⼀个公司⽐做⼀台电脑,那公司的总机号码就相当于ip地址,每个员⼯的分机号就相当于端⼝,你想公司某个⼈,必须先打电话到总机,然后再转分机。
建⽴⼀个socket必须⾄少有2端,⼀个服务端,⼀个客户端,服务端被动等待并接收请求,客户端主动发起请求,连接建⽴之后,双⽅可以互发数据。
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通常仅限于⾼级⽤户或管理员运⾏的程序使⽤。
socket.SOCK_SEQPACKET #废弃了
Socket ⽅法
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
sk.bind(address)
sk.listen(backlog)
  开始监听传⼊连接。backlog指定在拒绝连接之前,可以挂起的最⼤连接数量。
backlog等于5,表⽰内核已经接到了连接请求,但服务器还没有调⽤accept进⾏处理的连接个数最⼤为5
这个值不能⽆限⼤,因为要在内核中维护连接队列
sk.setblocking(bool)
  是否阻塞(默认True),如果设置False,那么accept和recv时⼀旦⽆数据,则报错。
sk.accept()
  接受连接并返回(conn,address),其中conn是新的套接字对象,可以⽤来接收和发送数据。address是连接客户端的地址。
  接收TCP 客户的连接(阻塞式)等待连接的到来
  连接到address处的套接字。⼀般,address的格式为元组(hostname,port),如果连接出错,返回so
<错误。
  同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061
sk.close()
  关闭套接字
  接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。
  与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
sk.send(string[,flag])
  将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能⼩于string的字节⼤⼩。即:可能未将指定内容全部发送。
sk.sendall(string[,flag])
  将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
内部通过递归调⽤send,将所有内容发送出去。
sk.sendto(string[,flag],address)
  将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要⽤于UDP协议。
sk.settimeout(timeout)
  设置套接字操作的超时期,timeout是⼀个浮点数,单位是秒。值为None表⽰没有超时期。⼀般,超时期应该在刚创建套接字时设置,因为它们可能⽤于连接的操作(如 client 连接最多等待5s )
  返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
  返回套接字⾃⼰的地址。通常是⼀个元组(ipaddr,port)
sk.fileno()
  套接字的⽂件描述符
socket.sendfile(file, offset=0, count=None)
发送⽂件,但⽬前多数情况下并⽆什么卵⽤。
socket server端
import socket
# 定义协议类型,默认可以对照上⾯参考
server = socket.socket()  # 声明SOCKET类型,同时⽣成SOCKET连接对象server.bind(('localhost',6999))  # 绑定监听端⼝
server.listen()  # 监听,最⼤多少个连接,挂起的连接
print('kaishi deng dianhua')
while True:
conn, addr = server.accept()  # 等电话打进来
print('dianhua lai le')
print(conn, addr)  # CONN就是客户端连过来⽽在服务器端为其⽣成的⼀个连接实例    while True:
data = v(1024)  # 接收消息
print('recv:', data)
if not data:
print('close conn')
break
conn.send(data.upper())  # 发送
# conn.sendall() # 发送全部,不⼀定会好使
server.close() 
客户端
# !/usr/bin/env python
# _*_coding:utf-8_*_
# Author:Joker
import socket
# 定义协议类型,默认可以对照上⾯参考
client = socket.socket()  # 声明SOCKET类型,同时⽣成SOCKET连接对象t(('localhost',6999))
while True:
msg = input('>>>:').strip()
if len(msg) == 0:continue
client.de('utf-8'))
data = v(1024)  # 1024 字节
print('recv',data.decode())
client.close()
利⽤socket模拟ssh远程执⾏命令
# !/usr/bin/env python
# _*_coding:utf-8_*_
# Author:Joker
import socket
import os,time
server = socket.socket()
server.bind(('localhost', 9996))
server.listen()
while True:
conn, addr = server.accept()
print('new conn:', addr)
while True:
data = v(1024)
if not data:
print('客户端已断开')
break
print('执⾏指令:', data)
cmd_res = os.popen(data.decode()).read()
if len(cmd_res) == 0:
cmd_res = 'cmd has no output'
conn.send(str(len(de())).encode('utf-8'))  # 发送⼤⼩给客户端
# time.sleep(1) # 通过缓冲区超时,来解决粘包问题
client_ack = v(1024) # wait client to confirm # 等待确认
print('ack from client:',client_ack)
conn.send(de('utf-8'))
server.close() 
client
# !/usr/bin/env python
# _*_coding:utf-8_*_
# Author:Joker
import socket
client = socket.socket()
while True:
cmd = input('>>>:').strip()
if len(cmd) == 0:continue
client.de('utf-8'))
cmd_res_size = v(1024)  # 接收命令结果的长度
print('命令结果⼤⼩',cmd_res_size)
client.send('我准备好了'.encode())
received_size = 0
received_data = b''
while received_size < int(cmd_res_size.decode()):
data = v(1024)
received_size += len(data)    # 每次收到的有可能⼩于1024,所以必须⽤LEN判断
else:
print('receve done',received_size)
print(received_data.decode())
client.close()
# 因为缓冲区的问题,很可能会执⾏的命令的结果缓冲在这个BUFFERS⾥⾯,所以客户端再收的时候会从这个BUFFERS⾥⾯取   
利⽤socket模拟ftp
socket server端
# !/usr/bin/env python
# _*_coding:utf-8_*_
# Author:Joker
import socket,hashlib
import os
server = socket.socket()
server.bind(('localhost', 9996))
server.listen()
while True:
conn,addr = server.accept()
while True:
print('等待指令')
data = v(1024)
if not data:
print('客户端已断开')
break
cmd, filename = data.decode().split() # GET FILENAME
print(filename)
if os.path.isfile(filename):
f = open(filename, 'rb')
m = hashlib.md5()
file_size = os.stat(filename).st_size
conn.send(str(file_size).encode()) # SEND FILENAME
for line in f:
m.update(line)
conn.send(line) # 发送
print('file md5',m.hexdigest())
f.close()
conn.send(m.hexdigest().encode()) # 最后发送MD5值
print('send done')
server.close()
client
# !/usr/bin/env pythonsocket通信报文格式
# _*_coding:utf-8_*_
# Author:Joker
import socket,hashlib
client = socket.socket()

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。