Python基础-面向对象-网络传输套接字

socket

简介

socket是应用层与TCP/IP协议通信的中间的软件抽象层,它是一组接口。把复杂的TCP/IP协议足隐藏在接口后面,对用户来说,一组简单的接口就是全部,socket去组织数据,以符合指定的协议

  • recv在缓冲区为空时,阻塞
  • recvfrom在缓冲区为空时,接收为空的字节
基于文件的套接字 AF_UNIX

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

基于网络类型的套接字 AF_INET

基于网络作为介质实现通信,还有AD_INET6,被用于ipv6等其它网络类型套接字

示意图

TCP客户端                       TCP服务端

socket()                        socket()
    |                               ↓
    |                            bind()
    |                               ↓
    |                           listen()
    ↓                               ↓
connect()   <--建立连接-->       accept()
    ↓                               ↓   阻塞,直到有客户端连接
write()     <--请求数据-->        read()
    ↓                               ↓   处理请求
read()      <--回应数据---       write()
    ↓                               ↓
close()     ---结束连接-->        read()
                                    ↓
                                  close()

套接字方法

服务端套接字函数
名称释义
s.bind()绑定(主机,端口号)到套接字
s.listen()开始TCP监听
s.accept()被动接受TCP客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
名称释义
s.connect()主动初始化TCP服务器连接
s.connect_ex()connect//90函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
名称释义
s.recv()接收TCP数据
s.send()发送TCP数据(send在待发送数据量大于己端缓存区剩余空间是,数据丢失,不会发完)
s.sendall()发送完成的TCP数据(本质是循环调用send,待发送数据量大于己端缓存区剩余空间时,数据不会丢失,循环调用send直到发完)
s.recvform()接收UDP数据
s.sendto()发送UDP数据
s.getpeername()连接到当前套接字的远端地址
s.getsockname()当前套接字地址
s.getsockopt()返回指定套接字的参数
s.setsockopt()设置指定套接字的参数
s.close()关闭套接字
面向锁的套接字方法
名称释义
s.setblocking()设置套接字的阻塞与非阻塞模式
s.settimeout()设置阻塞套接字操作的超时时间
s.gettimeout()得到阻塞套接字操作的超时时间
面向文件的套接字函数
名称释义
s.filen()套接字的文件描述符
s.makefile()创建一个与该套接字相关的文件

TCP传输套接字

简单示例

服务端

# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议
test.bind(('127.0.0.1',8000))      #定义通信ID
test.listen(5)                     #定义最大通信监听数
conn,addr = test.accept()          #定义对话连接
msg = conn.recv(1024)              #定义接收字节信息
print('客户端发送的消息是:',msg)
conn.send(msg.upper())              #定义发送消息
conn.close()                        #连接关闭
test.close()                        #程序关闭
客户端发送的消息是: b'hello'

客户端

# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议
test.connect(('127.0.0.1',8000))           #定义通信ID,服务器的地址和端口
test.send('hello'.encode('utf-8'))         #定义发送内容
data = test.recv(1024)                     #定义接收字节信息
print('收到服务端的发来的消息是:',data)   
收到服务端的发来的消息是: b'HELLO'
TCP网络传输套接字示例

原示例

import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

优化示例

form socket import *
test = socket(AF_INET,SOCK_STREAM)

==也可以将值以变量形式写入到配置文件中导入==

服务端优化示例
# -*- coding:utf8 -*-
from socket import *

test = socket(AF_INET,SOCK_STREAM)
ip_port = ('127.0.0.1',8000)
back_log = 5
buffer_size = 1024

test.bind(ip_port)                 #定义通信ID
test.listen(back_log)              #定义最大通信监听数
conn,addr = test.accept()          #定义对话连接

msg = conn.recv(1024)  # 定义接收字节信息
print('客户端发送的消息是:',msg)
conn.send(msg.upper())              #定义发送消息
conn.close()                        #连接关闭
test.close()                        #程序关闭
循环发送示例

服务端

# -*- coding:utf8 -*-
from socket import *

tcp_servive = socket(AF_INET,SOCK_STREAM)
ip_port = ('127.0.0.1',8000)
back_log = 5
buffer_size = 1024

tcp_servive.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)       #防止服务端再次启用导致端口被占用错误
tcp_servive.bind(ip_port)                               #定义通信ID
tcp_servive.listen(back_log)                            #定义最大通信监听数

while True:
    print("服务端程序运行中。。。")
    conn, addr = tcp_servive.accept()       #定义对话连接(循环收发消息)
    while True:
        try:                                #客户端异常断开处理
            msg = conn.recv(buffer_size)    #定义接收字节信息
            print('客户端发送的消息是:',msg.decode('utf-8'))
            conn.send(msg.upper())          #定义发送消息
        except Exception:
            print("客户端强制断开!")
            break
conn.close()                               #连接关闭
tcp_servive.close()                        #程序关闭

客户端

# -*- coding:utf8 -*-
from socket import *

ip_port = ('127.0.0.1',8000)
buffer_size = 1024

tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)                  #定义通信ID,服务器的地址和端口

while True:
    msg = input(">>>请输入需要发送的消息!".strip())
    if not msg:continue                                 #判断值是否为空
    tcp_client.send(msg.encode('utf-8'))                #定义发送内容
    print('客户端已经发送消息:',msg)
    data = tcp_client.recv(buffer_size)                 #定义接收字节信息
    print('收到服务端的发来的消息是:', data.decode('utf-8'))
tcp_client.close()
TCP协议远程执行命令示例

粘包特性

服务端

from socket import *
import subprocess
ip_port = ('127.0.0.1',8080)
back_log = 5
buffer_size = 4096

tcp_server = socket(AF_INET,SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)

while True:
    conn,addr=tcp_server.accept()           #建立连接
    print('新的客户端链接',addr)
    while True:
            #接收信息
        try:
            cmd=conn.recv(buffer_size)
            if not cmd:break
            print('收到客户端的命令',cmd.decode('utf-8'))
            #执行命令
            res=subprocess.Popen(cmd.decode('utf-8'),shell=True,
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 stdin=subprocess.PIPE)
            err=res.stderr.read()
            if err:
                cmd_res=err
            else:
                cmd_res=res.stdout.read()

            #发送信息
            if not cmd_res:
                cmd_res='执行成功'.encode('gbk')
            conn.send(cmd_res)
        except Exception as e:
            print(e)
            break

客户端

from socket import *
ip_port = ('127.0.0.1',8080)
back_log = 5
buffer_size = 4096

tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)

while True:
    cmd=input('>>请输入需要执行的命令: ').strip()
    if not cmd:continue
    if cmd == 'quit':break

    tcp_client.send(cmd.encode('utf-8'))
    cmd_res=tcp_client.recv(buffer_size)
    print('命令的执行结果是 ',cmd_res.decode('gbk'))
tcp_client.close()

UDP网络传输套接字

简单示例

服务端

udp_service = socket()      #创建一个服务器套接字
udp_service.bind()          #绑定服务器套接字
while True:                 #服务器通讯循环
    udp_service.recvfrom()  #服务端接收消息
    udp_sendto.recvfrom()   #服务端发送消息
udp_service.close()         #关闭服务端套接字

客户端

udp_client = socket()       #创建一个客户端套接字
while True:                 #客户端通讯循环
    udp_service.recvfrom()  #服务端接收消息
    udp_sendto.recvfrom()   #服务端发送消息
udp_client.close()          #关闭客户端套接字
UDP网络传输套接字示例示例

服务端示例

# -*- coding:utf-8 -*-
from socket import *
ip_port = ('127.0.0.1',8080)                    #定义通信ID
buffer_size = 4096                              #定义接收字节信息
udp_service = socket(AF_INET,SOCK_DGRAM)        #定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议

udp_service.bind(ip_port)                       #通信ID

print("服务端运行中...")
while True:
    msg,addr = udp_service.recvfrom(buffer_size)     #定义接收字节信息(元组形式)
    print("接收到的消息是:",msg.decode('utf-8'))    #打印接受到的字节信息
    udp_service.sendto(msg.upper(),addr)             #返回并修改传输值

客户端示例

# -*- coding:utf-8 -*-
from socket import *
ip_port = ('127.0.0.1',8080)                    #定义通信ID
buffer_size = 4096                              #定义接收字节信息
udp_client = socket(AF_INET,SOCK_DGRAM)         #定义socket通信方式和通信协议。socket.AF_INET基于网络通信,socket.SOCK_STREAM基于TCP协议

while True:
    msg = input(">>>请输入您要发送的内容".strip())
    udp_client.sendto(msg.encode('utf-8'),ip_port)  #定义发送内容和到达地址

    msg,addr = udp_client.recvfrom(buffer_size)     #定义接收字节信息(元组形式)
    print(msg.decode('utf-8'))                      #打印返回的字节信息
UDP协议远程执行命令示例

不粘包特性

服务端

from socket import *
import subprocess
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=4096

udp_server=socket(AF_INET,SOCK_DGRAM)
udp_server.bind(ip_port)

while True:
    #接收消息
    cmd,addr=udp_server.recvfrom(buffer_size)

    # 执行命令,得到命令的运行结果cmd_res
    res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                           stderr=subprocess.PIPE,
                           stdout=subprocess.PIPE,
                           stdin=subprocess.PIPE)
    err = res.stderr.read()
    if err:
        cmd_res = err
    else:
        cmd_res = res.stdout.read()

    if not cmd_res:
        cmd_res='执行成功'.encode('gbk')

    #发送消息
    udp_server.sendto(cmd_res,addr)

客户端

from socket import *
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=4096

udp_client=socket(AF_INET,SOCK_DGRAM)

while True:
    cmd=input('>>请输入需要执行的命令: ').strip()
    if not cmd:continue
    if cmd == 'quit':break

    udp_client.sendto(cmd.encode('utf-8'),ip_port)
    cmd_res,addr=udp_client.recvfrom(buffer_size)
    print('命令的执行结果是 ',cmd_res.decode('gbk'),end='')

udp_client.close()

SocketServer

简介

socketserver 是标准库中一个高级别的模块,用于简化网络客户与服务器的实现。

1、要实现本模块,必须定义一个继承于基类BaseRequestHandler的处理程序类。BaseRequestHandler类的实例可以实现以下方法:

> h.handle() 
调用该方法执行实际的请求操作。调用该函数可以不带任何参数,但是几个实例变量包含有用的值。h.request包含请求,h.client_address包含客户端地址,h.server包含调用处理程序的实例。对TCP之类的数据流服务,h.request属性是套接字对象。对于数据报服务,它是包含收到数据的字节字符串。

> h.setup()
该方法在handle()之前调用。默认情况下,它不执行任何操作。如果希望服务器实现更多连接设置,可以在这里实现。

> h.finish()调用本方法可以在执行完handle()之后执行清除操作。如果setup()和 handle()都不生成异常,则无需调用该方法。

2、服务器。要使用处理程序,必须将其插入到服务器对象。定义了四个基本的服务器类。

    1、TCPServer 支持ipv4的TCP协议的服务器。
    2、UDPServer 支持ipv4的UDP协议的服务器。
    3、UnixStreamServer 使用UNIX域套接字实现面向数据流协议的服务器,集成自TCPserver。
    4、UnixDatagramServer 继承自UDPServer

四个服务器类的实例都有一下方法和变量:

    1、s.socket 用于传入请求的套接字对象
    2、s.server_address 监听服务器的地址
    3、s.RequestHandleClass 传递给服务器构造函数并由用户提供的请求处理程序类
    4、s.server_forever() 处理无线的请求
    5、s.shutdown() 停止server_forever()循环
    6、s.fileno() 返回服务器套接字的整数文件描述符。该方法可以有效的通过轮询操作实例

SocketServer简单示例

import socketserver

class   自定义类(socketserver.BaseRequestHandler):
    def handle(self):
    pass
socketserver.ThreadingTCPServer((),自定义类)
s.server_forever

SocketServer TCP多线程并发实例

服务端

# -*- cond:utf8 -*-
import socketserver                                     #导入多并发模块

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        print('conn is: ',self.request)   #conn
        print('addr is: ',self.client_address) #addr
        while True:
            try:
            #收消息
                data=self.request.recv(1024)
                if not data:break
                print('收到客户端的消息是',data,self.client_address)
                #发消息
                self.request.sendall(data.upper())
            except Exception as e:
                print(e)
                break

if __name__ == '__main__':
    s=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer) #多线程
    print('服务运行中...')
    s.serve_forever()

客户端(允许多个一样的客户端)

from socket import *
ip_port=('127.0.0.1',8080)
back_log=5
buffer_size=1024

tcp_client=socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
    msg=input('>>请输入您要发送的内容: ').strip()
    if not msg:continue
    if msg == 'quit':break
    tcp_client.send(msg.encode('utf-8'))
    data=tcp_client.recv(buffer_size)
    print('收到服务端发来的消息:',data.decode('utf-8'))
tcp_client.close()

转载于:https://my.oschina.net/zhaojunhui/blog/1806544

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值