First, primary socket
socket is the network connection endpoint, and each socket is bound to a specific IP address and port. The IP address is a sequence of 4 numbers, which are the values in the range 0~255 (for example, 220,176,36,76), and the value range of the port value is 0~65535. The number of ports less than 1024 is reserved for well-known network services (such as the 80 port used by Web services), the maximum number of holds saved stored in the socket module Ipport_ The reserved variable. You can also use a different port value for your program.
Not all IP addresses are visible to other parts of the world. In fact, some are reserved specifically for non-public addresses (such as 192.168.y.z or 10.x.y.z). Address 127.0.0.1 is a native address; it starts with finally points to the current computer. The program can use this address to connect to other programs running on the same computer.
 IP address is not good to remember, you can spend some money to register a host name or domain name for a specific IP address (such as using www.jb51.net instead of 222.76.216.16). Domain Name server (DNS) handles mapping of names to IP addresses.
How much information is transmitted over a network is based on many factors, one of which is the protocol used. Many protocols are based on simple, low-level protocols to form a stack of protocols. For example, HTTP protocol, which is used in Web browser communication with the Web server protocol, it is based on the TCP protocol, and the TCP protocol is based on the IP protocol.
When you transfer information between your own two programs, you typically choose a TCP or UDP protocol. The TCP protocol establishes a continuous connection between the two ends, and the information you send is guaranteed to reach their destination in order. UDP does not establish a connection, it is fast but unreliable. The information you send may not reach the other end, or they do not arrive sequentially. Sometimes multiple copies of a message arrive at the receiving end, even if you only send it once.
Second, use address and hostname
The socket module provides several functions for working with host names and addresses.
The socket also defines a number of variables to represent reserved IP addresses. Inaddr_any and inaddr_broadcast are reserved IP addresses that represent any IP address and broadcast address respectively; Inaddr_loopback represents the LOOPBACK device, always the address 127.0.0.1. These variables are in the form of 32-byte digits.
The Getfqdn ([name]) function returns the full domain name of the given host name (or, if omitted, the full domain name of the machine).
Third, the use of low-level socket communication
Although Python provides some encapsulation, it makes it easier to use a socket, but you can also work directly with the socket.
1. Create and Destroy sockets
The socket (Family,type[,proto]) function in the socket module creates a new socket object. The value of family is usually af_inet. The value of type is usually Sock_stream (for a directed connection, a reliable TCP connection) or SOCK_DGRAM (for UDP):
>>> from Socket Import *
>>> S=socket (Af_inet,sock_stream)
The family and type parameters imply a protocol, but you can use the third optional parameter of the socket (proto, such as ipproto_tcp or Ipproto_raw) to specify the protocol used. Instead of using the IPPROTO_XX variable, you can use the function Getprotobyname:
>>> getprotobyname (' TCP ')
6
>>> ipproto_tcp
6
FROMFD (Fd,type[,proto]) is a rarely used function that is used to create a socket object from an open file descriptor (the file descriptor is returned by the file's Fileno () method). The file descriptor is connected to a real socket, not a file. The Fileno () method of the Socket object returns the file descriptor for the socket.
When you use the finished socket object, you should call the close () method to explicitly close the socket to release the resource as soon as possible (although the socket is automatically closed when it is reclaimed by the garbage collector). Alternatively, you can use the shutdown (how) method to close the connection side or both sides. Parameter 0 prevents the socket from receiving data, 1 blocks sending, and 2 blocks receiving and sending.
2. Connect socket
When two sockets are connected (for example, using TCP), one end listens and receives incoming connections, while the other end initiates the connection. The pro-listening side creates a socket, calls the bind (address) function to bind a specific address and port, calls the listen to hear the incoming connection, and finally calls accept () to receive the new, incoming connection, following the server-side code:
>>> S=socket (Af_inet,sock_stream)
>>> s.bind (' 127.0.0.1 ', 44444)
>>> S.listen (1)
>>> q,v=s.accept () #返回socket Q and Address V
Note: The above code will always wait until the connection is established. Let's open another Python interpreter as a client, and then type the following code:
>>> from Socket Import *
>>> S=socket (Af_inet,sock_stream)
>>> s.connect (' 127.0.0.1 ', 44444) #发起连接
OK, let's verify if the connection is established. We type the following code on the server side to send a message:
>>> q.send (' Hello,i come from pythontik.com ') Note: sometimes send () argument 1 must be string or Buffer,not str error may occur because Your machine does not support the UTF-8 character set, and the temporary solution is q.send (b ' Hello ... ')
#发送的字节数
Type the following code on the client to receive the information:
>>> S.RECV (1024)
' Hello,i come from pythontik.com '
The address you pass to bind and connect is a tuple (ipaddress,port) of sockets for Af_inet. Instead of connect, you can also call the CONNECT_EX (address) method. If the call back to the C's connect returns an error, then CONNECT_EX will return an error (otherwise 0 means success) instead of throwing an exception.
When you call listen, you give it a parameter that represents the total number of incoming connections that are allowed to be placed in the wait queue. When the waiting queue is full, if more connections arrive, the remote side is told that the connection is denied. The somaxconn variable in the socket module indicates the maximum amount that the wait queue can hold.
The Accept () method returns an address that is shaped like bind and connect, representing the address of the remote socket. The value of the variable v is shown below:
>>> V
(' 127.0.0.1 ', 1334)
UDP is a non-directed connection, but you can still use the given destination address and port to call connect to associate a socket.
3. Sending and receiving data
The function send (String[,flags]) sends the given string to the remote socket. SendTo (string[,flags],address) sends the given string to a specific address. Typically, the Send method is used for a reliable connected socket,sendto method for an unreliable socket, but if you call connect on a UDP socket to make it contact a specific target, Then you can also use the Send method instead of SendTo.
Both send and sendto return the actual number of bytes sent. When you send large amounts of data quickly, you may want to make sure that all the information has been sent, so you can use one of the following functions:
def safesend (sock,msg):
Sent=0
While msg:
I=sock.send (msg)
If I==-1: #发生了错误
Return-1
Sent+=i
Msg=msg[i:]
Time.sleep (25)
Return sent
The recv (Bufsize[,flags]) method receives a incoming message. If there is a large amount of data waiting, it returns only the previous number of bufsize bytes of data. Recvfrom (Bufsize[,flags]) does the same thing except that it uses the AF_INET socket's return value (data, (Ipaddress,port)), which makes it easy for you to know where the message came from (which is useful for a non-connected socket).
Both the SEND,SENDTO,RECV and Recvfrom methods have an optional parameter, flags, which is the default value of 0. You can pass to the socket. The msg_* variable is combined (bitwise OR) to establish the value of the flags. These values vary by platform, but the most common values are as follows:
Msg_oob: Handles out-of-band data (both TCP emergency data).
Msg_dontroute: Do not use a routing table, send directly to the interface.
Msg_peek: Returns the data waiting and does not remove them from the queue.
For example, if you have an open socket and it has a message waiting to be received, you can receive this message after you do not remove it from the queue of incoming data:
>>> Q.recv (1024,msg_peek)
' Hello '
>>> q.recv (1024,msg_peek) #因为没有删除, so you can get it again.
' Hello '
The makefile ([Mode[,bufsize]]) method returns a file class object that encapsulates the socket so that you can later pass it to code that requires a parameter as a file (perhaps you prefer to use a file instead of send and recv). The optional mode and bufsize parameters are the same as the built-in open functions.
4. Using the socket option
Both the Getpeername () and GetSockName () methods of the socket object return a two-tuple that contains an IP address and port (the two-tuple form is like you pass to connect and bind). Getpeername returns the address and port of the connected remote socket, GETSOCKNAME returns the same information about the local socket.
By default, the socket is blocked, meaning that the invocation of the socket method will not be returned until the task is completed. For example, if the cache of data sent outward is full and you attempt to send more data, then your call to send will be blocked until it can put more data into the cache. You can change this default behavior by calling the Setblocking (flag) method, where the flag value is 0,setblocking (0) to make the socket non-blocking. When the socket is non-blocking, if the action will cause blocking, it will cause an error exception. The following section of code will attempt to continuously accept new connections and use function ProcessRequest to handle them. If a new connection is not valid, it will be spaced for half a second and try again. Another way is to use Select or poll to detect the arrival of a new connection in your listening socket.
Other socket options can be set and obtained using the setsockopt (Level,name,value) and getsockopt (Level,name[,buflen]) methods. The socket represents a different layer of a protocol stack, and the level parameter specifies which layer the option applies to. The level value starts with Sol_ (SOL_SOCKET,SOL_TCP, and so on). Name indicates which option you are involved in. For value, if the option requires a numeric value, value can only pass in a numeric value. You can also pass in a cache (a string), but you must use the correct format. For getsockopt, not specifying the Buflen parameter means that you require a numeric value and return this value. If you provide buflen,getsockopt returns a string representing a cache, its maximum length is the number of bytes Buflen. The following example sets a socket for sending a cache size of 64KB:
>>> S=socket (Af_inet,sock_stream)
>>> s.setsockopt (sol_socket,so_sndbuf,65535)
To get the life cycle (TTL) and hop count that a package can have before it is routed, you can use the following code:
>>> s.getsockopt (SOL_IP,IP_TTL)
32
5. Numerical conversion
Because the byte order of different platforms is not the same, we use the standard network byte order when transferring data over the network. The Nthol (x) and Ntohs (x) functions require a numeric value of the network byte order and convert it to the same value as the current host byte order, whereas htonl (x) and htons (x) are the opposite:
>>> Import.socket
>>> socket.htons (20000) #转换为一个16位的值
8270
>>> socket.htonl (20000) #转换为一个32位的值
541982720
>>> Socket.ntohl (541982720)
20000
Using Socketservers
The Socketservers module defines a base class for a set of socket service classes that compresses and hides the details of the socket connection that listens, accepts, and processes incoming sockets.
1. Socketservers Family
Both TCPServer and Udpserver are subclasses of Socketserver, which handle TCP and UDP information separately.
Note: Socketserver also provides unixstreamserver (subclasses of TCPServer) and Unixdatagramserver (subclasses of Udpserver), which, like their parent classes, use AF In addition to creating a listening socket _unix replaced the af_inet.
By default, the socket service processes one connection at a time, but you can use the ThreadingMixIn and Forkingmixin classes to create threads and child processes of either socketserver. In fact, the Socketserver module provides some useful classes to solve your problems, they are: Forkingudpserver, Forkingtcpserver, Threadingudpserver, Threadingtcpserver, Threadingunixstreamserver and Threadingunixdatagramserver.
Socketserver handles incoming connections in the usual way; to make it more useful, you should provide your own request handler class to it so that it passes a socket to handle it. The Baserequesthandler class in the Socketserver module is the parent class for all request processors. Suppose, for example you need to write a multithreaded e-mail server, first you want to create a mailrequesthandler, which is a subclass of Baserequesthandler, and then pass it to a newly created socketserver:
Import Socketserver
... #创建你的MailRequestHandler
Addr= (' 220.172.20.6 ',) #监听的地址和端口
Server=socketserver.threadingtcpserver (Addr,mailrequesthandler)
Server.serve_forever ()
Each time a new connection arrives, the server creates a new Mailrequesthandler instance and calls its handle () method to handle the new request. Because the server inherits from Threadingtcpserver, it initiates a separate thread for each new request to handle the request so that multiple requests can be processed concurrently. If you use Handle_request () instead of server_forever, it will handle the connection request one at a. Server_forever just repeated calls to Handle_request.
In general, you only need to use one of the socket services, but if you need to create your own subclass, you can override the method we mentioned below to customize it.
When the service is created for the first time, the __init__ function calls the Server_bind () method to bind the listener socket (self.socket) to the correct address (self.server_address). Then call Server_activate () to activate the service (by default, call the socket's Listen method).
The socket service doesn't do anything until the Handle_request or Serve_forever method is called. Handle_request calls Get_request () to wait and receive a new socket connection, and then calls Verify_request (request,client_address) to see if the service will handle the connection ( You can use this in Access control, which by default verify_request always returns TRUE. If this request is processed, handle_request then calls Process_request (request,client_address) if Process_request (request,client_address) Causes an exception to be called Handle_error (request,client_address). By default, Process_request simply calls Finish_request (request,client_address), and the child and thread classes override this behavior to start a new process or thread, and then call Finish_request. Finish_request instantiates a new request processor, requesting the processor to call their handle () method in turn.
When Socketserver creates a new request processor, it passes the self variable of the processor's __init__ function so that the processor can access information about the service.
The Socketserver Fileno () method returns the file descriptor for the listener socket. The address_family member variable specifies the socket family (such as af_inet) that listens to the socket, and Server_address contains the address to which the listener socket is bound. The socket variable contains the listening socket itself.
2. Request processor
The request processor has the setup (), handle (), and finish () methods, which you can override to customize your own behavior. In general, you only need to overwrite the handle method. Baserequesthandler's __init__ function calls the Setup () method to do the initialization work, handle () serves the request, and finish () is used to perform cleanup work if handle or setup causes an exception, Finish is not called. Remember that your request processor creates a new instance for each request.
The request member variable has the most recently accepted socket for the stream (TCP) service, and for the datagram service, it is a tuple that contains incoming messages and a listening socket. Client_address contains the sender's address, and the server has a reference to Socketserver (through which you can access its members, such as Server_address).
The following example implements a Echorequesthandler, which, as a service side, sends the data sent by the client back to the client:
>>> Import Socketserver
>>> class Echorequesthandler (Socketserver.baserequesthandler):
... def handle (self):
... print ' Got new connection! '
... while 1:
... mesg=self.request.recv (1024)
... if not msg:
... break
... print ' Received: ', msg
... self.request.send (msg)
... print ' Done with connection '
>>> server=socketserver.threadingtcpserver ((' 127.0.0.1 ', 12321), Echoreuesthandler)
>>> server.handle_request () #执行后将等待连接
Got New connection!
Received:hello!
Received:i like tuesdays!
Done with connection
Open another Python interpreter as the client, and then execute the following code:
>>> from Socket Import *
>>> S=socket (Af_inet,sock_stream)
>>> s.connect (' 120.0.0.1 ', 12321)
>>> s.send (' hello! ')
6
>>> Print S.RECV (1024)
Hello!
>>> s.send (' I like tuesdays! ')
16
>>> Print S.RECV (1024)
I like tuesdays!
>>> S.close ()
The Socketserver module also defines the two subcategories of Baserequesthandler: Streamrequesthandler and Datagramrequesthandler. They cover the setup and Finish methods and create two file objects Rfile and Wfile, which you can use to read and write data to the client instead of using the socket method.
Blocking or synchronous programming of sockets
Third, use socket
The most basic part of network programming is the socket (socket). There are two types of sockets: The server socket and the client socket. After you create a server socket, you tell it to wait for the connection. It then listens for a network address (the shape: xxx.xxx.xxx.xxx:xxx) until the client connects. Then the two ends will be able to communicate.
Processing a client socket is usually easier than processing a server socket because the server must always be ready to process the connection from the client, and it must handle multiple connections, and the client needs to simply connect, then do something, and then disconnect.
When instantiating a socket, you can specify three parameters: Address series (default is socket.af_inet), stream socket (this is a default value: Socket. SOCK_STREAM) or datagram socket (Socket.sock_dgram), protocol (the default value is 0). For a simple socket, you can use the default values without specifying any parameters.
The service-side socket calls the Listen method after using the Bind method to listen for a given address. The client socket can then connect to the server by using the Connect method (the address parameter used by the Connect method is the same as bind). The Listen method requires a parameter, which is the number of connections that can be included waiting for the connection queue.
Once the service-side socket calls the Listen method, it enters the pro-listening state, and then usually uses an infinite loop: 1, begins to accept the room-side connection, which is achieved by calling the Accept method. When this method is called, it is blocked (waiting for the client to initiate the connection) until a client connects, and after the connection, the accept returns a tuple (client,address), where the client is a socket for communicating with clients. Address is the client's shape, such as xxx.xxx.xxx.xxx:xxx, 2, then the server processing the client's request, 3, the processing is completed and then call 1.
For transmitting data, the socket has two methods: Send and Recv. Send data using string parameters; The recv parameter is the number of bytes, which represents the amount of data that is accepted, preferably using 1024 if you are unsure of the amount of data to be accepted at one time.
Here is an example of a minimal server/client:
Service side:
Import socket
s = Socket.socket ()
Host = Socket.gethostname ()
Port = 1234
S.bind ((host, Port))
S.listen (5)
While True:
C, addr = S.accept ()
print ' Got connection from ', addr
C.send (' Thank for connecting ')
C.close ()
Client:
Import socket
s = Socket.socket ()
Host = Socket.gethostname ()
Port = 1234
S.connect ((host, Port))
Print S.RECV (1024)
Note: If you use CTRL-C to stop the server, you may need to wait a while if you use the same port again.
Iv. Use of Socketserver
The Socketserver module simplifies the work of writing Web servers.
It provides four basic service classes: TCPServer (using TCP protocol), Udpserver (using datagrams), Unixstreamserver,
Unixdatagramserver. Unixstreamserver and unixdatagramserver are used for UNIX-like platforms.
These four class processing requests use synchronous methods, which means that the current request processing must be completed before the next request processing begins
。
Creating a server with Socketserver requires four steps:
1. Create a request handler class using the subclass Baserequesthandler class and the handle () method that overrides it to handle incoming
's request;
2, instantiate the service class such as TCPServer, and pass to it parameter: Server address and Request processor class;
3. Call the Handle_request () or Serve_forever () method of the service instance object to process the request.
The following uses Socketserver to write the simplest server in a synchronous way:
From Socketserver import TCPServer, Streamrequesthandler
#第一步. Where the Streamrequesthandler class is a subclass of the Baserequesthandler class, it defines for the stream socket
#rfile和wfile方法
Class Handler (Streamrequesthandler):
def handle (self):
addr = Self.request.getpeername ()
print ' Got connection from ', addr
Self.wfile.write (' Thank for connecting ')
#第二步. Where ' represents the host running the server
Server = TCPServer ((' ', 1234), Handler)
#第三步. Serve_forever () causes the loop state to enter
Server.serve_forever ()
Note: You can connect only one client at a time using a blocking or synchronizing method to connect to the next client after processing is complete.
Non-blocking or asynchronous programming
V. A simple example
1.socket Server
#!/usr/bin/env python
#-*-Coding:utf-8-*-
# Author:alex Li
#!/usr/bin/env python
#-*-Coding:utf-8-*-
#import Socketserver
Import socketserver,json,sys,subprocess
Class MyServer (Socketserver. Baserequesthandler):
def handle (self):
# Print Self.request,self.client_address,self.server
Self.request.sendall (bytes (' Welcome to admin interface. ', encoding= "Utf-8"))
While True:
#第一次获取客服端发送内容
data = SELF.REQUEST.RECV (1024)
#如果输入为空, continue with the next input
If Len (data) = = 0:break
#如果输入为查看目录内容
If str (data,encoding= ' utf-8 ') = = ' dir ':
Cmd=subprocess. Popen (Data.decode (), shell=true,stdout=subprocess. Pipe,stderr=subprocess. PIPE)
Cmd_res=cmd.stdout.read ()
If not cmd_res:
Cmd_res=cmd.stderr.read ()
If Len (cmd_res) ==0:
Cmd_res=bytes ("Result", encoding= ' GBK ')
Self.request.send (Cmd_res)
#接受下一次任务
Continue
#目录切换 if the received content contains a CD
If ' CD ' in str (data,encoding= ' utf-8 '):
Cmd=subprocess. Popen (Data.decode (), shell=true,stdout=subprocess. Pipe,stderr=subprocess. PIPE)
Cmd_res=cmd.stdout.read ()
If not cmd_res:
Cmd_res=cmd.stderr.read ()
If Len (cmd_res) ==0:
Cmd_res=bytes ("Result", encoding= ' GBK ')
Self.request.send (Bytes ("%s succeeded"%data,encoding= ' GBK '))
Continue
Print ("Data", data)
Print ("[%s] says:%s"% (Self.client_address,data.decode ()))
#执行传输任务
Task_data = Json.loads (Data.decode ())
Task_action = Task_data.get ("action")
If Hasattr (self, "task_%s"%task_action):
Func = GetAttr (self, "task_%s"%task_action)
Func (Task_data)
Else
Print ("Task action is not supported", task_action)
def task_put (Self,*args,**kwargs):
Print ("---put", Args,kwargs)
filename = args[0].get (' filename ')
FileSize = Args[0].get (' file_size ')
Server_response = {"Status": 200}
Self.request.send (Bytes (Json.dumps (server_response), encoding= ' Utf-8 '))
f = open (filename, ' WB ')
Recv_size = 0
While Recv_size < filesize:
data = SELF.REQUEST.RECV (4096)
F.write (data)
Recv_size + = len (data)
#进度条
Rate = Recv_size/filesize
rate_num= Int (Rate * 100)
r = ' \r[%-100s]%d%% '% (' = ' * rate_num,rate_num,)
Sys.stdout.write (R)
Print ("Connect success")
Sys.stdout.flush ()
F.close ()
if __name__ = = ' __main__ ':
Server = Socketserver. Threadingtcpserver ((' 127.0.0.1 ', 8009), MyServer)
Server.serve_forever ()
2.socket Client
#!/usr/bin/env python
#-*-Coding:utf-8-*-
# Author:alex Li
Import socket
Import OS, JSON
ip_port= (' 127.0.0.1 ', 8009)
#买手机
S=socket.socket ()
#拨号
S.connect (Ip_port)
#发送消息
Welcome_msg = S.RECV (1024)
Print ("From server:", Welcome_msg.decode ())
While True:
Send_data=input (">>:"). Strip ()
If Len (send_data) = = 0:continue
#查看目录下的文件
If send_data== ' dir ':
S.send (bytes (send_data,encoding= ' utf-8 '))
RECV_DATA=S.RECV (1024)
Print (str (recv_data,encoding= ' GBK '))
Continue
Cmd_list = Send_data.split (")
If Len (cmd_list) <2:continue
Task_type = cmd_list[0]
#目录切换方法
If task_type== ' CD ':
S.send (bytes (send_data,encoding= ' utf-8 '))
RECV_DATA=S.RECV (1024)
Print (str (recv_data,encoding= ' GBK '))
Continue
#文件传输
if Task_type = = ' Put ':
Abs_filepath = cmd_list[1]
If Os.path.isfile (Abs_filepath):
File_size = Os.stat (abs_filepath). st_size
filename = abs_filepath.split ("\ \") [-1]
Print (' file:%s size:%s '% (abs_filepath,file_size))
Msg_data = {"Action": "Put",
"FileName": filename,
"File_size": File_size}
S.send (Bytes (Json.dumps (msg_data), encoding= "Utf-8"))
Server_confirmation_msg = S.RECV (1024)
Confirm_data = Json.loads (Server_confirmation_msg.decode ())
If confirm_data[' status '] ==200:
Print ("Start sending file", filename)
f = open (Abs_filepath, ' RB ')
For line in F:
S.send (line)
Print ("Send file Done")
#跳出本次任务, start the next mission.
Continue
Else
Print ("\033[31;1mfile [%s] is not exist\033[0m"% Abs_filepath)
Continue
Else
Print ("doesn ' t support task type", Task_type)
Continue
#s. Send (bytes (send_data,encoding= ' UTF8 '))
#收消息
RECV_DATA=S.RECV (1024)
Print (str (recv_data,encoding= ' UTF8 '))
#挂电话
S.close ()
Python's socket