iOS webSocket整理
iOS处方接入Socket调研。
项目背景:
纳里医生使用Object-C开发,为了避免引入swift产生混编,影响编译速度。故Socket的方案从OC框架中进行选择。
框架选择:
为了实时获取服务器的最新信息,长连接的经历了,轮询 -》长轮询 -》websocket 三个阶段。
轮询 | 长轮询 | websocket |
---|---|---|
定时发送请求 | 实时更新 | 实时更新 |
消耗大,延迟 | 客户端发送请求,服务器用更新是响应 | 使用HTTP进行握手,TCP/UDP进行数据传输, |
OC websocket 方案选择
基于使用Github星数,初步选择 CocoaAsyncSocket 和 SocketRocket
实现原理:
基于Socket API(为了便于使用对TCP/UDP进行了封装)
//1.生成内核socket;2。与文件描述符绑定
socket(AF_UNIX, SOCK_STREAM, 0);
//建立连接,包含三次握手
connect(sockfd, (struct sockaddr *)&address, len);
//绑定一个IP地址和端口到socket套接字上
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
//半连接队列、全连接队列
int listen(int sockfd, int backlog)
//返回一个new的socket文件描述符(不占用端口号)
accept(server_sockfd,(struct sockaddr *)&client_address, client_len);
//断开连接,包含四次挥手(TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列。TIME_WAIT原因)
int close(int sockfd);
由于OC对Socket有更深层次的封装,故 CocoaAsyncSocket 和 SocketRocket 使用的是 NSOutputSteam 和 NSInputStream 进行的数据的读取操作。同时由于NSStream不能读取远程数据,故使用的是对应的CFStream(CFReadStreamRef/CFWriteStreamRef)来实现。
CocoaAsyncSocket 和 SocketRocket 使用对比
CocoaAsyncSocket | SocketRocket | |
---|---|---|
线程管理 | 已封装CGD线程安全 | 已封装CGD线程安全 |
连接方式 | 多种方式 | URL形式 |
必须根目录 | 是 | 否 |
单独的心跳消息 | 否 | 是 |
自动接收服务器消息 | 否 | 是 |
故综合分析,为了使用方便,选择SocketRocket作为长连接的方案。 |
服务端简单的python代码
import hashlib
import base64
import socket
def ws_accept_key(ws_key):
"""calc the Sec-WebSocket-Accept key by Sec-WebSocket-key
come from client, the return value used for handshak
:ws_key: Sec-WebSocket-Key come from client
:returns: Sec-WebSocket-Accept
"""
try:
magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
sha1 = hashlib.sha1()
sha1.update((ws_key + magic).encode('utf-8'))
return base64.b64encode(sha1.digest())
except Exception as e:
print("出错了", e)
return None
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定IP,端口
server_socket.bind(("0.0.0.0", 80))
# 监听
server_socket.listen(5)
print ("show key = ", ws_accept_key('pHuz2gMvj8tYkR4E+Q4gOA=='))
while 1:
conn, addr = server_socket.accept()
print('地址', addr)
while 1:
receiveMsg = conn.recv(1024)
print('接收到 ', receiveMsg.decode('utf-8'))
tempRequest = receiveMsg.decode('utf-8')
if tempRequest == "":
continue
arr = tempRequest.split('\r\n')
tempkey = arr[2].split(': ')[1]
print('key =', tempkey)
accpet = ws_accept_key(tempkey).decode('utf-8')
print('accpet = ', accpet)
yy = 'GET HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Accept: '
yy = yy + accpet + '\r\n\r\n'
# conn.send(yy.encode('utf-8'))
conn.sendall(bytes(yy.encode('utf-8')))