Python builds TCP communication
TCP/IP protocol
TCP/IP (Transmission Control Protocol/Internet Protocol) refers to a protocol cluster that can realize information transmission between multiple different networks. TCP/IP protocol refers not only to TCP and IP Two agreements, but one by FTP,SMTP,TCP,UDP The protocol cluster composed of, IP and other protocols is called TCP/IP protocol because TCP protocol and IP protocol are the most representative among TCP/IP protocols.
TCP protocol processing of Python
To be honest, python does not have much advantage in this kind of low-level network protocol processing. Its processing speed is relatively slow compared with C/C + + or any other language, but the victory lies in the simple wwwww
Using Python to realize tcp communication is generally realized through Python's socket module.
socket is Python's own source library. You don't need to download it through pip. Just import it into the code.
socket module provided by Python, which provides standard BSD Sockets API
socket type
Let's take a look at the socket constructor first
socket.socket([family[, type[, proto]]])
class socket(_socket.socket): """A subclass of _socket.socket adding the makefile() method.""" __slots__ = ["__weakref__", "_io_refs", "_closed"] def __init__(self, family=-1, type=-1, proto=-1, fileno=None): pass # Omitted below
family:
The meaning is address family, which determines the communication type of socket. The type and description are as follows
socket address family type | Address family description |
---|---|
socket.AF_UNIX | It can only be used for inter process communication of a single Unix system |
socket.AF_INET | Network communication between servers |
socket.AF_INET6 | IPv6 |
type:
The meaning is socket type. Different connections are built according to different values. The types and descriptions are as follows
socket type | Type description |
---|---|
socket.SOCK_STREAM | Streaming socket, which is used to handle TCP connections |
socket.SOCK_DGAM | Datagram socket, which is used to handle UDP connections |
socket.SOCK_RAW | The original type of socket, ordinary socket can not handle ICMP, IGMP and other network messages, while SOCK_RAW is OK; Meanwhile, SCOK_RAW can also handle special IPv4 messages; Using the original socket, you can use IP_ The hdrincl socket option constructs the IP header by the user. |
socket.SOCK_SEQPACKET | Reliable continuous packet service |
protocol:
Generally, it is not filled in, and the default value is 0.
socket function
1) Unlike HTTP or UDP protocols, TCP has established a TCP connection when sending data, so there is no need to specify an address.
2) The server and client cannot directly send data types other than * * * string * * *.
3) The available functions are as follows
Server function
socket function | Function description |
---|---|
bind(address) | Bind the socket to the address in AF_ In INET address family mode, the address is represented in the form of tuple (host,port) |
listen(backlog) | Start listening for TCP incoming connections. bcaklog specifies the maximum number of connections that the operating system can suspend before rejecting the connection. This value is at least 1, which is valid in Win/MAC system. The default maximum value under Linux system. |
accept() | Accept TCP connection and return to conn (address). Conn is a new socket object that can be used to receive and send data. Address is the address of the connecting client. |
Client function
socket function | Function description |
---|---|
connect(address) | Connect to the socket at address. Generally, the format of address is tuple (hostname,port). If there is a connection error, socket is returned Error error. |
connect_ex(address) | The function is the same as that of connect(address), but 0 is returned for success and errno is returned for failure. |
General function
socket function | Function description |
---|---|
recv(bufsize[,flag]) | Accept data from TCP sockets. Data is returned in byte form, and bufsize specifies the maximum amount of data to be received. flag provides additional information about the message, which can usually be ignored. |
send(byte[,flag]) | Send TCP data. Send the data in byte to the connected socket. The return value is the number of bytes to send, which may be less than the byte size of string. |
sendall(byte[,flag]) | Send TCP data completely. Send the data in byte to the connected socket, but try to send all the data before returning. None is returned successfully, and an exception is thrown if it fails. |
recvfrom(bufsize[.flag]) | Accept data from UDP socket. Similar to recv(), but the return value is (data,address). Where data is the string containing the received data, and address is the socket address of the sending data. |
sendto(string[,flag],address) | Send UDP data. Send the data to the socket. Address is a tuple in the form of (ipaddr, port) and specifies the remote address. The return value is the number of bytes sent. |
close() | Close socket |
getpeername() | Returns the remote address of the connection socket. The return value is usually a tuple (ipaddr,port). |
getsockname() | Returns the socket's own address. Usually a tuple (ipaddr,port) |
setsockopt(level,optname,value) | Sets the value of the given socket option. |
getsockopt(level,optname[.buflen]) | Returns the value of the socket option. |
settimeout(timeout) | Set the timeout of socket operation. Timeout is a floating-point number in seconds. A value of None indicates that there is no timeout. In general, timeout periods should be set when a socket is first created, as they may be used for connection operations (such as connect()) |
gettimeout() | Returns the value of the current timeout period in seconds. If the timeout period is not set, it returns None. |
fileno() | Returns the file descriptor of the socket. |
setblocking(flag) | If the flag is 0, set the socket to non blocking mode, otherwise set the socket to blocking mode (default). In non blocking mode, if the call recv() does not find any data, or the call send() cannot send data immediately, it will cause socket Error exception. |
makefile() | Create a file associated with the socket |
socket programming
thinking
There should be a socket on the server to listen to a port, accept the connection established from the client, receive the message sent from the client and send the message to the client.
There should be a socket on the server side, which uses a port to request the server side to build a TCP connection, send messages, and receive messages sent from the server side.
Pseudo code
Server:
1. Create a socket and bind it to the local IP and port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 8892))
2. Start listening port
s.listen(5)
3. Enter the loop and continuously accept the connection request of the client
s.accept()
4. Receive the data and send the return information to the client
s.recv(1024) s.send()
5. Close the socket after the transmission or demand is completed
s.close()
client:
1. Create a socket and connect to the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect()
2. Send and receive data
data = 'data' s.send(data) s.recv()
3. Close the socket after the transmission or demand is completed
s.close()
Sketch Map
code
Server:
# server.py import socket class Server: def __init__(self, family, t, port): self.sock = socket.socket(family, t) self.sock.bind(('0.0.0.0', port)) self.sock.listen(10) def accept(self): self.sock.accept() if __name__ == '__main__': server = Server(socket.AF_INET, socket.SOCK_STREAM, 7792) client, client_addr = server.sock.accept() print('come from:' + str(client_addr) + 'Connection of') data = client.recv(1024) print('Received from:' + str(client_addr) + 'Message:') # The received data is byte and needs to be converted into string print(str(data, 'utf-8')) # Sending data needs to be converted into byte client.send(str('Hello,I have received the message!').encode())
client:
# client.py import socket class Client: def __init__(self, family, t, ip, port): self.sock = socket.socket(family, t) self.ip = ip self.port = port def connect(self): self.sock.connect((self.ip, self.port)) def recv(self, size): return self.sock.recv(size) def send(self, byteData): self.sock.send(byteData) def close(self): self.sock.close() if __name__ == '__main__': client = Client(socket.AF_INET, socket.SOCK_STREAM, '127.0.0.1', 7792) client.connect() client.send(str('Hello!').encode()) data = client.recv(1024) client.close() print('Message from server:\n' + str(data, 'utf-8'))
Operation results
Start the server first and then the client
Server result:
Client results:
Using threads to operate socket s
# Realize tcp request forwarding import sys, socket, time, threading, json # Log lock makes log output thread safe loglock = threading.Lock() def log(msg, ip): loglock.acquire() try: print('[%s]: \n[IP:%s]\n%s\n' % (time.ctime(), ip, msg.strip())) sys.stdout.flush() finally: loglock.release() # Transport class, with source as the source and target as the target # Forwarding principle: the server establishes a connection with the client, and the server establishes a connection with the forwarding target # The server gets two sock s and uses PipeThread to exchange messages class PipeThread(threading.Thread): def __init__(self, source, target, addr): threading.Thread.__init__(self) self.source = source self.target = target self.addr = addr def run(self): while True: try: data = self.source.recv(1024) log('datas:', self.addr) print(data) if not data: break self.target.send(data) except Exception as e: print(e) break log('PipeThread done', self.addr) class Forwarding(threading.Thread): def __init__(self, port, targethost, targetport): threading.Thread.__init__(self) self.targethost = targethost self.targetport = targetport self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind(('0.0.0.0', port)) self.sock.listen(10) def run(self): while True: client_fd, client_addr = self.sock.accept() target_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) target_fd.connect((self.targethost, self.targetport)) log('new connect', client_addr) PipeThread(target_fd, client_fd, '(' + self.targethost + ':' + str(self.targetport) + ")").start() PipeThread(client_fd, target_fd, client_addr).start() # two direct pipe if __name__ == '__main__': Forwarding(8928, '10.110.87.243', 8879).start() sys.exit(1)