内置方法比较 tcpudp进阶 粘包

补充

魔术方法__eq____lt____gt__

两个对象做==比较的时候会自动调用__eq__这个方法,<比较时调用的是__lt__,>比较时调用的是__gt__

 
 1 class Person(object):
 2      def __init__(self, name,age):
 3          self.name = name
 4          self.age = age
 5      def __eq__(self, other):
 6          return self.name == other.name and self.age == other.age
 7      def __gt__(self, other):
 8          print('执行gt啦')
 9      def __lt__(self, other):
10          print('执行lt啦')
11  alex = Person('alex',83)
12  alex222 = Person('alex',84)
13  print('-'*20)
14  print(alex == alex222)

 

alex22会被当做other参数传入方法,alex == alex222的结果就是return的返回值

今日内容

tcp协议的进阶

服务端:

  • sk:存储的是本身向操作系统申请的资源(ip地址与端口)

  • conn:存储的是一个客户端和服务端的连接信息

服务端方面,可以和多个客户端进行握手,可以和客户端一直通信,可退出

 1  import socket
 2  sk = socket.socket()
 3  sk.bind(('127.0.0.1',9001))
 4  sk.listen()
 5  6  while True:  # 为了和多个客户端进行握手
 7      conn,addr = sk.accept() # 能够和多个客户端进行握手了
 8      print('conn : ',conn)
 9      while True:
10          send_msg = input('>>>')
11          conn.send(send_msg.encode('utf-8'))
12          if send_msg.upper() == 'Q':break
13          msg = conn.recv(1024).decode('utf-8')
14          if msg.upper() == 'Q': break
15          print(msg)
16      conn.close()    # 挥手 断开连接
17 18  sk.close()      # 归还申请的操作系统的资源

 

客户端方面,可以和服务端一直通信,可退出

 1  import socket
 2  sk = socket.socket()
 3  sk.connect(('127.0.0.1',9001))
 4  5  while True:
 6      msg = sk.recv(1024)
 7      msg2 = msg.decode('utf-8')
 8      if msg2.upper() == 'Q':break
 9      print(msg,msg2)
10      send_msg = input('>>>')
11      sk.send(send_msg.encode('utf-8'))
12      if send_msg.upper() == 'Q':break
13  sk.close()

 

udp协议的编程

语法

新的方法:socket.socket(type = socket.SOCK_DGRAM),recvfrom,sendto

服务端

1  import socket
2 3  sk = socket.socket(type = socket.SOCK_DGRAM)
4  sk.bind(('127.0.0.1',9001))
5  while True:
6      msg,addr= sk.recvfrom(1024)
7      print(msg.decode('utf-8'))
8      msg = input('>>>')
9      sk.sendto(msg.encode('utf-8'),addr)

 

客户端

 1  import socket
 2  3  sk = socket.socket(type=socket.SOCK_DGRAM)
 4  server = ('127.0.0.1',9001)
 5  while True:
 6      msg = input('>>>')
 7      if msg.upper() == 'Q':break
 8      sk.sendto(msg.encode('utf-8'),server)
 9      msg = sk.recv(1024).decode('utf-8')
10      if msg.upper() == 'Q':break
11      print(msg)

 

和tcp协议的区别

不可靠,不面向连接,效率高

粘包现象

tcp协议的特点

多条消息之间没有边界,有许多优化机制,例如会在操作系统(内核态)中增加一个缓存机制,会把传输的数据;网络最大带宽限制MTU=1500字节,所以会自动把传输的数据拆分发送,再拼接接收(udp也可以传送超过1500字节,但是还是有限制,不得超过一个界限)

粘包是什么?

发送过来的消息会粘连在一起,几条消息被合并成一条消息

怎么发生

发送端 : 两条消息都很短,发送的间隔时间也非常短

接收端 : 多条消息由于没有及时接收,而在接收方的 缓存端堆在一起导致的粘包

怎么处理—本质是设置边界
自定义协议

自定义前四个字节的数据是长度

服务端

 1  import socket
 2  3  sk = socket.socket()
 4  sk.bind(('127.0.0.1',9001))
 5  sk.listen()
 6  7  conn,addr = sk.accept()
 8  msg1 = input('>>>').encode()
 9  msg2 = input('>>>').encode()
10  num = str(len(msg1))  # '10001'
11  ret = num.zfill(4)    # '0006'
12  conn.send(ret.encode('utf-8'))
13  conn.send(msg1)
14  conn.send(msg2)
15  conn.close()
16  sk.close()

 

客户端

 
 1 import socket
 2  3  sk = socket.socket()
 4  sk.connect(('127.0.0.1',9001))
 5  length = int(sk.recv(4).decode('utf-8'))
 6  msg1 = sk.recv(length)
 7  msg2 = sk.recv(1024)
 8  print(msg1.decode('utf-8'))
 9  print(msg2.decode('utf-8'))
10 11  sk.close()

 

struct模块

通过struct模块把长度转换成固定的四个字节;在使用struct.unpack把四个字节转换成数字

服务端

 1  import struct
 2  import socket
 3  4  sk = socket.socket()
 5  sk.bind(('127.0.0.1',9001))
 6  sk.listen()
 7  8  conn,addr = sk.accept()
 9  msg1 = input('>>>').encode()
10  msg2 = input('>>>').encode()
11  blen = struct.pack('i',len(msg1))
12  conn.send(blen)
13  conn.send(msg1)
14  conn.send(msg2)
15  conn.close()
16  sk.close()

 

客户端

 1 import time
 2 import struct
 3 import socket
 4 
 5 sk = socket.socket()
 6 sk.connect(('127.0.0.1',9001))
 7 length = sk.recv(4)
 8 length = struct.unpack('i',length)[0]
 9 msg1 = sk.recv(length)
10 msg2 = sk.recv(1024)
11 print(msg1.decode('utf-8'))
12 print(msg2.decode('utf-8'))
13 
14 sk.close()

 

posted @ 2019-01-27 19:09  .如影随行  阅读(145)  评论(0编辑  收藏  举报