互联网的实现, 分成好几层. 每一层都有自己的功能, 就像建筑物一样, 每一层都靠下一层支持. 如何分层有不同的模型, 有的模型分七层, 有的分四层. 我觉得, 把互联网分成五层, 比较容易解释. 最底下的一层叫做 "实体层"(Physical Layer), 最上面的一层叫做 "应用层"(Application Layer), 中间的三层 (自下而上) 分别是 "链接层"(Link Layer),"网络层"(Network Layer)和 "传输层"(Transport Layer). 越下面的层, 越靠近硬件; 越上面的层, 越靠近用户.
TCP 编程
Socket 是网络编程的一个抽象概念. 通常我们用一个 Socket 表示 "打开了一个网络链接", 而打开一个 Socket 需要知道目标计算机的 IP 地址和端口号, 再指定协议类型即可.
客户端
创建 Socket
- # 导入 socket 库:
- import socket
- # 创建一个 socket:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- # 建立连接:
- s.connect(('www.sina.com.cn', 80))
创建 Socket 时, AF_INET 指定使用 IPv4 协议, 如果要用更先进的 IPv6, 就指定为 AF_INET6.SOCK_STREAM 指定使用面向流的 TCP 协议, 这样, 一个 Socket 对象就创建成功, 但是还没有建立连接.
连接服务器
s.connect(('www.sina.com.cn', 80))
注意参数是一个 tuple, 包含地址和端口号.
发送请求
- # 发送数据:
- s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
TCP 连接创建的是双向通道, 双方都可以同时给对方发数据. 但是谁先发谁后发, 怎么协调, 要根据具体的协议来决定. 例如, HTTP 协议规定客户端必须先发请求给服务器, 服务器收到后才发数据给客户端.
接收数据
- # 接收数据:
- buffer = []
- while True:
- # 每次最多接收 1k 字节:
- d = s.recv(1024)
- if d:
- buffer.append(d)
- else:
- break
- data = b''.join(buffer)
关闭 Socket
- # 接收数据:
- buffer = []
- while True:
- # 每次最多接收 1k 字节:
- d = s.recv(1024)
- if d:
- buffer.append(d)
- else:
- break
- data = b''.join(buffer)
服务器
创建 Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建一个基于 IPv4 和 TCP 协议的 Socket.
绑定监听的地址和端口
- # 监听端口:
- s.bind(('127.0.0.1', 9999))
- s.listen(5)
- print('Waiting for connection...')
listen()方法传入的参数指定等待连接的最大数量.
接受客户端连接
- while True:
- # 接受一个新连接:
- sock, addr = s.accept()
- # 创建新线程来处理 TCP 连接:
- t = threading.Thread(target=tcplink, args=(sock, addr))
- t.start()
每个连接都必须创建新线程 (或进程) 来处理, 否则, 单线程在处理连接的过程中, 无法接受其他客户端的连接:
- def tcplink(sock, addr):
- print('Accept new connection from %s:%s...' % addr)
- sock.send(b'Welcome!')
- while True:
- data = sock.recv(1024)
- time.sleep(1)
- if not data or data.decode('utf-8') == 'exit':
- break
- sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
- sock.close()
- print('Connection from %s:%s closed.' % addr)
UDP 编程
TCP 是建立可靠连接, 并且通信双方都可以以流的形式发送数据. 相对 TCP,UDP 则是面向无连接的协议.
使用 UDP 协议时, 不需要建立连接, 只需要知道对方的 IP 地址和端口号, 就可以直接发数据包. 但是, 能不能到达就不知道了.
虽然用 UDP 传输数据不可靠, 但它的优点是和 TCP 比, 速度快, 对于不要求可靠到达的数据, 就可以使用 UDP 协议.
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # 绑定端口:
- s.bind(('127.0.0.1', 9999))
创建 Socket 时, SOCK_DGRAM 指定了这个 Socket 的类型是 UDP. 绑定端口和 TCP 一样, 但是不需要调用 listen()方法, 而是直接接收来自任何客户端的数据:
- print('Bind UDP on 9999...')
- while True:
- # 接收数据:
- data, addr = s.recvfrom(1024)
- print('Received from %s:%s.' % addr)
- s.sendto(b'Hello, %s!' % data, addr)
recvfrom()方法返回数据和客户端的地址与端口, 这样, 服务器收到数据后, 直接调用 sendto()就可以把数据用 UDP 发给客户端.
注意这里省掉了多线程, 因为这个例子很简单.
客户端使用 UDP 时, 首先仍然创建基于 UDP 的 Socket, 然后, 不需要调用 connect(), 直接通过 sendto()给服务器发数据:
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- for data in [b'Michael', b'Tracy', b'Sarah']:
- # 发送数据:
- s.sendto(data, ('127.0.0.1', 9999))
- # 接收数据:
- print(s.recv(1024).decode('utf-8'))
- s.close()
从服务器接收数据仍然调用 recv()方法.
来源: http://www.jianshu.com/p/2b7f1fc59749