本文来自小白debug的原创分享,原题“【修正版】动图图解!代码执行send成功后,数据就发出去了吗?”,即时通讯网有修订和排版优化。
cover-opti.png (23.43 KB, 下载次数: 96)
下载附件 保存到相册
1 个月前 上传
1.png (16.48 KB, 下载次数: 72)
2.png (19.85 KB, 下载次数: 72)
# netstat -nt Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 60 172.22.66.69:22 122.14.220.252:59889 ESTABLISHED
int main(int argc, char *argv[]) { // 创建socket sockfd=socket(AF_INET,SOCK_STREAM, 0)) // 建立连接 connect(sockfd, 服务器ip信息, sizeof(server)) // 执行 send 发送消息 send(sockfd,str,sizeof(str),0)) // 关闭 socket close(sockfd); return 0; }
3.png (25.4 KB, 下载次数: 87)
// net/ipv4/tcp.c // 以下省略了大量逻辑 int tcp_sendmsg() { // 如果还有可以放数据的空间 if (skb_availroom(skb) > 0) { // 尝试拷贝待发送数据到发送缓冲区 err = skb_add_data_nocache(sk, skb, from, copy); } // 下面是尝试发送的逻辑代码,先省略 }
int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
4.gif (287.45 KB, 下载次数: 84)
5.gif (193.34 KB, 下载次数: 76)
int tcp_sendmsg() { if (skb_availroom(skb) > 0) { // ..如果有足够缓冲区就执行balabla } else { // 如果发送缓冲区没空间了,那就等到有空间,至于等的方式,分阻塞和非阻塞 if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; } }
int sk_stream_wait_memory(struct sock *sk, long *timeo_p) { while (1) { // 非阻塞模式时,会等到超时返回 EAGAIN if (等待超时)) return -EAGAIN; // 阻塞等待时,会等到发送缓冲区有足够的空间了,才跳出 if (sk_stream_memory_free(sk) && !vm_wait) break; } return err; }
6.gif (196.49 KB, 下载次数: 87)
7.gif (147.89 KB, 下载次数: 97)
8.png (41.57 KB, 下载次数: 92)
9.png (26.06 KB, 下载次数: 76)
void tcp_close(struct sock *sk, long timeout) { // 如果接收缓冲区有数据,那么清空数据 while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - tcp_hdr(skb)->fin; data_was_unread += len; __kfree_skb(skb); } if (data_was_unread) { // 如果接收缓冲区的数据被清空了,发 RST tcp_send_active_reset(sk, sk->sk_allocation); } else if (tcp_close_state(sk)) { // 正常四次挥手, 发 FIN tcp_send_fin(sk); } // 等待关闭 sk_stream_wait_close(sk, timeout); }
10.gif (328.68 KB, 下载次数: 92)
void tcp_send_fin(struct sock *sk) { // 获得发送缓冲区的最后一块数据 struct sk_buff *skb, *tskb = tcp_write_queue_tail(sk); struct tcp_sock *tp = tcp_sk(sk); // 如果发送缓冲区还有数据 if (tskb && (tcp_send_head(sk) || sk_under_memory_pressure(sk))) { TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN; // 把最后一块数据值为 FIN TCP_SKB_CB(tskb)->end_seq++; tp->write_seq++; } else { // 发送缓冲区没有数据,就造一个FIN包 } // 发送数据 __tcp_push_pending_frames(sk, tcp_current_mss(sk), TCP_NAGLE_OFF); }
11.gif (282.32 KB, 下载次数: 88)
"每个UDP socket都有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。"
ssize_t send(int sock, const void *buf, size_t len, int flags); // flag 置为 MSG_MORE
int udp_sendmsg() { // corkreq 为 true 表示是 MSG_MORE 的方式,仅仅组织报文,不发送; int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; // 将要发送的数据,按照MTU大小分割,每个片段一个skb;并且这些 // skb会放入到套接字的发送缓冲区中;该函数只是组织数据包,并不执行发送动作。 err = ip_append_data(sk, fl4, getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), &ipc, &rt, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); // 没有启用 MSG_MORE 特性,那么直接将发送队列中的数据发送给IP。 if (!corkreq) err = udp_push_pending_frames(sk); }
来源:即时通讯网 - 即时通讯开发者社区!
轻量级开源移动端即时通讯框架。
快速入门 / 性能 / 指南 / 提问
轻量级Web端即时通讯框架。
详细介绍 / 精编源码 / 手册教程
移动端实时音视频框架。
详细介绍 / 性能测试 / 安装体验
基于MobileIMSDK的移动IM系统。
详细介绍 / 产品截图 / 安装体验
一套产品级Web端IM系统。
详细介绍 / 产品截图 / 演示视频
一套纯血鸿蒙NEXT产品级IM系统。
详细介绍 / 产品截图 / 安装
精华主题数超过100个。
连续任职达2年以上的合格正式版主
为论区做出突出贡献的开发者、版主等。
Copyright © 2014-2025 即时通讯网 - 即时通讯开发者社区 / 版本 V4.4
苏州网际时代信息科技有限公司 (苏ICP备16005070号-1)
Processed in 0.273448 second(s), 41 queries , Gzip On.