Comunicação de soquete e threads em Python

Quer escrever um software que possa se comunicar entre dois hosts diferentes? ? Quer imitar um software semelhante à loja de aplicativos? ? ?

Se você planeja desenvolver programas relacionados à rede, como software de bate-papo, você absolutamente não pode ignorar a programação de rede, e a comunicação de soquete é o foco da programação de rede.

1. Definição de Soquete

Dois programas na rede trocam dados por meio de uma conexão de comunicação bidirecional, e uma extremidade dessa conexão é chamada de soquete. (Citado da Enciclopédia Baidu) Emmmm... Para os alunos que querem entender a parte teórica, sugiro que verifiquem o conteúdo relevante em outros artigos, vamos focar nos aspectos práticos.

2. Um Exemplo Simples de Comunicação de Soquete

# -*-coding:utf-8 -*-
#   Server端
#   Server.py
import socket

HOST = '127.0.0.1'
PORT = 33333
ADDR = (HOST,PORT)
#  AF_INET 表示连接使用ipv4地址族  SOCK_STREAM表示用流式套接字
tcpSerSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcpSerSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 将套接字绑定该地址
tcpSerSock.bind(ADDR)
# 参数1表示阻塞模式  0表示非阻塞模式  默认为阻塞模式
tcpSerSock.setblocking(1)
# 开始监听TCP传入连接。参数指定在拒绝连接之前,操作系统可以挂起的最大连接数量。
tcpSerSock.listen(5)

print "Waiting connect..."
# tcpCliSock 是该链接的套接字,addr表示对方的地址
tcpCliSock, addr = tcpSerSock.accept()
# 设置超时时间
tcpCliSock.settimeout(20.0)
print '...connected from', addr
# recv(param)用于接收对方发送的数据 param为缓冲区大小
data = tcpCliSock.recv(1024)
print data
tcpCliSock.sendall("here is server")
# 关闭套接字
tcpCliSock.close()

# -*- coding: utf-8 -*-
# client端
#  Client.py
import socket

address = ('127.0.0.1', 33333)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.connect(address)

s.sendall("here is client")
data = s.recv(1024)
print data
s.close()

resultado da operação

resultados do lado do servidor

Resultados da execução do cliente

O método listen(x) é usado para escutar conexões TCP de entrada. O parâmetro especifica o número máximo de conexões que o sistema operacional pode suspender antes de rejeitar a conexão. Supondo que um host se conecte ao servidor, o servidor estabelecerá uma conexão com um para comunicação de soquete. Se o host b também se conectar ao servidor antes de a se desconectar do servidor, o servidor suspenderá a conexão com b e o servidor não se conectará a b até que a se desconecte do servidor. O parâmetro x do método listen é o número máximo de conexões que o servidor pode suspender.

Amigos que querem saber mais sobre os métodos do módulo socket, os métodos e parâmetros de uso detalhados, podem ler este artigo

No entanto, em aplicações práticas, o servidor geralmente precisa se conectar a vários clientes ao mesmo tempo, então o que devemos fazer? ? ? ? A solução pode ser habilitar multi-threading ou multi-processo. O multiprocessamento é mais caro do que o multithreading, mas para as configurações de servidor atuais (baseadas em Linux), esses custos são em grande parte insignificantes.

Vamos falar primeiro sobre servidores multithread hoje.

3.1 Multithreading

Multithreading refere-se à tecnologia que realiza a execução simultânea de vários threads de software ou hardware. Computadores com recursos multi-threading têm suporte de hardware para poder executar mais de um thread por vez, aumentando assim o desempenho geral do processamento.

Entendendo o multithreading com um exemplo simples

# -*- coding:utf-8 -*-
# simpleThread_1.py
import threading
import time

def process():
    n = 0
    while(n<5):
        print str(n)+": the threading %s is running"%threading.current_thread().name
        n = n + 1
        time.sleep(1)
# 创建新线程  target为线程要执行的方法  name为进程的名字,name参数可以省略,其实名字基本无多大用处
t1 = threading.Thread(target=process,name="One")
t2 = threading.Thread(target=process,name="Two")
t1.start()
t2.start()

então os threads t1 e t2 poderão ser executados ao mesmo tempo

Resultados de execução de SimpleThread_1.py

Se você adicionar vários: t1.join() entre t1.start() e t2.start(), então o thread t2 não começará a ser executado até que t1 termine de ser executado

3.2 Servidor multithread

#-*- coding:utf-8 -*-
#   多线程服务器   
#   threads_Server.py
import socket
import select
import threading
import time


def process(tcpCliSock,addr):
    print "connect from "+str(addr)
    pattern_data = tcpCliSock.recv(1024)
    print data
    tcpCliSock.sendall("here is server")
    


def run():
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(("127.0.0.1",33333))
    server.listen(5)
    while True:
        r,w,e = select.select([server,],[],[],1)
        # enumerate()分别列举出list r中的序号和内容
        for i,server in enumerate(r):
            conn,addr = server.accept()
            t = threading.Thread(target=process,args=(conn,addr))
            t.start()


if __name__=="__main__":
    run()

É claro que, na verdade, o cenário de aplicação mais comum de servidores multithread está em conexões longas.

Pois bem, temos outro problema. O cliente pode se desconectar repentinamente da conexão, mas o servidor não a encontra, quão triste o servidor deve estar, e não sabe [escape] depois de ser enganado. O servidor multithread enfrenta a conexão de tantos clientes, então como ele sabe se o cliente ainda está conectado ao servidor? Então lançamos outro artefato: o mecanismo do pacote de pulsação

O pacote de pulsação pode enviar periodicamente um pacote de dados para a outra parte e a conexão TCP pode ser julgada pela situação de envio.

Existem muitos métodos de design para o mecanismo de pacote de pulsação, como:

  • O cliente envia pacotes de pulsação para o servidor regularmente e o servidor envia um pacote para o cliente após receber o pacote de pulsação, para que ambas as partes possam saber se a outra parte está online.
  • O servidor envia periodicamente um pacote de heartbeat para o cliente. Se o envio falhar, significa que o cliente foi desconectado. Caso contrário, significa que o cliente ainda está conectado. Isso pertence ao monitoramento unilateral do servidor.

Existem mais de dois esquemas de design acima, e a situação específica é analisada em detalhes! ! ! Lembre-se, lembre-se! !

Então vamos dar uma olhada em como é um servidor multithread com um pacote heartbeat~

#-*- coding:utf-8 -*-
#   多线程服务器(心跳包版)   
#   hreatBeat_Server.py
import socket
import select
import threading
import time

# 心跳包线程  
def hreatBeat(conn):
    sum = 0   # 无回应次数
    while True:
        time.sleep(10)
        if sum<3:
            try:
                conn.sendall("hreatBeat")
                sum=0
            except socket.error:
                sum = sum + 1
                continue
        else:
            conn.close()
            break

def process(tcpCliSock,addr):
    print "connect from "+str(addr)
    pattern_data = tcpCliSock.recv(1024)
    print data
    tcpCliSock.sendall("here is server")
     #  创建心跳包线程
     #  须记住,创建新线程时 args参数如果只有一个的话一定要加个逗号!!
    thr = threading.Thread(target=hreatBeat, args=(tcpCliSock,))
        thr.start()
        #  thr.is_alive() 用于监测进程thr是否还存在(即client是否还在连接中)
        while thr.is_alive():
            print "do everything you like here"
    


def run():
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(("127.0.0.1",33333))
    server.listen(5)
    while True:
        r,w,e = select.select([server,],[],[],1)
        # enumerate()分别列举出list r中的序号和内容
        for i,server in enumerate(r):
            conn,addr = server.accept()
            t = threading.Thread(target=process,args=(conn,addr))
            t.start()


if __name__=="__main__":
    run()

4. Resumo

Começar com a comunicação Socket é fácil, mas ir fundo não é fácil. Se você quer melhorar, aprenda mais e pratique mais! Acredite que o conhecimento acima é suficiente para você construir um protótipo de um servidor de sucesso. Como programador, os requisitos são os primeiros, e tudo deve ser analisado em combinação com os requisitos específicos.

Amigos que estão aprendendo programação e Python, é difícil aprender por uma pessoa, e os blogueiros também estão aqui. Aqui, um novo grupo de dedução foi criado: 1020465983, que preparou recursos de aprendizado e projetos divertidos para todos. Bem-vindos a todos para participar e comunicar.

Acho que você gosta

Origin blog.csdn.net/weixin_56659172/article/details/124119776
Recomendado
Clasificación