Python网络编程底层包socket的使用

本文介绍了Python中使用socket进行网络编程的基础,包括TCP和UDP的服务器与客户端实现。TCP编程涉及服务端创建socket、bind、listen、accept及数据收发;客户端的connect和数据交换。UDP编程则不需连接,服务端和客户端通过sendto和recvfrom进行数据传输。此外,还讨论了心跳机制在TCP和UDP中的应用,并对比了TCP与UDP在连接、可靠性和有序性上的区别。
摘要由CSDN通过智能技术生成


Python中提供socket.py标准库,非常底层的接口库。
Socket是一种通用的网络编程接口,和网络层次没有一一对应的关系。

构建socket对象

socket = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  • family : 协议族
名称 含义
AF_INEET IPV4(默认值)
AF_INET6 IPV6
AF_UNIX Unix Domain Socket, windows没有
  • type: socket类型
名称 含义
SOCK_STREAM 面向连接的流套接字, 即TCP协议(默认值)
SOCKET_DGRAM 无连接的数据报文套接字。即UDP协议

TCP编程

socket编程需要两端,一般来说,需要一个服务端(Server),一个客户端(Client)

这种编程模式也称为CS编程

socket对象常用方法:

方法 含义
socket.getpeername 返回套接字的远程地址,返回值是raddr
socket.getsocketname 返回套接字自己的地址,返回值为laddr

TCP服务端编程

  • 创建socket对象
  • 使用bind方法,绑定IP地址,Address和端口Port
  • 使用listen开始监听,在上面以绑定的地址上
  • 使用accept开始等待连接进来,获取用于传送数据的socket对象和addr。注意使用accept会发生阻塞,惯用放在新的线程里面
    • 接收数据recv, buffsize可以选用1024,接收的字节流bytes
    • 发送数据send,发送的也是字节流bytes

构建一个TCP协议的远古版本群聊服务端

import datetime
import socket
import threading


class ChatSocket:
   def __init__(self, ip="127.0.0.1", port=9999): # 本地localhost也可以用""或者"localhost"表示
       self.addr = (ip, port)   
       self.socket = socket.socket()  # 创建socket对象
       self.clients = {}  # 创建客户端词典
       self.event = threading.Event()
       self.lock = threading.Lock() # 设置一把锁,为了遍历客户端的字典的时候保证线程安全

   def start(self):
       self.socket.bind(self.addr)  # 绑定端口
       self.socket.listen(2)  # 开始监听,监听客户端无上限
       threading.Thread(target=self.accept).start()  # 如果不创建此线程,下面的等待连接accept会阻塞当前的主线程,导致无法执行最后的stop

   def accept(self):
       while not self.event.is_set():  # 标志位的设置是为了stop时,不再 等待新线程的接入
           new_socket, client_info = self.socket.accept()  # 等待连接,阻塞,多人连接
           with self.lock:
               self.clients[client_info] = new_socket
           print(client_info, "已连接")
           t = threading.Thread(target=self.recv_send, args=(new_socket, client_info)) # 由于recv会发生阻塞行为
           t.start()

   def recv_send(self, new_socket, clint_info):
       while not self.event.is_set():
           data = new_socket.recv(1024)  # 设置一次最大读取数据上限是1024字节,阻塞,如果客户端主动断开连接,会收到空的字符串
           print(data)
           if data.decode().strip() == "quit" or data.decode().strip() == "":  # 客户端上的退出按钮会返回一个空字符串或者发送quit退出
               print("用户", clint_info[1], "quit")
               with self.lock:
                   self.clients.pop(clint_info)
                   new_socket.close()
               break
           msg = "用户{} {}说: {}".format(clint_info[1], datetime.datetime.now(), data.decode(encoding="gbk"))
           print(msg)
           with self.lock:
               for s in self.clients.values():  # 群聊的性质就是将从client接收的信息,转发给当前所有连接到server的client客户端,是一种很,标识符的选择一定要慎重
                   s.send(msg.encode(encoding="gbk"))

   def stop(self):
       self.event.set()  # 设为True
       with self.lock:
           for s in self.clients.values():
               s.close()
       self.socket.close()


cs = ChatSocket()
cs.start()
while True:
   cmd = input(">>").strip()
   if cmd == "quit":
       cs.stop()
       threading.Event().wait(3)
       break

TCP客户端

再构建一个客户端
客户端连接步骤:

  • 创建Socket对象
  • 连接到远端服务端的IP和port端口, connect方法
  • 传输数据
    • send发送数据
    • recv接收数据, 会阻塞
  • 关闭连接,释放资源
import socket
import threading
import logging

fmt = "%(asctime)s %(threadName)s %(thread)s %(message)s"
logging.basicConfig(format=fmt, level=logging.INFO)

class Client:
    def __int__(self, ip="127.0.0.1", port=9999):
        self.sock = socket.socket() # 建立socket对象
        self.addr = ip, port
        self.event = threading.Event()

    def start(self):
        self.<
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值