c/c++后台开发学习笔记POSIX API与网络协议栈

网络编程常用接口

int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags,
                        struct sockaddr *restrict src_addr,
                        socklen_t *restrict addrlen);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
                      
int close(int fd);

socket: 创建socket
bind:将socket与ip/port绑定。服务端必须绑定,客户端可不绑定,如果不绑定内核会随机分配一个端口
listen:服务端socket进入LISTEN状态,并指定三次握手队列大小。对于tcp,内核内部有两个队列:半连接队列和全连接队列。backlog在linux下指定全连接队列最大长度,在其他unix下指定半连接+全连接队列的长度。
connect: 用于客户端连接服务端,发送SYN
recv/send用于tcp收发数据
recvfrom/sendto用于udp收发数据
close:释放fd,发送fin,此时连接(tcp control block)仍然存在,进入FIN_WAIT_1状态。当收到ack与fin时进入TIME_WAIT

tcp状态图

在这里插入图片描述

三次握手

connect触发三次握手
1:客户端(内核协议栈)发送SYN+init_seqnum(1000),进入SYN_SENT
2:服务端(内核协议栈)接受到SYN,返回ACK(1001)以及SYN+服务端的init_seqnum(2000),进入SYN_RCVD
3:客户端(内核协议栈)接受到2,发送ACK(2001),进入ESTABLISHED
4:服务端接收到ACK后进入ESTABLISHED
之后两边对称

非阻塞connect

connect是否等待取决于fd是否为阻塞,如果设为非阻塞则不会等待,可以使用epoll监听EPOLLOUT事件
使用fcntl把fd设成非阻塞

int res = connect(fd, ...);
if (res < 0 && errno != EINPROGRESS) {
    // error, fail somehow, close socket
    return;
}

if (res == 0) {
    // connection has succeeded immediately
} else {
    // connection attempt is in progress
    // 使用epoll等待EPOLLOUT
}

内核如何区分连接

通过(src_ip, src_port, dst_ip, dst_port, protocol) 五元组

流量控制

ack中会有一个window size,告诉发送方接受方的buffer还有多少byte可以写

有序性

使用seq num

tcp的缺点

  1. 延迟ack:只有在一段时间没收到新的包时才会发送ack,这样可以接受多个包只返回一个ack
    不利于及时性(不过可以关闭)
  2. 发送方会重发ack num之后所有的包(可能会重复发送一些对方已经接收到的数据,有一些浪费)
    以上两种场景可以使用udp

四次挥手

  1. A发送fin,进入fin_wait_1
  2. B接受到fin,发送ack,进入close_wait
  3. A接受到ack,进入fin_wait_2 (等待B发送fin)
  4. B发送fin,进入last_ack
  5. A接受到fin,发送ack,进入time_wait
  6. B接受到ack,关闭连接
  7. 2MSL之后A关闭连接
    在这里插入图片描述
    为什么有time_wait?
    避免最后一次ack的丢失(不然另一方可能一直处在last_ack)

tcp设置不活跃自动断线的两种方法

  1. 用tcp自带的keepalive(https://stackoverflow.com/questions/17740492/how-i-will-use-setsockopt-and-getsockopt-with-keep-alive-in-linux-c-programming)不推荐
  2. 业务层心跳机制(推荐)

参考资料

[1] 零声教育c/c++后台开发2.2.3
[2] stackoverflow

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值