2.scoket 网络编程技术
一、网络编程技术概述
1.软件开发架构
- 应用类 -- C/S 架构 - C/S:客户端与服务器端架构,客户端 泛指 应用程序 EXE ,程序需要先安装才能运行,对系统环境依赖较大。
- Web 类 -- B/S 架构 - B/S:浏览器端与服务器端架构,用户通过 HTTP 请求服务器端相关的资源。
2.网络通信要素
- IP 地址 :互联网协议地址
- 端口 :设备与外界通讯交流的出口
- 传输协议
提示
IP 地址 精确到 具体的一台电脑,而 端口 精确到 具体的程序
3.通信协议
通信协议:互联网的核心就是由一堆协议组成,协议就是标准。
七层网络协议模型

二、Socket 通信流程
1.Socket 概念
Socket :是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口。
 在设计模式中,Sorcket 其实就是一个门面模式,它把复杂的 TPC/IP 协议族隐藏在 Socket 接口后面,对用户来说,一组简单的接口就是全部,让 Socket 去组织数据,以符合指定的协议。
提示
1.websocket (应用层) :通过 HTTP 协议进行传输,
2.socket (传输层) :通过 TCP 协议进行传输
2.Socket 实现方式:TCP 协议与 UDP 协议
- TCP协议 :可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。- 主要用途:Web 浏览器、电子邮件、文件传输程序 
- UDP协议 : 不可靠的、无连接的服务,传输效率高,一对一、多对多、一对多、多对一、面向报文,尽最大的努力服务,无拥塞控制。- 主要用途:域名系统、视频流、IP 语音。 
- TCP和- UDP都是 传输层 的。
TCP 协议流程图:

3. Socket 通信流程
- 服务器根据地址类型、Socket 类型、协议 创建 Scoket ; 
- 服务器为 socket 绑定 IP 地址和端口号 ; 
- 服务器 socket 监听端口号请求 ,随时准备 接收客户端发送来的连接,这个时候服务器端的 Socket 并没有打开; 
- 客户端创建 Socket ; 
- 客户端打开 socket ,根据服务器 IP 地址和 端口号 试图连接服务器 socket ; 
- 服务器 Scoket 接收到客户端的 socket 请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这个时候 socket 进入阻塞状态。 - 阻塞状态:即- accept()方法一直等到客户端返回连接信息后才返回,开始接收下一个客户端连接请求。
- **客户端连接成功,****向服务器发送连接状态信息**。 
- 服务器 accept 方法返回,连接成功; 
- 客户端向 socket 写入信息(或服务端向 socket 写入信息); 
- 服务器读取信息(客户端读取信息); 
- 客户端关闭; 
- 服务器关闭。 

Socket 常用方法
1.Python 的 Socket 编程
- 低级别的网络服务 支持基本的 Socket,它提供了标准的 BSD Socket API ,可以访问底层操作系统 Socket 接口的全部方法。
- **高级别的网络服务 **模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。
2.什么是 Socket 编程
socket :又称 ”套接字“ ,应用程序通常通过 ”套接字“ 向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
使用 socket() 函数来 创建 套接字
socket.socket([family[,type[,proto]]])- family:套接字家族可以使 AF_UNIX 或者 AF_INET .
- type:套接字类型可以根据是面向 连接 的还是 非连接 分为 SOCK_STREAM 或 SOCK_DGRAM .
- protocol:一般不填默认为 0 。
3. Socket 服务端
- 使用 socket 模块 的 socket 函数 来创建一个 socket 对象。socket 对象可以通过调用其他函数来设置一个 socket 服务。
- 可以通过调用 bind(hostname,port)函数来指定服务的 port (端口)。
- 调用 socket 对象 的 accept 方法。该方法等待客户端的连接,并返回 connection 对象,表示已连接到客户端。
4. Socket 客户端
- socket.connect(hosname, port)方法 打开一个 TCP 连接到主机为 hostname 端口为 port 的服务商。
- 连接后就可以从服务端获取数据,记住,操作完成 后需要 关闭连接
5.案例一(单个连接)
服务端:
import socket
ip_port = ('127.0.0.1', 9999)
# 1.创建 socket 对象
sk = socket.socket()
# 2.绑定 ip port
sk.bind(ip_port)
# 3.开启监听
sk.listen()
print("---服务已经启动---")
# 4.阻塞 等待连接  返回:socket连接对象(套接字)和 客户端IP
conn, addr = sk.accept()
print("客户端的地址 >>> :", addr)
# 5.接收数据---客户端数据
# recv() 需要文件宽度作为参数,一般为 1024
# 使用 decode() 进行解码
receive_data = conn.recv(1024).decode("utf-8")
print("接收客户端的数据 >>> :", receive_data)
# 6.发送数据
send_data = input("请输入 >>> :")
# sendall() 要求是 byte 类型,使用encode() 进行字符转换
conn.sendall(send_data.encode("utf-8"))
# 7.关闭 socket
conn.close()客户端:
import socket
# 1.创建 socket
sk = socket.socket()
# 2.连接到服务器
sk.connect(('127.0.0.1', 9999))
print("服务端连接成功")
# 3.发送数据
send_data = input("请输入 >>> :")
# sendall() 要求是 byte 类型,使用encode() 进行转码
sk.sendall(send_data.encode('utf-8'))
# 4.接收服务端数据
server_data = sk.recv(1024).decode("utf-8")
print("接收服务端的数据 >>> :", server_data)
# 5.关闭 socket
sk.close()案例二(多个连接):
服务端:
import socketserver
# 1.需要继承一个类
class sqServer(socketserver.BaseRequestHandler):
    def handle(self):
        print("聊天服务器上线了")
        while True:
            try:
                # 接收客户端数据
                self.client_data = self.request.recv(1024)
                print(self.client_data.decode("utf-8"))
                # 发送数据
                send_data = input("请输入 >>> :")
                self.request.sendall(send_data.encode("utf-8"))
            except ConnectionResetError as e:
                print("一个客户端关闭了连接")
                break
        self.request.close()
# 2.创建服务
# ThreadingTCPServer 是使用多线程
# ForkingTCPServer 是使用多进程处理并发
server = socketserver.ThreadingTCPServer(("127.0.0.1", 9998), sqServer)
# 3.一直在线
server.serve_forever()客户端:
import socket
# 1.创建 socket
sk = socket.socket()
# 2.连接到服务器
sk.connect(('127.0.0.1', 9998))
print("服务端连接成功")
# 3.发送数据
while True:
    send_data = "老王:" + input("请输入 >>> :")
    if send_data == '老王:' + 'exit':
        break
    else:
        # sendall() 要求是 byte 类型,使用encode() 进行转码
        sk.sendall(send_data.encode('utf-8'))
        # 4.接收服务端数据
        server_data = sk.recv(1024).decode("utf-8")
        print("接收服务端的数据 >>> :", server_data)
# 5.关闭 socket
sk.close()