socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
内核创建基本过程:
- 通过系统调用,陷入内核;
- 调用sock_create函数,创建socket结构体类型的实例sock,并设置sock的属性。如根据AF_INET可知,需要创建的是IPV4,调用其相应的创建函数;同样,根据type来创建是面向数据包还是流式的等等;
而sock实例负责与内核协议栈进行对接。
- 将初始化好的sock与文件描述符关联起来。从task_srruct中拿到一个未使用的fd, 创建一个新的file
file->f_op = &socket_file_ops file->private_data = sock sock->file = file
; - 将该fd返回回去。
bind
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
- socket 需要绑定地址的监听socket的文件描述符
- addr 服务端绑定的地址 IP + PORT
- addrlen 传入addr数据的长度。实际上,传入的可能是IPV4,IPV6或者本地套接字格式。bind会根据传入的不同的addrlen值,就知道是哪种类型的地址,然后去解析addr.
执行的基本流程:
- 根据fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
- 将sockaddr类型的实例拷贝到内核态;
- 调用
sock->ops->bind()
方法,从sock->sk取得sk,调用sk->sk_port->get_port()检查端口是否冲突,是否可以绑定。如果可以绑定,则初始化本地地址和端口。
listen
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
- socket 表示需要监听的socket的文件描述符
- 表示已完成ESTABLISHED且未aceept的队列大小,这个参数的大小决定了可以接收的并发数目。(该参数一般不使用)
内核调用的基本过程:
- 根据fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
- 调用
sock->ops->listen()
,从socket中拿到sock实例sk; - 设置
sk->sk_max_ack_backlog = backlog;
- 创建一个存放已连接的队列,icsk_accept_queue(三次握手后的连接);
- 最后设置sk的状态,sk_state_store(sk,TCP_LISTEN)
connect
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
- socket 表示客户端这边连接服务器时自己使用的socket,在connet前调用socket()进行创建
- addr 表示服务端监听的套接字绑定着的 IP +PORT
- addrlen addr的长度
内核调用的基本过程:
- 根据fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
- 调用sock->ops->onnect(),从socket中拿到sock实例sk;
- 拿到sk是为了进行内核协议栈的操作,这里是调用sk->sk_port->connect;
- 握手报文处理,将数据发送到网卡
accept
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr,
socklen_t *addrlen, int flags);
内核处理的基本流程:
- 根据传入参数fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
- 调用sock->ops->accept
- 从socket中拿到sock实例sk
- sk->sk_port->accept
- 于此同时,不断ongoing已经完成三次握手队列中取出连接,如果队列为空,贼放弃cpu。否则进行下一步;
- 创建新的socket实例new_sock,设置
new_sock->sk=sk2;new_sock->ops=sock->ops
- 创建一个新的file实例new_file,设置
new_file->private_data=new_sock,new_sock->file = new_file
进行关联; - 然后从task_struct中找到新的fd,与new_file进行关联。
原文地址:https://www.jb51.cc/wenti/3280789.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。