萌ICP备20220458号

Python socket 通信初步

2022年4月16日 1750点热度 1人点赞 0条评论

Python 中的 socket 是一个用于网络通信的基本模块,我们可以使用 socket 来进行简单的网络通信以及深入了解 socket

socket 对象

首先我们来了解一下 socket 对象。

socket 的建立

这一部分我们会使用简单的示例来演示 socket 的建立。

  • 客户端的 socket 可以由以下几种方式创建:
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建一个 socket 对象,AF_INET 指定使用 IPV4 地址,SOCK_STREAM 指定使用 TCP 协议

s.connect(('www.baidu.com', 80))
# 连接到 www.baidu.com 地址的 80 端口

# do something

或者

import socket

with socket.create_connection(('www.baidu.com', 80)) as s:
    # do something
  • 服务端的 socket 可以由以下几种方式创建:
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(('localhost', 9999))
# 绑定端口

s.listen(5)
# 监听端口,最多可以接受 5 个连接

while True:
    # 接受一个新连接

    c, addr = s.accept()
    # 创建新的 socket 对象

    # do something

或者

import socket

with socket.create_server(('localhost', 9999)) as s:
    c, addr = s.accept()
    # do something

如果想同时支持 IPv6,也可以

import socket

kwargs = {'family': socket.AF_INET6, 'dualstack_ipv6': True} if socket.has_dualstack_ipv6() else {}
with socket.create_server(('localhost', 9999), **kwargs) as s:
    c, addr = s.accept()
    # do something

数据的发送和接收

  • 发送数据
s.send(b'Hello, world')
# 发送 TCP 数据,发送的数据必须是 `bytes` 类型,如果是字符串,需要先进行编码。
# 该方法不保证能够发送所有的数据,返回值为实际发送的字节数。

s.sendall(b'Hello, world')
# 类似于 `send`,但是如果发送不完,则会一直等待直到发送完毕。
# 发送成功后返回 `None`,如果发送失败,则抛出异常。

s.sendfile(file)
# 发送文件。
# 发送成功后返回发送字节总数。
  • 接收数据
data = s.recv(1024)
# 接收 TCP 数据,接收的数据是 `bytes` 类型,如果收到的数据实为字符串,需要先进行解码。
# 该方法需要指定接收的最大字节数,返回值为实际接收到的数据。

关闭连接

s.close()
# 关闭连接

s.shutdown(socket.SHUT_RDWR)
# 关闭连接,同时关闭发送和接收。

提高性能

上面的示例中,我们的实现是单线程的,如果要提高性能,可以使用多线程或者多进程。

import socket
import threading

def handle_request(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    # do something
    sock.close()
    print('Connection from %s:%s closed.' % addr)

with socket.create_server(('localhost', 9999)) as s:
    while True:
        c, addr = s.accept()
        t = threading.Thread(target=handle_request, args=(c, addr))
        t.start()

或者

import socket
import multiprocessing

def handle_request(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    # do something
    sock.close()
    print('Connection from %s:%s closed.' % addr)

with socket.create_server(('localhost', 9999)) as s:
    while True:
        c, addr = s.accept()
        t = multiprocessing.Process(target=handle_request, args=(c, addr))
        t.start()

一个简单的登录认证服务器

我们来看一个简单的登录认证服务器,它可以接收密钥,并返回一个登录结果。

  • 服务端
import socket
import multiprocessing
import hashlib

token = input('Please input the token: ').strip()
hashed_token = hashlib.sha256(token.encode('utf-8')).hexdigest()

def handle_request(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    cli_hash = sock.recv(1024).decode('utf-8')
    if hashed_token == cli_hash:
        sock.send(b'OK')
    else:
        sock.send(b'Bad token')
    sock.close()
    print('Connection from %s:%s closed.' % addr)

with socket.create_server(('localhost', 9999)) as s:
    while True:
        c, addr = s.accept()
        t = multiprocessing.Process(target=handle_request, args=(c, addr))
        t.start()
  • 客户端
import socket
import hashlib

token = input('Please input the token: ').strip()
hashed_token = hashlib.sha256(token.encode('utf-8')).hexdigest()

with socket.create_connection(('localhost', 9999)) as s:
    s.send(hashed_token.encode('utf-8'))
    ret = s.recv(1024).decode('utf-8')
    print(ret)

NhanchouBaimin

A noob.

文章评论