Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erklärung des erweiterten Python-Sockets

Detaillierte Erklärung des erweiterten Python-Sockets

高洛峰
高洛峰Original
2016-10-17 16:13:55999Durchsuche

Die ursprüngliche englische Bedeutung von Socket ist „Loch“ oder „Buchse“. Als Prozesskommunikationsmechanismus von BSD UNIX wird er allgemein auch als „Socket“ bezeichnet, der zur Beschreibung von IP-Adressen und Ports verwendet wird. Er ist das Handle einer Kommunikationskette und kann zur Implementierung der Kommunikation zwischen verschiedenen virtuellen Maschinen oder verschiedenen Computern verwendet werden .

Zwei Programme im Netzwerk tauschen Daten über eine bidirektionale Kommunikationsverbindung aus. Ein Ende dieser Verbindung wird als Socket bezeichnet.

Mindestens ein Paar Portnummern (Socket) ist erforderlich, um eine Netzwerkkommunikationsverbindung herzustellen. Socket ist im Wesentlichen eine Programmierschnittstelle (API), die TCP/IP kapselt und Programmierern eine Schnittstelle zur Netzwerkentwicklung bietet Spezifische Form; Socket ist die Engine, die die Fähigkeit zur Netzwerkkommunikation bereitstellt.

Lassen Sie uns über den Python-Socket sprechen.

1.socket-Modul

Verwenden Sie die Funktion socket.socket(), um einen Socket zu erstellen. Die Syntax lautet wie folgt:

socket.socket(socket_family,socket_type,protocol=0)


socket_family kann die folgenden Parameter sein:


socket.AF_INET IPv4 (Standard)

socket.AF_INET6 IPv6


socket.AF_UNIX kann nur verwendet werden auf einem einzelnen Unix-System kann die prozessübergreifende Kommunikation


socket_type die folgenden Parameter sein:


socket.SOCK_STREAM Streaming socket, für TCP (Standard)

socket.SOCK_DGRAM Datagram socket, für UDP


socket.SOCK_RAW Raw-Socket, gewöhnlicher Socket kann ICMP, IGMP und nicht verarbeiten andere Netzwerknachrichten, aber SOCK_RAW kann auch spezielle IPv4-Nachrichten verarbeiten. Darüber hinaus kann der IP-Header vom Benutzer über die Socket-Option IP_HDRINCL erstellt werden.

Socket.SOCK_RDM ist eine zuverlässige Form von UDP, die die Zustellung von Datagrammen garantiert, jedoch nicht die Reihenfolge. SOCK_RAM wird verwendet, um Low-Level-Zugriff auf das Originalprotokoll bereitzustellen und wird verwendet, wenn bestimmte spezielle Vorgänge ausgeführt werden müssen, beispielsweise das Senden von ICMP-Nachrichten. SOCK_RAM ist normalerweise auf Programme beschränkt, die von Hauptbenutzern oder Administratoren ausgeführt werden.

 socket.SOCK_SEQPACKET Zuverlässiger kontinuierlicher Paketdienst


Protokollparameter:


 0 ( Standard) Das einer bestimmten Adressfamilie zugeordnete Protokoll. Wenn es 0 ist, wählt das System automatisch ein geeignetes Protokoll basierend auf dem erstellten Adressformat und der Socket-Kategorie aus -in-Methode


Serverseitige Socket-Funktion


s.bind() Bindungsadresse (IP-Adresse, Port ) zum Socket müssen die Parameter im Format von Tupeln vorliegen. Beispiel: s.bind(('127.0.0.1',8009))


s.listen( 5) Beginnen Sie mit dem Zuhören, 5 ist die maximale Anzahl ausstehender Verbindungen


s.accept() Akzeptieren Sie passiv Client-Verbindungen, blockieren Sie und warten Sie auf Verbindungen


Client-Socket-Funktion


s.connect() Stellen Sie eine Verbindung zum Server her. Die Parameter müssen im Tupelformat vorliegen. connect(('127,0.0.1',8009))


Öffentliche Socket-Funktion


s .recv(1024) TCP-Daten empfangen, 1024 ist die Größe eines Datenempfangs


s.send(bytes) TCP-Daten senden, das Format von Python3, das Daten sendet Muss sein im Byteformat


s.sendall() Senden Sie die Daten vollständig und die innere Schleife ruft send


s auf .close ()Schließen Sie den Socket


Beispiel 1. Einfache Implementierung des Socket-Programms

serverseitig

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import socket
import time
IP_PORT = ('127.0.0.1',8009)
BUF_SIZE = 1024
  
tcp_server = socket.socket()
tcp_server.bind(IP_PORT)
tcp_server.listen(5)
  
while True:
    print("waiting for connection...")
    conn,addr = tcp_server.accept()
    print("...connected from:",addr)
    while True:
        data = tcp_server.recv(BUF_SIZE)
        if not data:break
        tcp_server.send('[%s] %s'%(time.ctime(),data))
  
tcp_server.close()
Erklärung des obigen Codes:

