[TCP][二] lwip_socket(a,b,c)

不深挖旁枝末节,以主脉络为主。先记个流水账,旁枝末节的东西用到的时候再挖!


目录

 

函数原型

socket fd <—> socket <—> netconn <—> tcp_pcb

netconn

tcp_pcb

总结



 

函数原型

int lwip_socket(int domain, int type, int protocol)

点1:

返回值,是系统全局数组 sockets (如下)的某个 index(0 <= index < NUM_SOCKETS),即从 0 开始到 NUM_SOCKETS,若 sockets[index] 还未被使用,就将 index 返回。NUM_SOCKETS 的大小可在配置文件中修改。

static struct lwip_sock sockets[NUM_SOCKETS];

点2:

对于TCP, 参数 type = SOCK_STREAM。其他两个参数似乎没什么luan用。

 

socket fd <—> socket <—> netconn <—> tcp_pcb

(标题:我有点长...)

在应用层调用 lwip_socket() 后,先申请一个 netconn,再申请一个 tcp_pcb,然后在全局的 sockets[] 中找到一个未用的 socket,先将三者绑定在一起,然后返回 socket fd,范围 [ 0,NUM_SOCKETS )。

socket fd 是应用层可以直观看见并操作 socket 的标识,但在 Lwip 内部,对应于 socket fd 有几个外部不能直接访问的重要结构 socket、netconn、tcp_pcb。

看图吧:

每次操作 socket 时,将 socket fd 传入 API, API 内部就会将其作为 index,从全局的 sockets[] 中找到对应的 socket = sockets[index],进而找到对应的 tcp_pcb。

 

netconn

一个 socket 对应一个 netconn 结构,用于管理当前 socket 所对应的网络连接。

在应用层调用 lwip_socket() 后,内部通过  (struct netconn *)memp_malloc(MEMP_NETCONN) 申请一个 struct netconn 的结构,关于 Lwip memp 我想再用一篇内容分析这个装X的东西,暂且不说。

netconn 申请后,进行一些初始化动作:网络连接类型 NETCONN_TCP、申请 recvmbox(其实就是申请一个固定大小的队列 xQueueCreate(), mbox 大小可配)等。

再然后要申请一个 tcp_pcb。

 

tcp_pcb

一个 netconn 对应一个 pcb (protocol control block),对于 TCP,就是 tcp_pcb。系统中 tcp_pcb 的个数也是有限的,当第一次申请失败后,会将处于 TIME_WAIT 态时间最长的那个干掉,然后再次尝试申请;如果第二次申请失败后,会将 active 的 && 优先级比当前申请的 pcb 优先级低 && 优先级最低 && 最长时间 inactive 的那个干掉;如果还是申请失败,那就失败吧。

申请成功后,初始化,其中重要的一些:

pcb->snd_buf = TCP_SND_BUF; // 可供发送 data 的空闲空间(字节数)

pcb->rcv_ann_wnd = TCP_WND; // 向对端宣告的 rx window 大小(字节数)

pcb->snd_nxt = iss; // 初始 SN:6510 + tcp_ticks(tcp_ticks 每 500ms 递增1)

pcb->state 就是 [TCP][一] 中所讲的 State-machine 啦! 初始化后默认为 CLOSED。

enum tcp_state {
    CLOSED            = 0,
    LISTEN              = 1,
    SYN_SENT        = 2,
    SYN_RCVD        = 3,
    ESTABLISHED   = 4,
    FIN_WAIT_1       = 5,
    FIN_WAIT_2       = 6,
    CLOSE_WAIT     = 7,
    CLOSING            = 8,
    LAST_ACK          = 9,
    TIME_WAIT         = 10
};

初始化完成后,注册回调函数:

tcp_recv(pcb, recv_tcp); // rx
tcp_sent(pcb, sent_tcp); // tx
tcp_poll(pcb, poll_tcp, 4); // 周期函数,每 2s 调一次
tcp_err(pcb, err_tcp); // 出错后的回调

做完这些,创建一个 TCP socket 内部的工作基本就做完了哦。

 

总结

不想写总结。

int socket_fd = lwip_socket(int xxx, SOCK_STREAM, int yyy);

按上面傻瓜式调用,请把 socket_fd 带走不谢。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值