Day27 python sticky packet udp / tcp sticky solution bag module socktserver, socketserver concurrency

1. sticky package

# Tcp protocol when sending data packets will be sticky phenomenon.
(1) Data package is sticky because the client / server will have a data buffer,
the buffer is used to temporarily hold data, in order to ensure a complete receiver to be able to data, so the buffer will be set relatively large.
(2) send and receive data at frequent, since borderless tcp transmitting a message, do not know how much should the length taken
cause the client / server, are likely to be a plurality of data as data capture, resulting in sticky package

Example: The following three methods is adopted, Time module 1 may be used, the client or the server or sender of the data received one time slightly delayed, this can be done non-stick package.

2. The server in this example when sending data to send data to a client, let the client know how much data will be accepted, so it will not stick package. (method 1)

3. The method of malpractice 1. Once the server is sending too much data, each client does not need to accept the number of data and then again on the line assignment, write directly on the receiving eight bytes on the line, server-side use of "00000120" to allow customers to end know that each time you take 8 bytes on the line,

res0 = int (sk.recv (8) .decode ( "utf-8")) is not required to change each time the number 8, 8 bytes each receiving line, in such a way server transmitting to the line can.

The above figure is the number of bytes you need to accept. So it will not cause sticky package.

4. Method three is packed into the data line 4 bytes transmitted on the line according to the line use socketserver be transmitted using any number stuct.pack () on the line, and then let the client know you accept four bytes, then at the client, use struct.unpack () is 4 bytes of the packet on the line decompression to obtain the original data, so that the package will not cause sticky.

5. When the above circumstances are sent twice to the data in the server from the client to establish, generally twice the data without anything, because the tcp is borderless, do not know how many bytes to accept the customer end for the first time to accept recv (10) a second time to accept the client recv (10), the server side for the first time helllo send a second transmission is world, due to the borderless cause for the first time accepted that b " helloworl "the second is to accept b" d "have launched come.

Solution one :( will not cause stick pack)

Client code:

# ### 客户端
import socket
import time
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )

# time.sleep(0.2)
res0 = int(sk.recv(1).decode("utf-8")) #res0 "6"
print(res0)
res1 = sk.recv(res0)
print(res1)
# print(res1.decode("utf-8"))
res2 = sk.recv(10)
print(res2)
sk.close()

服务器端:
# ### server 
Import socket
 Import Time 
SK = socket.socket () 

# add this sentence before the bind method, you can make a port reuse 
sk.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
 # tie set the address port (registered on the network host) 
sk.bind (( " 127.0.0.1 " , 9000 )) 
sk.listen () 

Conn, addr = sk.accept () 
conn.send ( " . 6 " .encode ( " UTF -8 " )) 
Message = " Hello, " 
conn.send (message.encode ( " UTF-. 8" ))
 # The time.sleep (0.1) 
conn.send ( " world " .encode ( " UTF-8 " )) 


# fourth wave 
conn.Close ()
 # refunded port 
sk.close () 
Summary: In tcp line contract You can allow data to a client know how much we will send the packet to him, as is starting a 6 and then send "hello" and "world"
after the first receipt hello, received a second data will not cause sticky packet data.
 
 

 

 Method two: 
using recv (8) to accept the 8 bytes, so that the server can send data.
Client:
# ### 客户端
import socket
import time
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )

# time.sleep(0.2)
res0 = int(sk.recv(8).decode("utf-8")) #res0 "6"
print(res0)
res1 = sk.recv(res0)
print(res1)
# print(res1.decode("utf-8"))
res2 = sk.recv(10)
print(res2)
sk.close()

 Service-Terminal
# ### server 
Import socket
 Import Time 
SK = socket.socket () 

# add this sentence before the bind method, you can make a port reuse 
sk.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
 # tie set the address port (registered on the network host) 
sk.bind (( " 127.0.0.1 " , 9000 )) 
sk.listen () 

Conn, addr = sk.accept () 
conn.send ( " 00.00012 million " .encode ( " UTF -8 " )) 
Message = " Hello, " * 20 is 
conn.send (message.encode ( "8-UTF " ))
 # the time.sleep (0.1) 
conn.send ( " world " .encode ( " UTF-8 " )) 


# fourth wave 
conn.Close ()
 # refunded port 
sk.close () 
# server end use # time.sleep (0.1) delay the server to the client can also send data, which is sent to a data server and then wait for the client to send data again after receiving a second data like this will do.

Method three:
# Use module socketserver

Client code:

# ### client 
Import Socket
 Import struct
 Import Time 
SK = socket.socket () 
sk.connect (( " 127.0.0.1 " , 9000 )) 
the time.sleep ( 0.1 )
 # to accept a length of 4 bytes, he is actually that number to be transmitted to the conversion. 
n-sk.recv = (. 4 ) 
# n-
= struct.unpack ( " I " , n-) [0] Print (n-) # next receive data sent from the server RES1 = SK .recv (n-) Print (res1.decode ( " UTF-. 8 " )) RES2Sk.recv = (1024 ) Print (res2.decode ( " UTF-. 8 " )) # spaces are not encoded in ascii, attention. Sk.send (B " i_love_you " ) # close the connection sk.close ()

 

Server code:

