博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第十二章 Python网络编程
阅读量:6692 次
发布时间:2019-06-25

本文共 6097 字,大约阅读时间需要 20 分钟。

socket编程

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

  Ip层的ip地址可以唯一标识主机,而TCP层协议和端口可以唯一标识主机的一个进程,这样可以利用IP地址+协议+端口号唯一标识网络中的一个进程

  socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。socket是一种“打开-读写-关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

套接字工作流程

  

   服务端先初始化socket,然后与端口绑定(bind),对端口进行接听(listen),调用accept阻塞,等待客户端连接。这时如果有个客户端初始化一个socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器的连接就建立了。客户端发送数据请求,服务器接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

from socket import *s=socket(AF_INET,SOCK_STREAM) #创建套接字s.bind(('127.0.0.1',8080))    #绑定IP地址和端口(0-65535)s.listen(5)conn,client_addr=s.accept()   #链接成功后返回一个链接对象:(链接对象,客户端IP和端口)#print(conn,client_addr)data=conn.recv(1024)          #每次最大收取1024bytesconn.send(data.upper())conn.close()                  #关闭客户端套接字s.close()                     #关闭服务器端套接字
服务端套接字函数s.bind()    绑定(主机,端口号)到套接字s.listen()  开始TCP监听s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来客户端套接字函数s.connect()     主动初始化TCP服务器连接s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数 s.recv()            接收TCP数据 s.send()            发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完) s.sendall()         发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完) s.recvfrom()        接收UDP数据 s.sendto()          发送UDP数据 s.getpeername()     连接到当前套接字的远端的地址 s.getsockname()     当前套接字的地址 s.getsockopt()      返回指定套接字的参数 s.setsockopt()      设置指定套接字的参数 s.close()           关闭套接字
 
面向锁的套接字方法 s.setblocking()     设置套接字的阻塞与非阻塞模式 s.settimeout()      设置阻塞套接字操作的超时时间 s.gettimeout()      得到阻塞套接字操作的超时时间 面向文件的套接字的函数 s.fileno()          套接字的文件描述符 s.makefile()        创建一个与该套接字相关的文件

基于TCP的套接字

#TCP服务端from socket import *s=socket(AF_INET,SOCK_STREAM)s.bind(('127.0.0.1',8080))s.listen(5)while True:                         #建立和多个客户端链接    print('starting...')    conn,client_addr=s.accept()     #阻塞情况1    print(client_addr)    while True:        try:            data=conn.recv(1024)        #阻塞情况2            if not data:break           #针对linux断开链接后会一直收空消息的处理            print('客户端消息',data)            conn.send(data.upper())        except ConnectionResetError:    #非正常断开链接处理            break    conn.close()
#TCP客户端from socket import *c=socket(AF_INET,SOCK_STREAM)c.connect(('127.0.0.1',8080))while True:    msg=input("message:").strip()    if not msg:continue             #客户端发送空消息处理    c.send(msg.encode('utf-8'))    data=c.recv(1024)    print(data)c.close()
#模拟ssh通信from socket import *import subprocessimport structserver=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1',8081))server.listen(5)print('starting...')conn,client_addr=server.accept()print(client_addr)while True:    try:        cmd=conn.recv(8096)        if not cmd:break        obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,                         stdout=subprocess.PIPE,                         stderr=subprocess.PIPE,                         )        stdout=obj.stdout.read()        stderr=obj.stderr.read()        #制作固定长度的报头        total_size=len(stdout)+len(stderr)        headers=struct.pack('i',total_size)        # 发送命令的长度        conn.send(headers)        #发送命令的执行结果        conn.send(stdout)        conn.send(stderr)    except ConnectionResetError:        breakconn.close()server.close()
模拟ssh通信_服务端
#模拟ssh通信from socket import *import structclient=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8081))while True:    cmd=input("message:").strip()    if not cmd:continue    client.send(cmd.encode('utf-8'))    #接收命令长度    headers=client.recv(4)    total_size=struct.unpack('i',headers)[0]    #接收命令结果    recv_size=0    data=b''    while recv_size < total_size:        recv_data=client.recv(1024)        data+=recv_data        recv_size+=len(recv_data)    print(data.decode('gbk'))client.close()
模拟ssh通信_客户端

粘包现象及解决方案

  只有TCP有粘包现象,UDP没有。粘包问题主要是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的。

#服务端from socket import *import timeserver=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1',8081))server.listen(5)print('starting...')conn,client_addr=server.accept()res1=conn.recv(1)print('res1:',res1)time.sleep(6)res2=conn.recv(10)print('res2',res2)conn.close()server.close()
#客户端from socket import *import timeclient=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8081))client.send('hello'.encode('utf-8'))time.sleep(5)client.send('world'.encode('utf-8'))client.close()

  解决粘包现象

from socket import *import subprocessimport structimport jsonserver=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1',8081))server.listen(5)print('starting...')conn,client_addr=server.accept()print(client_addr)while True:    try:        cmd=conn.recv(8096)        if not cmd:break        obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,                         stdout=subprocess.PIPE,                         stderr=subprocess.PIPE,                         )        stdout=obj.stdout.read()        stderr=obj.stderr.read()        #制作固定长度的报头        headers = {            'filepath': 'a.txt',            'md5': 'fdgre343fg',            'total_size': len(stderr)+len(stdout)        }        headers_json = json.dumps(headers)        headers_bytes = headers_json.encode('utf-8')        #发送报头的长度        conn.send(struct.pack('i',len(headers_bytes)))        # 发送报头        conn.send(headers_bytes)        #发送命令的执行结果        conn.send(stdout)        conn.send(stderr)    except ConnectionResetError:        breakconn.close()server.close()
服务端
from socket import *import structimport jsonclient=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8081))while True:    cmd=input("message:").strip()    if not cmd:continue    client.send(cmd.encode('utf-8'))    #接收报头长度    headers_size=struct.unpack('i',client.recv(4))[0]    #接收报头    headers_bytes=client.recv(headers_size)    headers_json=headers_bytes.decode('utf-8')    headers_dic=json.loads(headers_json)    total_size=headers_dic['total_size']    #接收命令结果    recv_size=0    data=b''    while recv_size < total_size:        recv_data=client.recv(1024)        data+=recv_data        recv_size+=len(recv_data)    print(data.decode('gbk'))client.close()
客户端

 

转载于:https://www.cnblogs.com/iamluoli/p/8398021.html

你可能感兴趣的文章
aaa认证
查看>>
linux系统查找具体进程
查看>>
c#执行Oracle存储过程
查看>>
adb_安装软件
查看>>
廖雪峰官网学习js 字符串
查看>>
phpcms 如何获取文章
查看>>
C# 如何防止重放攻击(转载)
查看>>
C#匿名类型
查看>>
ActiveMQ
查看>>
Nginx服务器部署 负载均衡 反向代理
查看>>
C++学习笔记:指向函数的指针
查看>>
Child Action
查看>>
# 2017-2018-1 20155319 实验五 《通讯协议设计》
查看>>
通用后台管理系统(1)-数据库设计
查看>>
做自适应网页
查看>>
ACM的奇计淫巧_bitset优化
查看>>
centos 配置防火墙操作
查看>>
比亚迪速锐F3专用夏季座套 夏天坐垫 四季坐套
查看>>
Java web 实现 之 Filter分析ip统计网站的访问次数
查看>>
bzoj1303
查看>>