WebSocket流程
websocket https://github.com/dhbaird/easywsclient
Server端
- socket()
- bind()
- listen()
- accept()
- recv()
Client端
- socket()
- connect()
- send()
Lwip-API
lwip_socket
功能:用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源的函数
函数原型
1
参数选项
domain:地址族AF_INET(IP_V4)、AF_INET6(IP_V6)
type:
1
2
3ptotocol
1
2
3
4
5
// 一般自动设置为0, 系统自动设置合适的协议
lwip_connect
函数功能:用于建立与指定socket的连接。一般用于客户端,
函数原型
1
参数
- s :socket()返回文件描述符代表的套接字
- const struct sockaddr *name:存放了服务端用于通信的地址和端口。
- socklen_t namelen:name参数结构体的长度。
lwip_setsockopt
功能:设置与某个套接字关联的选项,当操作套接字选项时,选项位于的层和选项的名称必须给出
函数原型:
1
int setsockopt(int sock, int level,int optname, const void *optval, socklen_t optlen)
参数选项
sock:将要被设置选项的套接字
optname:需要访问的选项名
optval:指向包含新选项值得缓冲
optlen:现选项的长度
level:参数(level)详细说明:level是指定控制套接字的层次,可以取如下三种值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20选项名称(optname) 说明 数据类型
========================================================================
SO_BROADCAST 允许发送广播数据 int
SO_DEBUG 允许调试 int
SO_DONTROUTE 不查找 int
SO_ERROR 获得套接字错误 int
SO_KEEPALIVE 保持连接 int
SO_LINGER 延迟关闭连接 struct linger
SO_OOBINLINE 带外数据放入正常数据流 int
SO_RCVBUF 接收缓冲区大小 int
SO_SNDBUF 发送缓冲区大小 int
SO_RCVLOWAT 接收缓冲区下限 int
SO_SNDLOWAT 发送缓冲区下限 int
SO_RCVTIMEO 接收超时 struct timeval
SO_SNDTIMEO 发送超时 struct timeval
SO_REUSERADDR 允许重用本地地址和端口 int
SO_TYPE 获得套接字类型 int
SO_BSDCOMPAT 与BSD系统兼容 int
========================================================================
// SOL_SOCKET:通用套接字选项1
2
3
4
5
6
7
8选项名称(optname) 说明 数据类型
========================================================================
IP_HDRINCL 在数据包中包含IP首部 int
IP_OPTINOS IP首部选项 int
IP_TOS 类型
IP_TTL 生存时间 int
========================================================================
//IPPROTO_IP:IP选项1
2
3
4
5
6选项名称(optname) 说明 数据类型
========================================================================
TCP_MAXSEG TCP最大数据段的大小 int
TCP_NODELAY 不使用Nagle算法 int
========================================================================
// IPPROTO_TCP:TCP选项
lwip_fcntl
- 功能:fcntl 的最小实现。 目前仅实现了命令 F_GETFL 和 F_SETFL。 只有标志 O_NONBLOCK 被实现。
lwip_send / lwip_sendto / lwip_write
功能:发送数据
区别:
- lwip_send:核心, 最终的调用
- lwip_write:直接调用lwip_send
- Lwip_sendto:相较于lwip_to多了远程主机的ip地址和端口号相关的参数,处理中多了netconn_connect的调用(lwip_connect + lwip_send)
函数原型
1
lwip_select
功能:用于I/O多路复用的API,使用select可以同时监听多个socket的状态,以便读写数据
原型
1
2
3
lwip_select(maxfdp1,readset,writeset,exceptset,timeout)参数含义
maxfdp1:要检查的最大文件描述符的数目,一般是最大dp+1
readset/writeset/exceptset:
fd_set类型,指向需要监听的可读、可写和异常事件的文件描述符集合
lwip_recv
函数功能:接受数据
函数原型
1
Q&A
Q:调用lwip_send / lwip_recv时出现WSAEWOULDBLOCK / WSAEINPROGRESS
A:本质上以上两个错误码不是错误,而是一种警告,接收方告诉发送方它现在处于busy状态
WSAEWOULDBLOCK的意思是output buffer已经满了,无法再写入数据。按照网上博主的说法,在绝大多数情况下其实不会出现buffer满的情况,而是 处于busy状态。我理解的这与overrun的意思差不多,只不过这里不会对数据正确性、完整性造成影响,接收方告诉我它的缓冲区满了或者数据已经处理 不过来了,它不再接受数据了,所以给我们一个异常。
WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。
解决:当出现 WSAEWOULDBLOCK 异常后直到空出 Output Buffer 时,系统会发送一个 FD_WRITE 给发送方。我们完全可以在等收到 FD_WRITE 消息后再重新发送从出现异常开始的数据包即可(该包需要全部重新发送)。