# ### server 
Import Socket
 Import struct 

SK = socket.socket () 
sk.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, . 1 ) 
sk.bind (( " 127.0.0.1 " , 9000 )) 
sk.listen () 

Conn, addr = sk.accept () 
InP = INPUT ( " >>> MSG: " ) 
MSG = inp.encode ( " UTF-. 8 " )
 # length of the transmission data converted by pack, having a fixed length becomes 4 byte values 
RES = struct.pack ( " I " , len (MSG)) 

conn.send (RES)
# Next, start the real transmission data 
conn.send (MSG) 
conn.send ( " World " .encode ( " UTF-. 8 " )) 

RES = conn.recv (1024 )
 Print (RES)
 Print (res.decode ( " UTF-8 " ))
 # fourth wave 
conn.Close ()
 # refunded port 
sk.close ()
Summary: using, after SocketServer, the first server transmits the data to the client, no matter how long the length of the transmission transmitted by struct.pack ( "i", len ( msg)) after the calculation 
value is in accordance with 4-byte length to be transmitted, then the byte is sent to the client, it knows to accept the first four bytes of the line length, the client using unpack (), the data obtained on the line on the line
to restore the original data, so as not to cause sticky package.

 

 

 

 

2. sticky package appears in both cases

Package # sticky phenomenon:
the transmitting side, since the two short data transmission interval time short, the packets are formed at the transmitting end sticky
# package sticky phenomena:
at the receiving end, since the two data are almost simultaneously transmitted to a counterpart cache, all formed at the receiving end of the packet sticky
# summary:
transmitting end, a time interval between the short packet or a receiver, receiving is not timely, it will stick package
core because borderless tcp data taken, not according to the transmission Analyzing sequence

3. solve the sticky problem of package

# Package to solve the sticky scenarios:
scenarios in real-time communication, need to read the message sent is what the
# package does not need to solve the sticky scene:
download or upload a file, and finally put packages together, sticky bag does not matter.

4. Module socketserver

The bottom of the socket is # network protocols, based on the original socket module, and a layer of the package, is SocketServer
SocketServer to achieve tcp protocol, server side concurrency.

 :( basic usage method to solve the sticky bag three points will be used to knowledge)

import struct
# pack     把任意长度的数字转化成具有固定4个字节长度的字节流
# unpack   将4个字节的值恢复成原本的数据,最后返回一个元组
# i => int 我要转化的当前数据类型是整型
res = struct.pack("i",304535345)
print(res)
print(len(res))

res = struct.unpack("i",res)
print(res)
print(res[0],type(res[0]))
 

 5.sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)加上可以实现端口的互用

6.socketserver并发

客户端1代码:(不带循环的客户端就行访问服务器)

# ### 客户端
import socket
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )
sk.close()

'''
try:
    print(name)
# 无论是否报错,都会执行finally里面代码块;
finally:
    pass
'''
# print(name)
"""
如果有一些语句,即使在发生报错的情况也仍然要调用或处理一些逻辑,那么使用finally
"""
# try:
    # print(name)
# finally:
    # print(123)
    # print(456)
    
'''
try这个代码块如果有错误,不执行else代码块中的内容
如果没有报错,那么执行else代码块中的内容.
try ... except ... else 要配合使用 else不能单独拿出来和try使用.
try ... finally ... 可以配合在一起使用.
'''
'''
try:
    # print(name)
    print(123)
except:
    pass
else:
    print(789)
'''

 

 

服务器1代码:

 
 
import socketserver
# 需要自定义一个类,并且继承socketserver.BaseRequestHandler
class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        #<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 54088)>
        print(self.request) 
        print("--->执行这句话")

# Threading( (ip,端口号)   ,  自定义类 )
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , MyServer)
# 循环调用
server.serve_forever()
服务器代码:
只要有客户端连接服务器就会打印出下面的代码。self.request相当于,接收到有人连接服务器,myserver这个类下面的函数handle就会自动去处理。看看是谁连接到了我,从而支持并发。
 

# 由于客户端没有给服务器发送消息,服务器这边采用可socketserver支持多人连接。

# 带循环的客户端2

import socket
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )

while True:    
    sk.send(b"wangwen_dashuaguo")
    msg = sk.recv(1024)
    print(msg)


sk.close()

 

 

 

# 服务器代码2:

import socketserver
class MyServer(socketserver.BaseRequestHandler):
    # 在handle里面自定义收发逻辑
    def handle(self):
        print("--->这句话被执行了")
        
        conn = self.request
        while True:    
            msg = conn.recv(1024).decode("utf-8")
            print(msg)
            conn.send(msg.upper().encode("utf-8"))
# 产生一个对象    
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) ,MyServer )
# 循环调用
server.serve_forever()

 

运行代码:

 小结:

1.上面开的三个客户端都是发送wangwen_dashuaguo

2.服务器这边的逻辑就是只要有客户端来连接我我就使用

# 产生一个对象    
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) ,MyServer )
来产生一个对象就行处理,在这个类当中可以发现只要是客户端给我发消息我就可以接受到,然后再将他发送的内容发送给他。从而形成了并发,可以是多个客户端连接服务器。conn = self.request也很关键。

Guess you like

Origin www.cnblogs.com/longerandergou/p/10958782.html