linux网络编程之socket,bind,listen,connect,accept

socket

       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int socket(int domain, int type, int protocol);
  • domain:协议族,如AF_INET,AF_INET6等
  • type:套接字类型,如SOCK_STREAM,SOCK_DGRAM 等
  • protocol:协议,一般认为0

内核创建基本过程:

  1. 通过系统调用,陷入内核;
  2. 调用sock_create函数,创建socket结构体类型的实例sock,并设置sock的属性。如根据AF_INET可知,需要创建的是IPV4,调用其相应的创建函数;同样,根据type来创建是面向数据包还是流式的等等;

    在这里插入图片描述

socket fd是对用户提供接口,与文件描述符关联

而sock实例负责与内核协议栈进行对接。

  1. 将初始化好的sock与文件描述符关联起来。从task_srruct中拿到一个未使用的fd, 创建一个新的filefile->f_op = &socket_file_ops file->private_data = sock sock->file = file;
  2. 将该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.

执行的基本流程:

  1. 根据fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
  2. 将sockaddr类型的实例拷贝到内核态;
  3. 调用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的队列大小,这个参数的大小决定了可以接收的并发数目。(该参数一般不使用)

    在这里插入图片描述

内核调用的基本过程:

  1. 根据fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
  2. 调用sock->ops->listen(),从socket中拿到sock实例sk;
  3. 设置sk->sk_max_ack_backlog = backlog;
  4. 创建一个存放已连接的队列,icsk_accept_queue(三次握手后的连接);
  5. 最后设置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的长度

内核调用的基本过程:

  1. 根据fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
  2. 调用sock->ops->onnect(),从socket中拿到sock实例sk;
  3. 拿到sk是为了进行内核协议栈的操作,这里是调用sk->sk_port->connect;
  4. 握手报文处理,将数据发送到网卡

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);

内核处理的基本流程:

  1. 根据传入参数fd文件描述符找到file实例,从file实例的private_data中拿到sock实例;
  2. 调用sock->ops->accept
  3. 从socket中拿到sock实例sk
  4. sk->sk_port->accept
  5. 于此同时,不断ongoing已经完成三次握手队列中取出连接,如果队列为空,贼放弃cpu。否则进行下一步;
  6. 创建新的socket实例new_sock,设置 new_sock->sk=sk2;new_sock->ops=sock->ops
  7. 创建一个新的file实例new_file,设置new_file->private_data=new_sock,new_sock->file = new_file 进行关联;
  8. 然后从task_struct中找到新的fd,与new_file进行关联。

在这里插入图片描述

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...
win11本地账户怎么改名?win11很多操作都变了样,用户如果想要...