Zeile 1~4


Die Die erste Zeile ist Unix. Die Startinformationszeile, dann das Zeitmodul und das Socket-Modul importieren


5~10 Zeilen


IP_PORT ist eine globale Variable. Die IP-Adresse und der Port werden deklariert, was darauf hinweist, dass die Funktion bind() an diese Adresse gebunden ist und die Puffergröße auf 1K eingestellt ist. Die Funktion listen() gibt die maximale Anzahl zulässiger Verbindungen an gleichzeitig ein, und nachfolgende Verbindungen werden abgelehnt


11~Gehe zur letzten Zeile


Danach Wenn Sie in die Schleife des Servers eintreten, warten Sie passiv auf das Eintreffen der Verbindung. Wenn eine Verbindung besteht, treten Sie in die Konversationsschleife ein und warten Sie, bis der Client Daten sendet. Wenn die Nachricht leer ist, bedeutet dies, dass der Client beendet wurde. Er bricht aus der Schleife aus und wartet auf das Eintreffen der nächsten Verbindung. Fügen Sie nach Erhalt der Client-Nachricht einen Zeitstempel vor der Nachricht hinzu und kehren Sie zurück. Die letzte Zeile wird nicht ausgeführt, da die Schleife nicht beendet wird und der Server close() nicht ausführt. Nur zur Erinnerung: Vergessen Sie nicht, die Funktion close() aufzurufen.


Client


#!/usr/bin/env python

# _*_ coding:utf-8 _*_
import socket
  
HOST = '127.0.0.1'
PORT = 8009
BUF_SIZE = 1024
ADDR = (HOST,PORT)
  
client = socket.socket()
client.connect(ADDR)
  
while True:
    data = input(">>> ")
    if not data:break
    client.send(bytes(data,encoding='utf-8'))
    recv_data = client.recv(BUF_SIZE)
    if not recv_data:break
    print(recv_data.decode())
      
client.close()

5~11行

HOST和PORT变量表示服务器的IP地址与端口号。由于演示是在同一台服务器所以IP地址都是127.0.0.1,如果运行在其他服务器上要做相应的修改。端口号要与服务器端完全相同否则无法通信。缓冲区大小还是1K。


客户端套接字在10行创建然后就去连接服务器端


13~21行


客户端也无限循环,客户端的循环在以下两个条件的任意一个发生后就退出:1.用户输入为空的情况或者服务器端响应的消息为空。否则客户端会把用户输入的字符串发送给服务器进行处理,然后接收显示服务器返回来的带有时间戳的字符串。


运行客户端程序与服务端程序


以下是客户端的输入与输出

[root@pythontab]# python client.py 
>>> hello python
[Thu Sep 15 22:29:12 2016] b'hello python'

   


以下是服务端输出

[root@pythontab]# python server.py 
waiting for connection...
...connected from: ('127.0.0.1', 55378)

   

3.socketserver模块

socketserver是标准库中的一个高级别的模块。用于简化实现网络客户端与服务器所需要的大量样板代码。模块中已经实现了一些可以使用的类。


实例1:使用socketserver实现与上面socket()实例一样的功能


服务端程序代码

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import socketserver
import time
  
HOST = '127.0.0.1'
PORT = 8009
ADDR = (HOST,PORT)
BUF_SIZE = 1024
  
class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            print("...connected from:",self.client_address)
            data = self.request.recv(BUF_SIZE)
            if not data:break
            self.request.send(bytes("%s %s"%(time.ctime(),data)))
  
server = socketserver.ThreadingTCPServer(ADDR,Myserver)
print("waiting for connection...")
server.serve_forever()

   


11~17行


主要的工作在这里。从socketserver的BaseRequestHandler类中派生出一个子类,并重写handle()函数。


在有客户端发进来的消息的时候,handle()函数就会被调用。


19~21行


代码的最后一部分用给定的IP地址和端口加上自定义处理请求的类(Myserver)。然后进入等待客户端请求与处理客户端请求的无限循环中。


客户端程序代码

import socket
HOST = '127.0.0.1'
PORT = 8009
ADDR = (HOST,PORT)
BUF_SIZE = 1024
  
client = socket.socket()
client.connect(ADDR)
  
while True:
    data = input(">>> ")
    if not data:continue
    client.send(bytes(data,encoding='utf-8'))
    recv_data = client.recv(BUF_SIZE)
    if not recv_data:break
    print(recv_data.decode())
  
client.close()

   

执行服务端和客户端代码  


下面是客户端输出

[root@pythontab]# python socketclient.py 
>>> hello python
Thu Sep 15 23:53:31 2016 b'hello python'
>>> hello pythontab
Thu Sep 15 23:53:49 2016 b'hello pythontab'

   


下面是服务端输出

[root@pythontab]# python socketserver.py 
waiting for connection...
...connected from: ('127.0.0.1', 55385)
...connected from: ('127.0.0.1', 55385)
...connected from: ('127.0.0.1', 55385)
...connected from: ('127.0.0.1', 55385)


   


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn