python10-socket

socket网络编程

  • socket基于tcp、ip协议的工具
  • 所有的网络通信都基于socket
    • wanghzh/p/5560787.html
    • wupeiqi/articles/5040823.html
  • 客户端去访问服务器:
    • TCP:三次握手
    • UDP:单向访问
    • python支持unix系统进程与进程之间的通信

自己实现socket客户端和服务端

socket服务端
import socket

sk = socket.socket()  # 服务器启动,创建socket
ip_port = ('127.0.0.1', 9999)
sk.bind(ip_port)  # socket绑定ip和端口作为服务端
sk.listen(5)  # socket服务器支持连接等待的数量

while True:
    sock, addr = sk.accept()  # 阻塞等待客户端访问
    sock.sendall(bytes('已链接到服务器', encoding='utf-8'))
    print(type(sock))
    while True:
        try:
            byte_data = sock.recv(1024) # 客户端如果断开了,这里会报异常
            data = str(byte_data, encoding='utf-8')
            ret = '服务器:%s' % data
            sock.sendall(bytes(ret, encoding='utf-8'))
            if data == 'q':
                break
        except Exception as e:
            break
        else:
            pass
        finally:
            pass
socket客户端
import socket

client = socket.socket()  # 创建socket
client.connect(('127.0.0.1', 9999,))  # socket去连接服务端
byte_data = client.recv(1024)
print(str(byte_data, encoding='utf-8'))
while True:
    inp = input()
    client.sendall(bytes(inp, encoding='utf-8'))
    byte_data = client.recv(1024)
    data = str(byte_data, encoding='utf-8')
    if data == '服务器:q':
        print('断开连接')
        break
    else:
        print(data)
client.close()
  • socket.sendall()方法在python2.7中接收字符串,在python3.x中接收ude是字节

socket更多方法

  • wupeiqi/articles/5040823.html
sk = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM,proto=0)
# family:socket.AF_INET = IPv4(默认) IPv6
# type:TCP协议
# proto:默认为0
sk.bind((ip,port,)
# 服务端绑定IP和port
sk.listen(count)
# 开始监听,参数表示最多等待的数量,当count == 2
# 一个客户端连上了服务器,如果再有2个客户端访问,后面的2个会处于等待状态,当再有客户端访问,超过count == 2的客户端会报错
sk.setblocking(bool)
# 是否阻塞
# True:阻塞(默认)
# False:不阻塞,当socket调用recv和accept时会报错,以后会用到
sk.connect((ip,port,)
# 客户端连接服务端
sk.connect_ex((ip,port,)
# 同上,只是如果连接上,则返回0,如果连不上,返回错误码
sk.close()
# 断开连接
sk.recv(1024)
# 接收信息,参数表示一次最所接收多少个字节
sk.recvfrom(buffersize)
# 从哪里接收UPD用到
sk.send()
# 发送信息,2.7中接收字符串,3.x中接收字节
# send方法有个弊端,实际发送的数据会出现少于实质传入的数据
sk.sendall()
# 底层通过循环和send方法发送数据,不会出现数据丢失
sk.sendto()
# 针对UDP
sk.settimeout()
# 设置超时
sk.getsocketname()
# 返回socket自己的地址
sk.getpeername()
# 返回socket连接远程的地址
sk.fileno()
# socket的文件描述(后面会用到)

socket实现文件上传

  • 注意防止粘包问题
server
import socket

server = socket.socket()
server.bind(('127.0.0.1', 9999))
server.listen(5)
print('服务器启动:\n>>>>>')

while True:
    conn,address = server.accept()
    print('获取到客户端访问:ip:%s port:%s'%(address[0], address[1]))
    retStr = '文件上传服务器,请发送文件名以及文件大小'
    conn.sendall(bytes(retStr, encoding='utf-8'))
    fileInfo = conn.recv(1024)
    fileInfo = str(fileInfo, encoding='utf-8')
    fileName, fileLength = fileInfo.split('&')
    print('获取到文件名:%s 文件大小:%s'%(fileName,fileLength))
    conn.sendall(bytes('接收成功',encoding='utf-8'))
    totalLength = int(fileLength)
    hasLoadSize = 0
    file = open(fileName, mode='wb')
    while True:
        if hasLoadSize >= totalLength:
            break
        data = conn.recv(1024)
        file.write(data)
client
import socket
import os
client = socket.socket()
client.connect(('127.0.0.1', 9999))

connectInfo = client.recv(1024)
connectInfo = str(connectInfo, encoding='utf-8')
print(connectInfo)
fileName = input('请输入文件名\n>>> ')
fileLength = os.stat('dest_top_img.jpg').st_size
ret_msg = '%s&%s'%(fileName,fileLength)
client.sendall(bytes(ret_msg, encoding='utf-8'))
rec_msg = client.recv(1024)
print(str(rec_msg, encoding='utf-8'))
print(str(rec_msg, encoding='utf-8'))
with open('dest_top_img.jpg', mode='rb') as file:
    for line in file:
        client.sendall(line)
client.close()
  • 粘包原因:
    • 报错:ImageNotLoaded(下载完后打不开文件)
    • 客户端发送文件到服务端,需要依赖系统的缓冲区
    • 服务端接收客户端发送的文件,需要到缓冲区取
    • 但是客户端缓冲区什么时候发送是系统决定的,不可控,可能存在这种情况,当发送文件名和文件大小给服务器的时候,数据存放在缓冲区还没发送出直接发送文件内容,当服务端获取文件和文件大小的字段带有一部分文件的内容,这就导致需要发送的文件到服务器实际接收的时候不完整
    • 解决:发送文件名、大小和发送文件之间与服务器做一个响应

socketserver模块实现多并发

  • socket模块不支持多并发,服务端同一时刻只支持响应一个客户端请求
  • 处理并发有两种方式:
    • IO多路复用

    • socketserver模块:由python提供的另一个模块,用于解决多并发访问的问题

      • 内部实现:IO多路复用&多线程或多进程并发操作
    • 实现步骤:

      • 创建类继承:socketserver.BaseRequestHandler
      • 创建server,传入ip端口和刚创建的类
      • 开启服务
```
import socketserver

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request) # 客户端的连接
        print(self.client_address) # 客户端地址
        print(self.server) # 当前服务器:server

if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1',9999),MyServer)
    server.serve_forever()
# 
# ('127.0.0.1', 4971)
# 
```

```
import socket
client = socket.socket()
client.connect(('127.0.0.1',9999))
```

梳理

  • 对象中封装对象
  • 面向对象的两种特性
    • 装饰器 + 方法
    • @property + 方法
  • python2.7继承流程
    • 继承object类(新式类):顶部最后
    • 未继承object类(经典类):一条道走到黑,深度优先
  • python3.x继承流程
    • 顶部最后
  • 抽象类和抽象方法(python中目前用的不多)
    • 约束
    • 接口(python没有接口)
    • 抽象类+抽象方法

你可能感兴趣的:(python10-socket)