Python学习23——Socket套接字编程

Python学习23——Socket套接字编程

什么是Socket

socket是应用层 与 传输层 中间的软件抽象层,是一组接口。
在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面.
对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
在这里插入图片描述

Socket套接字的发展史

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。
因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。
一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯,这也被称进程间通讯或 IPC。
套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

  1. 基于文件类型的套接字家族

    套接字家族的名字:AF_UNIX

    unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

  2. 基于网络类型的套接字家族

套接字家族的名字:AF_INET

还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET。

TCP与UDP

TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)
在这里插入图片描述

对比TCPUDP
是否连接面向连接无连接
是否可靠可靠传输,使用流量控制和拥塞控制不可靠传输,不使用流量控制和拥塞控制
连接对象个数只能是一对一通信支持一对一,一对多,多对多交互通信
传输方式面向字节流面向报文
首部开销首部最小20字节,最大60字节首部开销小,仅8字节
适用场景适用于要求可靠传输的应用,例如文件传输适用于实时应用(IP电话、视频会议、直播等)

基于TCP协议通信的套接字程序

服务端要满足的特性:

1.一直对外提供服务

2.并发地提供服务

基础版:
server.py

import socket

# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议

# 2、插手机卡
phone.bind(("127.0.0.1", 8080))  # 本地回环

# 3、开机
phone.listen(5)
print('starting %s:%s' %("127.0.0.1", 8080))

# 4、等电话链接
conn, client_addr = phone.accept()

# 5、收/发消息
data = conn.recv(1024)  # 最大接收的字节个数
print("收到的客户端数据:", data.decode('utf-8'))
conn.send(data.upper())

# 6、关闭
conn.close()  # 挂电话
phone.close()  # 关机

client.py

import socket

# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议

# 2、拨电话
phone.connect(("127.0.0.1", 8080))

# 3、发/收消息
phone.send("hello".encode('utf-8'))
data = phone.recv(1024)
print("服务的返回的数据:", data.decode('utf-8'))

# 4、关闭
phone.close()

加入循环:
server.py

import socket

# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议

# 2、插手机卡
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加

phone.bind(("192.168.11.97", 8080))  # 本地回环

# 3、开机
phone.listen(5)
print('starting %s:%s' %("192.168.11.97", 8080))

# 4、等电话链接=>链接循环
while True:
    conn, client_addr = phone.accept()
    print(client_addr)
    # 5、收/发消息=>通信循环
    while True:
        try:
            data = conn.recv(1024)  # 最大接收的字节个数
            if len(data) == 0:  # 针对linux系统
                break
            print("收到的客户端数据:", data.decode('utf-8'))
            conn.send(data.upper())
        except Exception:  # 针对windows系统
            break

# 6、关闭
conn.close()  # 挂电话
phone.close()  # 关机

client.py

import socket

# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议

# 2、拨电话
phone.connect(("192.168.11.97", 8080))

# 3、发/收消息=>通信循环
while True:
    msg = input(">>: ").strip()
    phone.send(msg.encode('utf-8'))
    data = phone.recv(1024)
    print("服务的返回的数据:", data.decode('utf-8'))

# 4、关闭
phone.close()

远程执行命令:服务端开启后,客户端可以直接输入命令控制服务端,服务端返回输出的值
server.py

import socket
import subprocess

# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议

# 2、插手机卡
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 就是它,在bind前加

phone.bind(("127.0.0.1", 8080))  # 本地回环

# 3、开机
phone.listen(5)
print('starting %s:%s' % ("127.0.0.1", 8080))

# 4、等电话链接=>链接循环
while True:
    conn, client_addr = phone.accept()
    print(client_addr)
    # 5、收/发消息=>通信循环
    while True:
        try:
            cmd = conn.recv(1024)  # 最大接收的字节个数
            if len(cmd) == 0:  # 针对linux系统
                break

            obj = subprocess.Popen(cmd.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE
                                   )

            res=obj.stdout.read()+obj.stderr.read()  # ???
            print(res)
            conn.send(res)
        except Exception:  # 针对windows系统
            break

    # 6、关闭
    conn.close()  # 挂电话
phone.close()  # 关机

client.py

import socket

# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议

# 2、拨电话
phone.connect(("127.0.0.1", 8080))

# 3、发/收消息=>通信循环
while True:
    cmd = input("[root@localhost]# ").strip()
    phone.send(cmd.encode('utf-8'))
    data = phone.recv(1024)
    print(data.decode('gbk'))

# 4、关闭
phone.close()

基于udp协议的套接字通信

# TCP  VS  UDP协议
# 1、可靠性
# tcp协议是可靠协议:
#   对方必须回复一个ack确认信息,才会将自己这端的数据从内存中删除

# udp协议不可靠:
#   发送一条消息就会立即删除,不管对方是否接收到

# 2、有无链接
# tcp有链接,udp无链接

# 3、传输数据的效率
# udp更高

# 4、粘包问题
# udp协议称之为数据报协议,每次发送都是一个完整的数据报,一个发送唯一对应一个接收
# 所以udp协议没有粘包问题

server.py

from socket import *
import time

server = socket(AF_INET, SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

while True:
    data, client_addr = server.recvfrom(1024)
    time.sleep(10)
    server.sendto(data.upper(), client_addr)

client.py

from socket import *

client = socket(AF_INET, SOCK_DGRAM)

while True:
    msg = input('>>: ').strip()
    client.sendto(msg.encode("utf-8"), ('127.0.0.1', 8080))

    data, server_addr = client.recvfrom(1024)
    print(data.decode('utf-8'))

基于socketserver模块实现并发tcp

server.py

# from socket import *
#
#
# server=socket(AF_INET,SOCK_STREAM)
# server.bind(('127.0.0.1',8080))
# server.listen(5)
#
# while True:
#     conn,addr=server.accept()
#     print(addr)
#
#     while True:
#         try:
#             data=conn.recv(1024)
#             if len(data) == 0:break
#             conn.send(data.upper())
#         except Exception:
#             break
#
#     conn.close()

# 支持并发版本
import socketserver


class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):  # 处理通信
        print(self.client_address)
        while True:
            try:
                data = self.request.recv(1024)  # self.request=>conn
                if len(data) == 0: break
                self.request.send(data.upper())
            except Exception:
                break
        self.request.close()


if __name__ == '__main__':
    s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
    s.serve_forever()

client.py

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    msg=input(">>: ").strip()
    if len(msg) == 0:
        continue

    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

基于socketserver模块实现并发udp

server.py

import socketserver


class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):  # 处理通信
        data,server=self.request
        server.sendto(data.upper(),self.client_address)

if __name__ == '__main__':
    s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
    s.serve_forever()

client.py

from socket import *

client = socket(AF_INET, SOCK_DGRAM)

while True:
    msg = input('>>: ').strip()
    client.sendto(msg.encode("utf-8"), ('127.0.0.1', 8080))

    data, server_addr = client.recvfrom(1024)
    print(data.decode('utf-8'))

阿里云部署

server.py

# coding:utf-8
# from socket import *
#
#
# server=socket(AF_INET,SOCK_STREAM)
# server.bind(('127.0.0.1',8080))
# server.listen(5)
#
# while True:
#     conn,addr=server.accept()
#     print(addr)
#
#     while True:
#         try:
#             data=conn.recv(1024)
#             if len(data) == 0:break
#             conn.send(data.upper())
#         except Exception:
#             break
#
#     conn.close()

# 支持并发版本
import socketserver


class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):  # 处理通信
        print(self.client_address)
        while True:
            try:
                data = self.request.recv(1024)  # self.request=>conn
                if len(data) == 0: break
                self.request.send(data.upper())
            except Exception:
                break
        self.request.close()


if __name__ == '__main__':
    s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
    s.serve_forever()

client.py

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('121.199.45.113',8080))

while True:
    msg=input(">>: ").strip()
    if len(msg) == 0:
        continue

    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值