1. HTTP、Socket、TCP
网络模型和协议位置:
1. socket 不属于任何协议,可以看作操作系统给的api。 通过socket我们可以利用TCP和UDP协议。比如QQ就是利用socket自己构建一套应用层协议,来实现聊天功能的。
2. http实现不了双向, 比如网站的聊天功能利用websocket协议, http实现不了这样的功能。
2. 利用socket 实现client和server通讯
socket编程流程(左侧server端,右侧client端):
http: 三次握手后,recv,send就close了。下次通讯又得三次握手。显然不满足我们聊天功能的需求。
实时聊天: 三次握手不断开, 不断重复recv和send
代码实现server和client通信
server:
import socket
# AF_INET ip4网络 SOCK_STREAM 表示tcp
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 8000))
server.listen()
sock, addr = server.accept()
# 获取从客户端发送的数据
data = sock.recv(1024) # 一次获取1024字节 即1k的数据
print(data.decode('utf8'))
sock.send('hello back'.encode('utf8'))
server.close()
sock.close()
client:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('0.0.0.0', 8000))
client.send('hello'.encode('utf8'))
data = client.recv(1024)
print(data.decode('utf8'))
client.close()
3. socket 实现聊天功能和多用户连接
1. 先实现单对单聊天
server:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 5000))
server.listen()
sock, addr = server.accept()
while True:
data = sock.recv(1024) # server先recv再send
print(data.decode('utf8'))
re_data = input()
sock.send(re_data.encode('utf8'))
client:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('0.0.0.0', 5000))
while True:
re_data = input()
client.send(re_data.encode('utf8')) # clinet端先send后recv
data = client.recv(1024)
print(data.decode('utf8'))
2. 实现多人聊天
server:
import socket
import threading
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 6000))
server.listen()
def handle_sock(sock, addr):
while True:
data = sock.recv(1024)
message = data.decode('utf8')
print(message)
if message == 'exit': # client 发送exit时, 连接断开
break
re_data = input()
sock.send(re_data.encode('utf8'))
sock.close()
while True:
sock, addr = server.accept()
# 用线程处理新的用户连接
client_thread = threading.Thread(target=handle_sock, args=[sock, addr])
client_thread.start()
client:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('0.0.0.0', 6000))
while True:
re_data = input()
client.send(re_data.encode('utf8'))
data = client.recv(1024)
print(data.decode('utf8'))
4. socket 模拟http请求
以get百度为例子:
import socket
from urllib.parse import urlparse
def get_url(url):
# 通过socket请求html
url = urlparse(url)
host = url.netloc # www.baidu.com
path = url.path
if path == "":
path = '/'
# 建立socket连接
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, 80))
client.send(
"GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode('utf8'))
data = b""
while True:
d = client.recv(1024)
if d:
data += d
else:
break
data = data.decode('utf8')
html_data = data.split('\r\n\r\n')[1] # 把请求头信息去掉, 只要网页内容
print(html_data)
client.close()
if __name__ == '__main__':
get_url('http://www.baidu.com')