博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 之网络编程
阅读量:7092 次
发布时间:2019-06-28

本文共 7312 字,大约阅读时间需要 24 分钟。

1222878-20180323071035070-713967707.png

# 流程描述:## 1. 服务器根据地址类型(ipv4, ipv6), socket类型, 协议创建socket;## 2. 服务器为socket绑定ip地址和端口号;## 3. 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开;## 4. 客户端创建socket## 5. 客户端打开socket, 根据服务器ip地址和端口号试图连接服务器socket;## 6. 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket#   进入阻塞状态, 所谓阻塞即accept()方法一直等到客户端返回连接信息后才返回,开始接收下一个客户端连接请求。## 7. 客户端连接成功,向服务器发送连接状态信息;## 8. 服务器 accept 方法返回,连接成功;## 9. 客户端向socket写入信息(或服务端向socket写入信息)## 10. 服务器读取信息(或客户端读取信息)## 11. 客户端关闭# 12. 服务端关闭

1.1 相关方法及参数介绍

import socketsk = socket.socket()
  • sk.bind(address):将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式
    表示地址;
  • sk.listen(backlog):开始监听传入的连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。
    backlog等于5,表示内核已经接到的连接请求,但服务器还没有调用accept进行处理的连接个数最大为5。这个值不可能无限大,因为要在内核中维护连接队列;
  • sk.setblocking(bool): 是否阻塞(默认为True), 如果设置为False, 那么accept和recv时,一旦无数据,则报错;
  • sk.accept(): 接收连接并返回(conn, address), 其中conn是新的套接字对象,可以用来接收和发送数据;address是
    连接客户端的地址;
  • sk.connect(address): 连接到address处的套接字。一般,address的格式为元组(hostname, port),如果连接出错,
    返回socket.error错误;
  • sk.connect_ex(address): 同上,只不过会有返回值,连接成功时,返回0; 连接失败的时候,返回编码,例如: 10061
  • sk.close(): 关闭套接字;
  • sk.recv(bufsize[, flag]): 接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。
  • sk.recvfrom(bufsize[,flag]): 与recv()类似,但返回值是 (data, address), 其中,data是包含接收数据的字符串,
    address 是发送数据的套接字地址;
  • sk.send(string[,flag]): 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字
    节大小。即: 可能未将指定内容全部发送。
  • sk.sendall(string[,flag]): 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功,返回None;
    失败则抛出异常。内部通过递归调用 send, 将所有内容发送出去。
  • sk.sendto(string[,flag], address): 将数据发送到套接字,address的形式为元组(ipaddr, port)。返回值是发送的
    字节数,该函数主要用于UDP协议;
  • sk.settimeout(timeout):设置套接字操作的超时时长,timeout是一个浮点数,单位是秒。值为None,表示没有超时期。
  • sk.getpeername():返回连接套接字的远程地址。返回值通常是元组(ipaddr, port);
  • sk.getsockname():返回套接字自己的地址,通常是一个元组(ipaddr, port);
  • sk.fileno(): 套接字的文件描述符;
