您的位置:澳门新葡8455最新网站 > 澳门新葡8455最新网站 > 网络编程

网络编程

发布时间:2019-10-14 03:47编辑:澳门新葡8455最新网站浏览(63)

    Socket套接字方法

     

    socket 实例类(8-10分钟)

    socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
    

     family***(*socke*t家族)***

    • socket.AF_UNIX:用于本机进度间通讯,为了确定保障程序安全,多少个单身的主次(进度)间是无法相互访谈互相的内部存款和储蓄器的,但为了促成进度间的通信,可以透过创建贰个本地的socket来完毕
    • socket.AF_INET:(还有AF_INET6被用于ipv6,还也可以有一部分其余的地方家族,可是,他们也许是只用于某些平台,要么正是现已被撇下,恐怕是非常少被采用,可能是平素未有完结,全部地方家族中,AF_INET是采用最普遍的三个,python支持很二种地方家族,不过出于大家只关怀互联网编制程序,所以大多数时候作者么只行使AF_INET)

     socket type***类型***

    • socket.SOCK_STREAM #for tcp
    • socket.SOCK_DGRAM #for udp
    • socket.SOCK_RAW #原始套接字,普通的套接字不或者管理ICMP、I地霉素P等互连网报文,而SOCK_RAW可以;其次,SOCK_RAW也得以拍卖极其的IPv4报文;另外,利用原始套接字,能够经过IP_HDOdysseyINCL套接字选项由客商构造IP头。
    • socket.SOCK_RDM #是一种保证的UDP格局,即确认保证交到数据报但不保险顺序。SOCK_RAM用来提供对原来公约的中低端访问,在须求实行有个别特殊操作时选拔,如发送ICMP报文。SOCK_RAM平常只限于高等顾客或领队运营的顺序选择。
    • socket.SOCK_SEQPACKET #废弃了

    (Only SOCK_STREAM and SOCK_DGRAM appear to be generally useful.)

     proto=0 请忽视,特殊用途

     fileno=None 请忽视,特殊用途

    劳动端套接字函数(2分钟)

    • s.bind() 绑定(主机,端口号)到套接字
    • s.listen() TCP起首监听传入连接。backlog钦点在不肯连接此前,能够挂起的最浦那接数量。 backlog等于5,表示内核已经抽出了一连诉求,但服务器还未曾调用accept进行拍卖的一连个数最大为5, 那么些值不能够最棒大,因为要在根本中保养连接队列
    • s.accept() 被动接受TCP客商的连接,(阻塞式)等待连接的到来 
      服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。
    

     

    客商端套接字函数(2分钟)

    • s.connect() 主动早先化TCP服务器连接
    • s.connect_ex() connect()函数的扩张版本,出错时回来出错码,而不是抛出分外

    公物用途的套接字函数(3-5分钟)

    • s.recv() 接收数据
    • s.send() 发送数据(send在待发送数据量大于己端缓存区剩余空间时,数据错过,不会发完,可前面通过实例解释)
    • s.sendall() 发送完整的TCP数据(本质正是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不放弃,循环调用send直到发完)
    • s.recvfrom() Receive data from the socket. The return value is a pair (bytes, address)
    • s.getpeername() 连接到当前套接字的远端的地址
    • s.close() 关闭套接字
    • socket.setblocking(flag) #True or False,设置socket为非阻塞形式,未来讲io异步时会用
    • socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) 重临远程主机的地址音讯,例子 socket.getaddrinfo('luffycity.com',80)
    • socket.getfqdn() 获得本机的主机名
    • socket.gethostbyname() 通过域名剖析ip地址

    tcp套接字

    1.简单套接字
    客户端和服务端:两个主要功能,1、建立链接 2、数据通讯
    服务端程序会产生两个套接字socket,一个用于三次握手建立链接,另一个用于收发消息数据通讯;
    客户端产生一个套接字socket,既可以用于建立链接后,再用于收发消息数据通讯。
    
    client.py
    

    图片 1图片 2

     1 import socket
     2 
     3 #1.买手机
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 print(phone)
     6 
     7 #2.拨号
     8 phone.connect(('127.0.0.1',8081)) 
     9 #端口范围0-65535,0-1024给操作系统用的,若一直无法连接上server,则会一直停留在这一步
    10 
    11 #3.发收消息
    12 phone.send('hello'.encode('utf-8'))
    13 data = phone.recv(1024)
    14 print(data)
    15 
    16 #4.关闭
    17 phone.close()
    

    View Code

     service.py

    图片 3图片 4

     1 import socket
     2 
     3 #1.买手机
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 print(phone)
     6 
     7 #2.绑定手机卡
     8 phone.bind(('127.0.0.1',8081)) #端口范围0-65535,0-1024给操作系统用的
     9 
    10 #3.开机
    11 phone.listen(5) # 参数表示最大监听数
    12 
    13 #4.等电话链接
    14 print('starting...')
    15 conn,client = phone.accept() #返回一个新的套接字conn用于通讯,client为发起通讯链接的客户端的ip和端口号
    16 print(conn,client)
    17 # print('===>')
    18 
    19 #5.收,发消息
    20 data = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    21 print('客户端的数据',data)
    22 conn.send(data.upper())
    23 
    24 #6.挂电话
    25 conn.close()
    26 
    27 #7.关机
    28 phone.close()
    

    View Code

     2.丰硕循环套接字

    client.py 
    

    图片 5图片 6

     1 import socket
     2 
     3 #1.买手机
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 
     6 print(phone)
     7 
     8 #2.拨号
     9 phone.connect(('127.0.0.1',8080)) #端口范围0-65535,0-1024给操作系统用的
    10 
    11 while True:
    12     msg = input('>>:').strip()
    13     if not msg:continue
    14     phone.send(msg.encode('utf-8'))  #phone.send(b'')
    15     print('has send') #判断能否发空
    16     data = phone.recv(1024)
    17     print(data.decode('utf-8'))
    18 
    19 #4.关闭
    20 phone.close()
    

    View Code

    service.py
    

    图片 7图片 8

     1 import socket
     2 
     3 
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
     6 print(phone)
     7 phone.bind(('127.0.0.1',8080)) #端口范围0-65535,0-1024给操作系统用的
     8 phone.listen(5) #最大链接挂起数
     9 
    10 print('starting...')
    11 conn,client = phone.accept() #监听
    12 # print('===>')
    13 
    14 #监听到到后,进行通讯循环
    15 # while True:
    16 #     data = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    17 #     #conn tcp协议三次握手的成果,双向链接
    18 #     if not data:break #适用与linux操作,当client单方面终止链接时,service端会出现死循环
    19 #     print('客户端的数据',data)
    20 #     conn.send(data.upper())
    21 
    22 while True:
    23     try:
    24         data = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    25         #conn tcp协议三次握手的成果,双向链接
    26 
    27         print('客户端的数据',data)
    28         conn.send(data.upper())
    29     except ConnectionResetError:
    30 
    31         break
    32 
    33 conn.close()
    34 phone.close()
    

    View Code

    if not data:break 是用于linux的判断,因为在linux中当client端单方面终止时,servce端会一直接收到空,会一直循环print('客户端的数据',data),因此需要加上判断;
    
    except ConnectionResetError: 是针对windows的,当client端单方面终止时,server端会报ConnnectionRsetError。
    
    有时重启服务端时会遇到报错:
    

    图片 9

     

    由于重启时系统还没来得及回收端口,由此会唤起端口已被并吞。

    本条是由于你的服务端照旧存在八回挥手的time_wait状态在挤占地址(假诺不懂,请深切研究1.tcp二次握手,四次挥手 2.syn洪流攻击 3.服务器高并发情形下会有雅量的time_wait状态的优化措施)

    减轻方法:参预一条socket配置,重用ip和端口。

    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind ip和端口 前加。

    或者:

    实验之前要全部关闭掉所用占用端口的程序,用以下指令
    linux:pkill -9 python
    windows:taskkill python
    

     

    3.加上 链接循环

    事先代码运转可以知道,client端关闭后,service端也会关闭,但此时大家想client端关闭后,service端应该能在接收新的client端的链接央浼,由此,在建

    立链接的局地加入循环。

    client.py 
    

    图片 10图片 11

     1 import socket
     2 
     3 #1.买手机
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 
     6 print(phone)
     7 
     8 #2.拨号
     9 phone.connect(('127.0.0.1',8080)) #端口范围0-65535,0-1024给操作系统用的
    10 
    11 while True:
    12     msg = input('>>:').strip()
    13     if not msg:continue
    14     phone.send(msg.encode('utf-8'))  #phone.send(b'')
    15     print('has send') #判断能否发空
    16     data = phone.recv(1024)
    17     print(data.decode('utf-8'))
    18 
    19 #4.关闭
    20 phone.close()
    

    View Code

    service.py
    

    图片 12图片 13

     1 import socket
     2 
     3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     4 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
     5 print(phone)
     6 phone.bind(('127.0.0.1',8080)) #端口范围0-65535,0-1024给操作系统用的
     7 phone.listen(5) #最大链接挂起数
     8 
     9 print('starting...')
    10 
    11 while True:
    12     '''
    13     用于监听多次client端的链接,但一次链接发起结束后,
    14     可继续监听下一次client端的连接
    15     '''
    16     conn,client = phone.accept()
    17     print(client)
    18     while True:
    19         try:
    20             data = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    21             #conn tcp协议三次握手的成果,双向链接
    22             if not data: break
    23             print('客户端的数据',data)
    24             conn.send(data.upper())
    25         except ConnectionResetError:
    26             break
    27     conn.close()
    

    View Code

     4.模拟ssh远程施行命令

    client.py 
    

    图片 14图片 15

     1 import socket,subprocess
     2 
     3 
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
     6 print(phone)
     7 phone.bind(('127.0.0.1',9900)) #端口范围0-65535,0-1024给操作系统用的
     8 phone.listen(5) #最大链接挂起数
     9 
    10 print('starting...')
    11 while True:
    12     conn,client = phone.accept() #监听
    13 
    14     while True: #通讯循环
    15         try:
    16             #1、收命令
    17             cmd = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    18             #conn tcp协议三次握手的成果,双向链接
    19             if not cmd: break
    20             #2、执行命令、拿到结果,命令的结果存入stdout=subprocess.PIPE管道,而不是直接输出到终端
    21             obj = subprocess.Popen(cmd.decode('utf-8'),shell=True,
    22                                    # 指令由client端发送过来是以utf-8解码为bytes发送过来的,因此处应该以utf-8来编码,
    23                                    # 因此此处的命令编码应该与client端的一致
    24                                    stdout=subprocess.PIPE,
    25                                    stderr=subprocess.PIPE)
    26             print(obj)
    27             stdout = obj.stdout.read()
    28             stderr =  obj.stderr.read() #s收发都是bytes格式
    29 
    30             #3、把命令的结果返回给客户端
    31             conn.send(stdout+stderr) #申请一块新的内存空间存放stdout+stderr,会占内存,效率会低
    32         except ConnectionResetError:
    33             break
    34     conn.close()
    35 
    36 phone.close()
    

    View Code

    service.py
    

    图片 16图片 17

     1 import socket
     2 
     3 #1.买手机
     4 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     5 
     6 print(phone)
     7 
     8 #2.拨号
     9 phone.connect(('127.0.0.1',9900)) #端口范围0-65535,0-1024给操作系统用的
    10 
    11 while True:
    12     msg = input('>>:').strip()
    13     if not msg:continue
    14     phone.send(msg.encode('utf-8'))
    15     # 注意:信息由utf-8解码为bytes格式发送到service端,因此service端也必须把bytes格式以utf-8来编码,
    16 
    17     data = phone.recv(1024)  #返回值可能超过1024bytes,
    18     print(data.decode('gbk'))
    19     # windows上,res.stdout.read()读出的就是GBK编码,因此此处也用GBK编码,linux上默认是utf-8
    20 
    21 #4.关闭
    22 phone.close()
    

    View Code

    这里注意八个小标题:

      1.service端的下令的编码应该与client端的解码格局对应,client端以utf-8解码指令为bytes,则service端必须以utf-8来编码;

      2.service端的把命令结果发送给client端,client则供给将指令结果开展编码,若serice端在windows上,则以GBK举行编码,若在linux上则以utf-8进行编码。

    5.粘包现象分析

    须知:独有TCP有粘包现象,UDP永久不会粘包

    图片 18

     

    所谓粘包难点根本照旧因为接收方不知晓新闻之间的界限,不驾驭叁回性领取多少字节的多少所导致的。

    udp的recvfrom是阻塞的,二个recvfrom(x)必需对独一三个sendinto(y),收完了x个字节的多少便是成功,若是y>x数据就不见,那意味udp根本不会粘包,可是会丢数据,离谱赖。

    tcp的会谈数据不会丢,未有收完包,下一次吸收接纳,会继续上次前赴后继接受,己端总是在摄取ack时才会免去缓冲区内容。数据是保证的,可是会粘包。

    二种境况下会发出粘包:

    出殡端要求等缓冲区满才发送出去,形成粘包(发送数据时间间隔非常的短,数据段异常的小,相会到贰头,发生粘包)。TCP使用了优化措施(Nagle算法),将每每区间非常的小且数据量小的数量,合併成三个大的数据块,然后举办封包。

    client.py
    

    图片 19图片 20

    1 import socket
    2 
    3 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    4 client.connect(('127.0.0.1',9903))
    5 
    6 #TCP使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,
    7 # 合并成一个大的数据块,然后进行封包。从而在发送端造成粘包。
    8 client.send('hello'.encode('utf-8'))
    9 client.send('world'.encode('utf-8'))
    

    View Code

    service.py
    

    图片 21图片 22

     1 import socket
     2 
     3 service = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     4 service.bind(('127.0.0.1',9903))
     5 service.listen(5)
     6 
     7 conn,addr = service.accept()
     8 
     9 res1 = conn.recv(1024)
    10 print('第一次',res1.decode())
    11 
    12 res2 =  conn.recv(1024)
    13 print('第二次',res2.decode())
    

    View Code

     输出结果:
    
    第一次 helloworld
    第二次 
    

    发送端由于TCP 优化算法形成粘包

     

    接收方不比时接收缓冲区的包,变成多少个包接收(顾客端发送了一段数据,服务端只收了一小部分,服务端下一次再收的时候照旧从缓冲区拿上次遗留的多少,发生粘包) 

     

    client.py
    

    图片 23图片 24

     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 import socket
     4 BUFSIZE=1024
     5 ip_port=('127.0.0.1',8080)
     6 
     7 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     8 res=s.connect_ex(ip_port)
     9 
    10 
    11 s.send('hello feng'.encode('utf-8'))
    12 
    13 客户端
    

    View Code

    service.py
    

    图片 25图片 26

     1 #_*_coding:utf-8_*_
     2 __author__ = 'Linhaifeng'
     3 from socket import *
     4 ip_port=('127.0.0.1',8080)
     5 
     6 tcp_socket_server=socket(AF_INET,SOCK_STREAM)
     7 tcp_socket_server.bind(ip_port)
     8 tcp_socket_server.listen(5)
     9 
    10 
    11 conn,addr=tcp_socket_server.accept()
    12 
    13 
    14 data1=conn.recv(2) #一次没有收完整
    15 data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的
    16 
    17 print('----->',data1.decode('utf-8'))
    18 print('----->',data2.decode('utf-8'))
    19 
    20 conn.close()
    21 
    22 服务端
    

    View Code

    输出结果

    -----> he
    -----> llo feng
    

    接收端由于没能二回将发送端贰次发送的数额总体收受,导致粘包

     

    拆包的产惹祸态

    当发送端缓冲区的尺寸超越网卡的MTU时,tcp会将这一次发送的数额拆成多少个数据包发送出去。

    增加补充问题一:为啥tcp是可信传输,udp是不可靠传输

    tcp在数码传输时,发送端先把数据发送到本身的缓存中,然后公约决定将缓存中的数据发往对端,对端重临三个ack=1,发送端则清理缓存中的数据,对端重临ack=0,则再次发送数据,所以tcp是牢靠的。

    而udp发送数据,对端是不会回来确认音讯的,因而不可信赖。

    补充难题二:send(字节流)和recv(1024)及sendall

    recv里钦赐的1024意思是从缓存里一遍拿出1022个字节的数量

    send的字节流是先放入己端缓存,然后由协调决定将缓存内容发往对端,假诺待发送的字节流大小大于缓存剩余空间,那么数量遗失,用sendall就能够循环调用send,数据不会吐弃。

    send 和 recv:
    1.不管是recv还是send都不是直接接收对方的数据,而是操作自己的操作系统内存-->不是一个send对应一个recv
    2.recv阶段,耗时分析:
      wait data 耗时非常长
      copy data 耗时短
      send耗时分析:
      copy data
    

    5.粘包消除办法

    粘包难点的由来在于接收端不晓得发送端就要传送的字节流的尺寸,所以化解粘包的不二法门正是围绕,如何让发送端在发送数据前,把团结将在发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完全部数据。

    首先步:先获得多少的长短

    第二步:接收真实的多寡

     先来介绍下struct模块

    该模块能够把二个类型,如数字,转成固定长度的bytes类型

    图片 27

     

    但注意类型如数字是有限量的,超过范围就能够报错

    >>> struct.pack('i',1111111111111)

    。。。。。。。。。

    struct.error: 'i' format requires -2147483648 <= number <= 2147483647  #其一是限量

    图片 28图片 29

    1 import struct
    2 
    3 res = struct.pack('i', 1235)
    4 print(res,type(res), len(res))
    5 
    6 obj = struct.unpack('i', res)
    7 print(obj)
    

    struct 用法

    出口结果

    b'xd3x04x00x00' <class 'bytes'> 4
    (1235,)
    

    在数额发送端将数据长度打包,发送给接收端,解包获取实际数据的长短。

     

     轻松版本报头自制

    client.py
    

    图片 30图片 31

     1 import socket, struct
     2 
     3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     4 print(phone)
     5 
     6 phone.connect(('127.0.0.1',9900)) #端口范围0-65535,0-1024给操作系统用的
     7 
     8 while True:
     9     #1、发命令
    10     msg = input('>>:').strip()
    11     if not msg:continue
    12     phone.send(msg.encode('utf-8'))
    13 
    14     #2、拿到命令的结果,并打印
    15 
    16     #第一步:先收报头
    17     header = phone.recv(4)
    18     #第二步:从报头中解析出对真实数据的描述信息
    19     total_size = struct.unpack('i',header)[0]
    20 
    21     #第三部:接收真实数据
    22     recv_size = 0
    23     recv_data = b''
    24     while recv_size < total_size:
    25         data = phone.recv(1024)
    26         recv_data += data
    27         recv_size += len(data)
    28 
    29     print(data.decode('gbk'))
    30     # windows上,res.stdout.read()读出的就是GBK编码,因此此处也用GBK编码,linux上默认是utf-8
    31 
    32 phone.close()
    

    自制报头

    service.py
    

    图片 32图片 33

     1 import socket,subprocess,struct
     2 
     3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     4 phone.bind(('127.0.0.1',9900)) #端口范围0-65535,0-1024给操作系统用的
     5 phone.listen(5) #最大链接挂起数
     6 
     7 print('starting...')
     8 while True:
     9     conn,client = phone.accept() #监听
    10 
    11     while True: #通讯循环
    12         try:
    13             #1、收命令
    14             cmd = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    15             #conn tcp协议三次握手的成果,双向链接
    16             if not cmd: break
    17             #2、执行命令、拿到结果,命令的结果存入stdout=subprocess.PIPE管道,而不是直接输出到终端
    18             obj = subprocess.Popen(cmd.decode('utf-8'),shell=True,
    19                                    stdout=subprocess.PIPE,
    20                                    stderr=subprocess.PIPE)
    21             print(obj)
    22             stdout = obj.stdout.read()
    23             stderr = obj.stderr.read() #s收发都是bytes格式
    24 
    25             #3、把命令的结果返回给客户端
    26             #第一步:制作固定长度的报头
    27             total_size = len(stdout)+len(stderr)
    28             header = struct.pack('i', total_size)
    29 
    30             #第二步:把报头(固定长度)发送给客户端
    31             conn.send(header)
    32 
    33             #第三步:再发送真实数据
    34             conn.send(stdout)
    35             conn.send(stderr)
    36 
    37         except ConnectionResetError:
    38             break
    39     conn.close()
    40 
    41 phone.close()
    

    自制报头

     

    高阶报头自制

    上述讲授了简短报头的自制,但有缺陷:

    1、报头存有的音讯少。

    2、struct模块打包的int数字有限量,普通指令的结果长度就算不会超过那几个界定,然则上传下载文件时就很有望会超过此限制,因而上边介绍一样运用struct模块来自制跟高档的报头。

    以字典的款型营造报头,字典中能够存文件名、文件md5值、文件大小等,再将字典连串化,将类别化的字符串长度通过struct pack,那样既可让报头存有丰盛的音信,又不会超出struct模块打包的int的数字范围。

    client.py
    

    图片 34图片 35

     1 import socket, struct, json
     2 
     3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     4 print(phone)
     5 
     6 phone.connect(('127.0.0.1',9900)) #端口范围0-65535,0-1024给操作系统用的
     7 
     8 while True:
     9     #1、发命令
    10     msg = input('>>:').strip()
    11     if not msg:continue
    12     phone.send(msg.encode('utf-8'))
    13 
    14     #2、拿到命令的结果,并打印
    15 
    16     #第一步:先收报头长度
    17     obj = phone.recv(4)
    18     header_size = struct.unpack('i',obj)[0]
    19     # 第二步:再收报头
    20     header = phone.recv(header_size)
    21 
    22     #第三步:从报头中解析出对真实数据的描述信息
    23     header_dic = json.loads(header)
    24     total_size = header_dic['total_size']
    25 
    26     #第三部:接收真实数据
    27     recv_size = 0
    28     recv_data = b''
    29     while recv_size < total_size:
    30         data = phone.recv(1024)
    31         recv_data += data
    32         recv_size += len(data)
    33 
    34     print(data.decode('gbk'))
    35     # windows上,res.stdout.read()读出的就是GBK编码,因此此处也用GBK编码,linux上默认是utf-8
    36 
    37 phone.close()
    

    高阶报头自制

    service.py
    

    图片 36图片 37

     1 import socket, subprocess, struct, json
     2 
     3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     4 phone.bind(('127.0.0.1',9900)) #端口范围0-65535,0-1024给操作系统用的
     5 phone.listen(5) #最大链接挂起数
     6 
     7 print('starting...')
     8 while True:
     9     conn,client = phone.accept() #监听
    10 
    11     while True: #通讯循环
    12         try:
    13             #1、收命令
    14             cmd = conn.recv(1024) # 单位:bytes,  1024代表最大接收1024个bytes
    15             #conn tcp协议三次握手的成果,双向链接
    16             if not cmd: break
    17             #2、执行命令、拿到结果,命令的结果存入stdout=subprocess.PIPE管道,而不是直接输出到终端
    18             obj = subprocess.Popen(cmd.decode('utf-8'),shell=True,
    19                                    stdout=subprocess.PIPE,
    20                                    stderr=subprocess.PIPE)
    21             print(obj)
    22             stdout = obj.stdout.read()
    23             stderr = obj.stderr.read() #s收发都是bytes格式
    24 
    25             #3、把命令的结果返回给客户端
    26             #第一步:制作报头
    27 
    28             header_dic = {
    29                 'filename':'a.txt',
    30                 'md5':'xxfdxxx',
    31                 'total_size': len(stdout)+len(stderr)
    32             }
    33             header_json = json.dumps(header_dic)
    34             header_types = header_json.encode('utf-8')
    35 
    36             #第二步:把报头(固定长度)发送给客户端
    37             conn.send(struct.pack('i',len(header_types)))
    38 
    39             #第三步:再发送报头、
    40             conn.send(header_types)
    41 
    42             #第四步:再发送真实数据
    43             conn.send(stdout)
    44             conn.send(stderr)
    45 
    46         except ConnectionResetError:
    47             break
    48     conn.close()
    49 
    50 phone.close()
    

    高阶报头自制

     udp 左券套接字

    tcp基于链接通讯

    • 基于链接,则必要listen(backlog),钦赐连接池的大大小小
    • 基于链接,必得先运营的服务端,然后顾客端发起链接诉求
    • 对此mac系统:借使一端断开了链接,那另外一端的链接也随之完蛋recv将不会卡住,收到的是空(消除措施是:服务端在收音信后增加if判别,空音信就break掉通讯循环)
    • 对于windows/linux系统:倘若一端断开了链接,那另外一端的链接也随着完蛋recv将不会卡住,收到的是空(化解方式是:服务端通讯循环内加十二分管理,捕捉到非常后就break掉通信循环)

    udp无链接

    udp 不需要经过3次握手和4次挥手,不需要提前建立连接,直接发数据就行。
    
    • 无链接,由此没有要求listen(backlog),尤其未有怎么连接池之说了
    • 无链接,udp的sendinto不用管是不是有贰个正值运营的服务端,能够己端四个劲的发音信,只可是数据错过
    • recvfrom收的多寡低于sendinto发送的多寡时,在mac和linux系统上数据直接吐弃,在windows系统上发送的比收受的大一直报错
    • 唯有sendinto发送数据未有recvfrom收多少,数据遗失
    • 二个sendto对应三个recvfrom,不会发出粘包难点

           udp左券固然不会发出粘包,但 udp公约不安全,tcp协议会在发多少前发个新闻,在接收端回复确认能够接收数据后,才会发送数据,发送数据          后还要拭目以俟接收端回复已选择后才会持续发送,由此tcp公约是和煦安全的。

    client.py 
    

    图片 38图片 39

     1 import socket
     2 # 建立套接字对象
     3 client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
     4 #client.connect(('127.0.0.0',8080)) #udp没有链接
     5 
     6 
     7 while True:
     8     msg = input('>>:').strip()
     9     client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) #udp没有链接,发送信息必须指定ip和端口
    10 
    11     data,server_addr = client.recvfrom(1024)
    12     print(data,server_addr)
    13 
    14 client.close()
    

    udp套接字 client

    >>:hah
    b'HAH' ('127.0.0.1', 8080)
    >>:yy
    b'YY' ('127.0.0.1', 8080)
    >>:
    
    service.py
    

    图片 40图片 41

     1 import socket
     2 # 建立套接字对象
     3 server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
     4 server.bind(('127.0.0.1',8080))
     5 
     6 #server.listen() #监听最大链接数,udp没有链接
     7 #server.accept() #建立链接,udp无链接
     8 
     9 while True:
    10     data,client = server.recvfrom(1024)
    11     print(data,client) #返回数据和数据发送端的ip和端口
    12     server.sendto(data.upper(),client) #udp没有链接,发送信息必须指定ip和端口
    13 
    14 server.close()
    

    udp套接字 server

    b'hah' ('127.0.0.1', 59001)
    b'yy' ('127.0.0.1', 59001)
    

      

     

     

     

    本文由澳门新葡8455最新网站发布于澳门新葡8455最新网站,转载请注明出处:网络编程

    关键词: