At work , We always meet the need :
We need to send the message in the specified format to the server program , And then the server does some processing , And then send us the processed message .
Or say , We always need it :
When writing a server-side program , Always want to have one that can simulate receiving packets 、 A client program that monitors messages and can reply to them , In this way, it is convenient for us to debug and write the program logic that our server runs .
The former is the perspective of writing client programs , The latter is the perspective of writing server-side programs .
Anyway? , We always want a message Simulator , Be able to receive 、 monitor 、 Send message , It can facilitate the development and testing work related to the message interaction between the client and the server .
I've always had this idea , Recently, I encountered a project with relatively complex message format , If you don't write a message simulator yourself , The logic debugging of server program will be very troublesome .
therefore , I put forward my own requirements for this message simulator :
therefore , After a few days of fighting , I finally realized the above requirements in a very simple way :
that , Now? , Let's implement the simulator together :)
ps: Students who are interested in the code of this project , You can come to me GitHub
wangying2016/Packet_Simulator
Since we want to make a message Simulator , I also put forward to myself what is mentioned in the introduction 5 A need , So we need to think about how to achieve it .
technical , Here I have chosen Python3 & Tkinter, As for why ...
Because I like Python3 & Tkiner ah :)
But then again , For us programmers , Some of the assistive tools at work , Of course, the easier it is to write, the better , The less code you write, the better , The more powerful the library, the better , Its language is native to support UI The library can basically meet our needs .
So , I chose Python3, And because of Tkinter yes Python3 Native support, cross platform UI library , It's powerful and easy to learn , So the tools for implementation are decided .
Some people may find it strange , We write a little tool , Why the choice of business is also involved ?
Of course , Although we just want to write a message simulator , But we need to build a simple scenario to make it run . In this scenario , Including our server program , Including the message format we need to define for the interaction between the server and the client , These need to be defined .
in addition , The simpler we define our business, the more representative it is , So when we transplant this message simulator to specific projects for use in the future , Or expand , For example, the message format of the interaction between the server and the client , It involves the encryption and decryption of messages 、 Message reading and writing logic , These need to be personalized and expanded according to the specific project .
here , Let's simply define the following business rules :
We have made a good choice in technology and business , The rest is to write the code , Which part to start with ?
Certainly UI.
In my code file Sim_Sender.py in , class GUI Is the key class used to implement interface design .
Among them __init__
Method is used to initialize the interface layout , The layout includes an input box 、 A text box 、 Three buttons and a scrolling text box .
in addition , The trigger function bound to the control is also defined in GUI Class , It also includes reading and writing local message files , And the trigger function of the button 、 The contents of the scrolling text box are written and so on .
here , I'll pick a few places with heavy medicine to explain it .
Tkinter Windows in are created by Tk() Functionally progressive , It returns a value similar to the window handle , The position and size of the window can be set .
Inherited from Frame( Framework class ) Of GUI Class is the control class of window layout , It initializes the kind of controls displayed on our interface .
if __name__ == '__main__':
...
# Gui
root = Tk()
app = GUI()
...
root.geometry("350x600+300+300")
root.mainloop()
In the code , After defining the window position and size ,root.mainloop()
It's us Windows The most familiar window message loop in programming :)
The layout of the window uses pack layout (Tkinter Support pack/grid/place Three layouts ). The core code of layout is of course GUI Class init_ui() Function :
def init_ui(self):
self.master.title(" Message Simulator ")
self.pack(fill=BOTH, expand=True)
self.frame1 = Frame(self)
self.frame1.pack(fill=X, expand=True)
lbl1 = Label(self.frame1, text=" Identification code ", width=10)
lbl1.pack(side=LEFT, padx=5, pady=5)
self.entry = Entry(self.frame1)
self.entry.pack(fill=X, padx=5, expand=True)
self.frame2 = Frame(self)
self.frame2.pack(fill=X, expand=True)
lbl2 = Label(self.frame2, text=" Message content ", width=10)
lbl2.pack(side=LEFT, anchor=N, padx=5, pady=5)
self.txt = Text(self.frame2, height=10)
self.txt.pack(fill=X, pady=5, padx=5, expand=True)
self.frame3 = Frame(self)
self.frame3.pack(fill=X, expand=True)
button1 = Button(self.frame3, text=" Open local ", command=self.open_local)
button1.pack(side=LEFT, padx=5, pady=5, fill=X, expand=True)
button2 = Button(self.frame3, text=" Save local ", command=self.save_local)
button2.pack(side=LEFT, padx=5, pady=5, fill=X, expand=True)
button3 = Button(self.frame3, text=" Send message ", command=self.send_msg)
button3.pack(side=LEFT, padx=5, pady=5, fill=X, expand=True)
self.frame4 = Frame(self)
self.frame4.pack(fill=X, expand=True)
lbl3 = Label(self.frame4, text=' Log monitoring ')
lbl3.pack(side=LEFT, padx=5, pady=5)
self.frame5 = Frame(self)
self.frame5.pack(fill=BOTH, expand=True)
self.log = scrolledtext.ScrolledText(self.frame5, height=55, width=150)
self.log.pack(side=LEFT, pady=5, padx=5, expand=True)
self.log.focus_set()
self.add_log('packet simulator', 'start listen')
Tkinter It's not hard to learn , Just be able to find the information in the source code on your own , Be able to search for relevant courses online , I won't go into that here .
In the interface , The most difficult control is the scrolling text box at the bottom of the log monitor .
This one is used Tkinter Of scrolledtext Control , The most important function of adding log information is as follows :
def add_log(self, title, msg):
tm = time.localtime(time.time())
fmt_msg = '%s-%s-%s %s:%s:%s %s\n%s\n\n' % (tm.tm_year,
'{:0>2}'.format(tm.tm_mon),
tm.tm_mday,
'{:0>2}'.format(tm.tm_hour),
'{:0>2}'.format(tm.tm_min),
'{:0>2}'.format(tm.tm_sec),
title,
msg)
self.log.insert(INSERT, fmt_msg)
self.log.focus_set()
self.log.yview_moveto(1)
among , It's all about matching the time format , hinder self.log.yview_moveto(1)
Function to keep the current display always on the last line ( Realize the function of rolling tracking ).
If there are other doubts , I recommend one online Tkinter course , It's very good for beginners to learn :
Python Programming with Tkinter
Now? , We implemented the layout of the interface , It can also simulate scrolling log information to show , So what are we going to do next ?
Socket Programming :)
in the final analysis , This is still a project of interaction between the server and the client . So in addition to the message Simulator , We also need to write a server-side program .
Yes, of course , To simplify the structure of the project as much as possible , We used the initiator's short connection . That is to say , When the originator sends a message , Create your own socket Connect , Close immediately after sending . For message listeners , You need to be monitoring all the time .
The service list program is relatively simple , Just hang the listening message all the time , Just after receiving the message , Need to start another socket Connect to reply to a message .
The following is the code of listening message :
class Server:
"""
Listen for client.
"""
def __init__(self):
# Create socket
tcp_server_socekt = socket(AF_INET, SOCK_STREAM)
# Bind ip & port
server_address = (server_ip, server_port)
tcp_server_socekt.bind(server_address)
# Begin listen
tcp_server_socekt.listen(1)
print('start listen\n')
# Server long connection, client short connection
while True:
# Listen for client's connection
new_socket, client_address = tcp_server_socekt.accept()
# Receive client data
recv_data = str(new_socket.recv(1024), encoding='utf-8')
# if data length is 0, because client close the connect
if len(recv_data) > 0:
print('recv data = [%s]\n' % recv_data)
else:
print('recv data = 0\n')
# Processing message
processor = Processor(recv_data)
send_data = processor.get_msg()
client = Client(send_data)
print('send data = [%s]\n' % send_data)
# Close the client socket
new_socket.close()
# Stop listen
tcp_server_socekt.close()
You can see , After we suspended monitoring , Every time the message is received , It's all called Client()
Class to reply to a message , In this class , We have a new connection from the sender socket Connect :
class Client:
"""
Send message to client.
"""
def __init__(self, data):
# Create socket
self.tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# Bind ip & port
self.server_address = (client_ip, client_port)
# Connect to client
self.tcp_client_socket.connect(self.server_address)
# Send data
self.tcp_client_socket.send(bytes(data.encode("utf-8")))
# Close connect
self.tcp_client_socket.close()
therefore , The logic of the server-side program is very simple , It's listening to the message simulator all the time , After receiving the message, it will be processed , Finally, a new connection is created to return .
In fact, the client program is very similar to the server program , It is also a message hanging on the monitoring server , Then a new one socket Connect to send a message .
however , The client program is different , That is to consider multithreading UI And listening threads .
here , stay GUI Class initialization , I started a new thread to monitor messages :
class GUI(Frame):
"""
GUI with tkinter.
"""
def __init__(self):
super().__init__()
# Instance variable
...
# Init ui
self.init_ui()
# Begin listen
t = threading.Thread(target=network)
t.setDaemon(True)
t.start()
def network():
server = Server()
class Server:
"""
Listen message from server.
"""
def __init__(self):
...
The above code should allow you to see the structure of the project , It's very clear .
For client message sending , In fact, it is very similar to the server side :
def send_msg(self):
# Get parameter
argv1 = self.entry.get().strip()
argv2 = self.txt.get('1.0', END).strip().replace('\n', '')
if len(argv1) != 4:
messagebox.showerror(' error ', ' Please enter 4 Bit identification code ')
return
print('argv1 = [%s], argv2 = [%s]' % (argv1, argv2))
# Make message
maker = Maker()
msg = maker.get_msg(argv1, argv2)
print('send data: \n[%s]\n' % msg)
# Send Data
client = Client(msg)
class Client:
"""
Send message to server.
"""
def __init__(self, data):
# Create socket
self.tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# Bind ip & port
self.server_address = (server_ip, server_port)
# Connect to server
self.tcp_client_socket.connect(self.server_address)
# Send data
self.tcp_client_socket.send(bytes(data.encode("utf-8")))
# Close connect
self.tcp_client_socket.close()
# Add log
data = 'data = [%s]' % data
app.add_log('send data', data)
This is where the packets are grouped , And then call Client
Class creates a new socket Connect to send a message .
thus , The core network programming related content of this project is finished .
that , What's left ?
Message reading and writing :)
We defined the message format in the requirement analysis , So the corresponding , We need a class that generates messages according to the message format , And a class that interprets messages according to their format .
The class that generates the message :
class Maker:
"""
Packet generate class.
"""
def __init__(self):
self.index = ''
self.content = ''
self.msg = ''
def get_msg(self, index, content):
self.index = index
self.content = content
length = 6 + 4 + 2 + len(content)
self.msg = '{:0>6}'.format(length) + '|' + index + '|' + content
return self.msg
def get_index(self):
return self.index
def get_content(self):
return self.content
Interpreting the class of the message :
class Reader:
"""
Packet analysis class.
"""
def __init__(self, msg):
self.msg = msg
self.index = msg[7:11]
self.content = msg[12:]
def get_index(self):
return self.index
def get_content(self):
return self.content
This is because my message format is defined by myself , I won't go back to , It's worth mentioning , Depending on the complexity of the project , Just extend these two classes , You can support different projects :)
thus , This project is finished ^_^
End of the flower :)
As a consumer, it's my own project , As long as I'm comfortable with it . But of course, this packet simulator has some shortcomings :
wait , These can be in the subsequent project development process , Add and implement according to your own ideas .
But then again , I really like it Python Of Tkinter Interface library , Although it's not so good-looking , But as long as you can run Python3 The place of , Can run Tkinter I have to say it's really convenient , Think IDLE That's what it says , Except that the interface isn't cool enough , Other basic also satisfied the demand , Especially suitable for this kind of handy gadget project !
Python3 & Tkinter There is still a long way to go
To be Stronger:)