# 示例一: 建立连接# sever 端import socket# 创建socket对象sk = socket.socket()# 绑定ip和端口address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print("waiting......")conn = sk.accept()    # 此时,返回一个包含两个元素的元组print(conn)# client 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.connect(address)# 示例二: 服务端发送,客户端接收# server 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print('waiting......')conn, addr = sk.accept()# 发送消息msg = input('>>>')# conn.send(msg), 此处会报错: a bytes-like object is required, not 'str'conn.send(bytes(msg, 'utf8'))# client 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.connect(address)# 接收消息data = sk.recv(1024)    # 此处,客户端会阻塞,等待服务端发送消息print(str(data, 'utf8'))# 示例三: 客户端发送, 服务端接收# server 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print('waiting......')conn, addr = sk.accept()# 接收消息data = conn.recv(1024)  # 注意,服务端使用 conn 来收发数据print(data)conn.close()    # 关闭连接# client 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.connect(address)# 发送消息sk.send(bytes('大家好', 'utf8'))sk.close()# 示例四: 不间断聊天# server 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print('waiting......')conn, addr = sk.accept()while True:    data = conn.recv(1024)    if not data:        break    print(str(data, 'utf8'))    msg = input('>>>')    conn.send(bytes(msg, 'utf8'))conn.close()# client 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.connect(address)while True:    msg = input('>>>')    if msg == 'exit':        break    sk.send(bytes(msg, 'utf8'))    data = sk.recv(1024)    print(str(data, 'utf8'))sk.close()# 示例五:# server 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print('waiting......')while True:    conn, addr = sk.accept()    # 某一个客户端关闭后,可以接收另外一个客户端发来的消息    print(addr)    while True:        try:            data = conn.recv(1024)        except Exception:            break        if not data:            break        print(str(data, 'utf8'))        msg = input('>>>')        conn.send(bytes(msg, 'utf8'))sk.close()# 示例六: 远程执行命令# server 端import socketimport subprocesssk = socket.socket()address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print('waiting......')while True:    conn, addr = sk.accept()    print(addr)    while True:        data = conn.recv(1024)        if not data:            break        print(str(data, 'utf8'))        obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE)        cmd_result = obj.stdout.read()        # 只能传输bytes类型数据,int首先转成str,然后转成bytes        result_len = bytes(str(len(cmd_result)), 'utf8')        # 获取传输内容的大小        conn.sendall(result_len)        conn.recv(1024)     # 解决粘包问题        conn.sendall(cmd_result)sk.close()# client 端import socketsk = socket.socket()address = ('127.0.0.1', 8000)sk.connect(address)while True:    msg = input('>>>')    if msg == 'exit':        break    sk.send(bytes(msg, 'utf8'))    result_len = int(str(sk.recv(1024), 'utf8'))    sk.sendall('ok')    data = bytes()      # 空字节    while len(data) != result_len:        data += sk.recv(1024)    print(str(data, 'utf8'))# 示例七: 上传文件# server 端import socketimport ossk = socket.socket()address = ('127.0.0.1', 8000)sk.bind(address)sk.listen(3)print('waiting......')BASE_DIR = os.path.dirname(os.path.abspath(__file__))while True:    conn, addr = sk.accept()    while True:        data = conn.recv(1024)        cmd, file_name, file_size = str(data, 'utf8').split('|')        path = os.path.join(BASE_DIR, 'a', file_name)        file_size = int(file_size)        f = open(path, 'ab')        has_receive = 0        while has_receive != file_size:            data = conn.recv(1024)            f.write(data)            has_receive += len(data)        f.close()sk.close()# client 端import socketimport ossk = socket.socket()address = ('127.0.0.1', 8000)sk.connect(address)BASE_DIR=os.path.dirname(os.path.abspath(__file__))while True:    msg = input('>>>').strip()  # 规定输入格式为: post|a.jpg(命令|路径), strip()去除首尾空格    cmd, path = msg.split('|')    # 路径拼接, 因为传入的path可能为 a/b/a.jpg    path = os.path.join(BASE_DIR, path)    # 获取文件名称    filename = os.path.basename(path)    # 获取文件大小    file_size = os.stat(path).st_size    file_info = 'post|%s|%s' % (filename,file_size)    # 向服务端发送消息    sk.sendall(bytes(file_info, 'utf8'))    # 向服务端发送文件内容    f = open(path, 'rb')    # 以bytes的格式读取数据    has_sent = 0    while has_sent != file_size:        data = f.read(1024)     # 每次发送1024字节数据        sk.sendall(data)        has_sent += len(data)    f.close()    print('上传成功!')

2. socketserver 模块

# 示例一: server端并发聊天# server 端import socketserverclass MyServer(socketserver.BaseRequestHandler):    def handle(self):        print('服务端启动...')        while True:            conn = self.request            print(self.client_address)            while True:                client_data = conn.recv(1024)                print(str(client_data, 'utf8'))                print('waiting......')                conn.sendall(client_data)            conn.close()if __name__ == '__main__':    server = socketserver.ThreadingTCPServer(('127.0.0.1', 8000), MyServer)    server.serve_forever()# client 端import socketip_port = ('127.0.0.1', 8000)sk = socket.socket()sk.connect(ip_port)print('客户端启动:')while True:    msg = input('>>>')    sk.sendall(bytes(msg, 'utf8'))    if msg == 'exit':        break    server_response = sk.recv(1024)    print(str(server_response, 'utf8'))sk.close()

参考资料:

转载于:https://www.cnblogs.com/linkworld/p/8628229.html

你可能感兴趣的文章
ConcurrentHashMap中的putIfAbsent方法的使用以及返回值的含义
查看>>
计算机速度GHz等于每秒多少次
查看>>
linux实现共享内存同步的四种方法
查看>>
Memcache的安装和使用【转】
查看>>
CoffeeScirpt中文手册
查看>>
Python_删除/创建指定目录及其下所有子目录的文件,该文件记录当前文件夹的内容...
查看>>
泰为信息科技(上海)有限公司 (高级)网站开发工程师(@CBE Dept.)
查看>>
MVVM Light (Part 4)
查看>>
很强大的 js拖曳效果
查看>>
Document versioning
查看>>
jbpm入门样例
查看>>
Unity3D如何减少安装包大小
查看>>
漫游Kafka设计篇之数据持久化
查看>>
Java提高篇——equals()与hashCode()方法详解
查看>>
oracle用户创建
查看>>
dubbo-admin 管理台的部署
查看>>
ACM进阶计划
查看>>
【转】数据库中查询记录时是否每次只能使用一个索引?
查看>>
C#单例测试(懒汉式双锁保证线程安全)
查看>>
Java知识点总结
查看>>