Skynet:套接字线程工作原理

本文深入解析Skynet框架中套接字线程的工作原理,主要关注`skynet_socket_poll`和`socket_server_poll`函数。`socket_server_poll`函数先检查读管道事件,然后使用select和epoll监听套接字事件。根据不同套接字状态(如SOCKET_TYPE_CONNECTING、SOCKET_TYPE_LISTEN、SOCKET_TYPE_INVALID等)进行相应处理,包括连接建立、客户端连接、错误处理和数据读写操作。
摘要由CSDN通过智能技术生成

涉及的到的相应结构体以及预定义注释为:

//用于标记socket结构体的状态
#define SOCKET_TYPE_INVALID 0                //socket结构体未被使用
#define SOCKET_TYPE_RESERVE 1                //socket结构体已被分配,但是还没有实际进行网络连接
#define SOCKET_TYPE_PLISTEN 2                //已经绑定套接字监听端口号,但是没有添加到epoll监听事件,调用start_socket函数才会,变为SOCKET_TYPE_LISTEN状态
#define SOCKET_TYPE_LISTEN 3                //已经绑定套接字监听端口号, 并且已经添加到epoll监听事件
#define SOCKET_TYPE_CONNECTING 4            //套接字正在连接中, 但是还没有连接上, 此时还不能传送信息
#define SOCKET_TYPE_CONNECTED 5                //套接字连接成功, 可以发送信息
#define SOCKET_TYPE_HALFCLOSE 6                //半关闭状态, 虽然套接字本身没有关闭, 但是已经不能往里边添加信息了, 最终会在清空写缓冲的情况下关闭
#define SOCKET_TYPE_PACCEPT 7                //已经接受了客户端的连接, 但是没有添加到epoll监听事件, 当调用 start_socket 才变成 CONNECTED
#define SOCKET_TYPE_BIND 8                    //绑定外部创建的套接字,监听可读事件

//处理管道信息和epoll监听事件的返回结果,即socket_server_poll返回值
#define SOCKET_DATA 0            //套接字已接收TCP数据
#define SOCKET_CLOSE 1            //套接字已被关闭
#define SOCKET_OPEN 2            //说明套接字已经可以进行正常的通信,例如绑定套接字成功,请求连接成功
#define SOCKET_ACCEPT 3            //客户端请求连接事件处理,表明连接成功
#define SOCKET_ERR 4            //出错返回
#define SOCKET_EXIT 5            //整个套接字服务退出
#define SOCKET_UDP 6            //套接字已接收UDP数据
#define SOCKET_WARNING 7        //写缓存超出阈值

//skynet_socket_message中type套接字消息的类型
#define SKYNET_SOCKET_TYPE_DATA 1        //接收到的TCP数据
#define SKYNET_SOCKET_TYPE_CONNECT 2    //套接字已经可以进行正常的通信,例如绑定套接字成功,请求连接成功
#define SKYNET_SOCKET_TYPE_CLOSE 3        //套接字已被关闭
#define SKYNET_SOCKET_TYPE_ACCEPT 4        //客户端请求连接事件处理,表明连接成功
#define SKYNET_SOCKET_TYPE_ERROR 5        //出错返回
#define SKYNET_SOCKET_TYPE_UDP 6        //接收到UDP数据
#define SKYNET_SOCKET_TYPE_WARNING 7    //写缓存超出阈值

struct skynet_socket_message {
       //发送到 skynet 各个服务去的套接字消息
    int type;        //套接字消息的类型,取上面的预定义值
    int id;            //定位存储套接字信息的id
    int ud;            //套接字消息的数据的大小
    char * buffer;    //套接字消息的数据
};

//全局的信息
struct socket_server {
   
    int recvctrl_fd;                    //读管道fd
    int sendctrl_fd;                    //写管道fd
    int checkctrl;                        //默认值为1,是否需要检查管道中的命令的标记
    poll_fd event_fd;                    //epoll句柄
    int alloc_id;                        //当前分配到的socket ID
    int event_n;                        //epoll触发的事件数量
    int event_index;                    //当前已经处理的epoll事件的数量
    struct socket_object_interface soi;    //初始化发送对象时用
    struct event ev[MAX_EVENT];            //事件的相关数据
    struct socket slot[MAX_SOCKET];        //所有套接字相关的信息
    char buffer[MAX_INFO];                //open_socket发起TCP连接时,用于保存套接字的对端IP地址,如果是客户端套接字保存客户端的ip地址和端口号
    uint8_t udpbuffer[MAX_UDP_PACKAGE];    //接收UDP数据
    fd_set rfds;                        //select的读描述符集合
};

//每个套接字相关的信息
struct socket {
                               //套接字相关信息结构体
    uintptr_t opaque;                    //一般用于存储定位服务的handle
    struct wb_list high;                //高优先级的写缓存
    struct wb_list low;                    //低优先级的写缓存
    int64_t wb_size;                    //套接字写入缓存的大小,会随着缓存的大小变化,为高优先级和低优先级的和
    int fd;                                //套接字描述符
    int id;                                //用于在socket_server结构体中定位存储套接字信息
    uint8_t protocol;                    //协议类型
    uint8_t type;                        //socket结构体所处的状态,绑定套接字时,即套接字的状态
    uint16_t udpconnecting;                //大于0标记该套接字正在进行关联ip地址操作,用于UDP协议
    int64_t warn_size;                    //阈值,写缓存超过的阈值,每超过一次阈值就会翻倍
    union {
   
        int size;                        //在 TCP 协议下使用, 表示一次性最多读取的字节数
        uint8_t udp_address[UDP_ADDRESS_SIZE];    //udp_address[0]存协议类型,udp_address[1],udp_address[]存端口号,剩余部分存ip地址
    } p;
    struct spinlock dw_lock;            //写缓存锁
    int dw_offset;                        //已经发送的数据偏移位置
    const void * dw_buffer;                //已发送一部分的全部数据缓存
    size_t dw_size;                        //已发送一部分的全部数据的大小
};

struct wb_list {
                   //写缓存队列
    struct write_buffer * head;    //队列头
    struct write_buffer * tail;    //尾队列
};

//socket 写入的缓存数据, 如果是 TCP 协议将不包含 udp_address 字段, 而仅仅是前面部分
struct write_buffer {
   
    struct write_buffer * next;                
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值