Linux源码-sys_accept()

本文详细解析了Linux操作系统中accept系统调用的工作原理及其实现细节,包括sys_accept()函数如何分配新socket、调用inet_accept()进行连接确认、以及如何通过tcp_accept()处理连接队列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(本文部分参考《Linux源代码情景分析》)
操作SYS_ACCEPT接受连接请求,通过sys_accept()实现。
“有连接”模式的插口一旦通过 listen()设置成 server 插口以后,就只能被动地通过 accept()接受来自client 插口的连接请求。进程对 accept()的调用是阻塞性的,就是说如果没有连接请求就会进入睡眠等待,直到有连接请求到来,接受了请求以后(或者超过了预定的等待时间)才会返回。所以,在已经有连接请求的情况下是“接受连接请求”,而在尚无连接请求的情况下是“等待连接请求”。在内核中,accept()是通过 net/socket.c 中的函数 sys_accept()实现的。
函数整个调用过程如下:
这里写图片描述

下面是完整代码:

函数 sys_accept()代码如下:

asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen)
{
    struct socket *sock, *newsock;
    int err, len;
    char address[MAX_SOCK_ADDR];

    sock = sockfd_lookup(fd, &err);/* 获得侦听端口的socket */
    if (!sock)
        goto out;

    err = -ENFILE;
    if (!(newsock = sock_alloc()))/* 分配一个新的套接口,用来处理与客户端的连接 */ 
        goto out_put;

    /* 根据侦听套接口来初始化新连接的类型和回调表 */
    newsock->type = sock->type;
    newsock->ops = sock->ops;


...
    /* accept系统调用在套接口层的实现,对TCP来说,是inet_accept */
    err = sock->ops->accept(sock, newsock, sock->file->f_flags);
    if (err < 0)
        goto out_release;

    if (upeer_sockaddr) {/* 调用者需要获取对方套接口地址和端口 */
        /* 
*调用传输层回调获得对方的地址和端口
*这个函数既可以用来获取对方插口的地址,也可以用来获取本插口的地址,具体由参数 peer 决定。在这里由于调用时将参数的值设成 2,所以取的是对方地址。 
*/
        if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
            err = -ECONNABORTED;
            goto out_release;
        }
        /* 成功后复制到用户态 */
        err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
        if (err < 0)
            goto out_release;
    }


    if ((err = sock_map_fd(newsock)) < 0)/* 为新连接分配文件描述符并返回*/
        goto out_release;
...
}

代码中先通过 sockfd_lookup()找到 server 插口的 socket 结构,然后通过 sock_alloc()分配一个新的socket 结构,再通过相应函数指针调用具体的回调函数inet_accept()。
值得注意的是:一个插口经 listen()设置成 server 插口以后永远不会与任何插口建立起连接。因为一旦接受了一个连接请求之后就会创建出另一个插口,连接就建立在这个新的插口与请求连接的那个插口之间,而原先的 server 插口则并无改变,并且还可再次通过 accept()接受下一个连接请求,server 插口永远保持接受新的连接请求的能力,但是其本身从来不成为某个连接的一端。正因为这样, sys_accept()返回的是新插口的打开文件号,同时会把对方(cli)的插口地址从参数中带出来。

inet_accept()代码如下:

/* accept系统调用在套接口层的实现 */
int inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
    struct sock *sk1 = sock->sk;/* 根据套口获得传输层控制块 */
    int err = -EINVAL;
    /* 调用传输层的函数tcp_accept获得已经完成的连接的传输控制块,即子传输控制块 */
    struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err);

    if (!sk2)/* 失败返回 */
        goto do_err;

    lock_sock(sk2);

    BUG_TRAP((1 << sk2->sk_state) &
         (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE));

    /* 将子传输控制块与传输控制块关联起来 */
    sock_graft(sk2, newsock);

    /* 设置套接口的状态 */
    newsock->state = SS_CONNECTED;
    err = 0;
    release_sock(sk2);
do_err:
    return err;
}

tcp_accept()函数代码如下:

/* accept调用的传输层实现 */
struct sock *tcp_accept(struct sock *sk, int flags, int *err)
{
    struct tcp_sock *tp = tcp_sk(sk);
    struct open_request *req;
    struct sock *newsk;
    int error;

    lock_sock(sk);

    error = -EINVAL;
    if (sk->sk_state != TCP_LISTEN)/* 本调用仅仅针对侦听套口,不是此状态的套口则退出 */
        goto out;

    if (!tp->accept_queue) {/* accept队列为空,说明还没有收到新连接 */
        long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);/* 如果套口是非阻塞的,或者在一定时间内没有新连接,则返回 */
/*标志位 O_NONBLOCK在文件操作中常用,表示如果有报文就接收,但是若没有也得马上返回,而不是睡眠等待,这个标志位也可用于 accept()。*/

        error = -EAGAIN;
        if (!timeo)/* 超时时间到,没有新连接,退出 */
            goto out;

        /* 运行到这里,说明有新连接到来(返回值为0),则等待新的传输控制块 */
        error = wait_for_connect(sk, timeo);
        if (error)
            goto out;
    }

    req = tp->accept_queue;
    if ((tp->accept_queue = req->dl_next) == NULL)
        tp->accept_queue_tail = NULL;

    newsk = req->sk;
    sk_acceptq_removed(sk);
    tcp_openreq_fastfree(req);
    BUG_TRAP(newsk->sk_state != TCP_SYN_RECV);
    release_sock(sk);
    return newsk;

out:
    release_sock(sk);
    *err = error;
    return NULL;
}

wait_for_connect()函数代码如下;


static int wait_for_connect(struct sock *sk, long timeo)
{
    struct tcp_sock *tp = tcp_sk(sk);
    DEFINE_WAIT(wait);
    int err;

    for (;;) {
        prepare_to_wait_exclusive(sk->sk_sleep, &wait,
                      TASK_INTERRUPTIBLE);
        release_sock(sk);
        if (!tp->accept_queue)
            timeo = schedule_timeout(timeo);
        lock_sock(sk);
        err = 0;
        if (tp->accept_queue)
            break;
        err = -EINVAL;
        if (sk->sk_state != TCP_LISTEN)
            break;
        err = sock_intr_errno(timeo);
        if (signal_pending(current))
            break;
        err = -EAGAIN;
        if (!timeo)
            break;
    }
    finish_wait(sk->sk_sleep, &wait);
    return err;
}



void fastcall
prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
    unsigned long flags;
    /*参数 WQ_FLAG_EXCLUSIVE 表示如果有多个进程在睡眠等待就只唤醒其中一个*/
    wait->flags |= WQ_FLAG_EXCLUSIVE;
    spin_lock_irqsave(&q->lock, flags);
    if (list_empty(&wait->task_list))
        __add_wait_queue_tail(q, wait);

    if (is_sync_wait(wait))
        set_current_state(state);
    spin_unlock_irqrestore(&q->lock, flags);
}

当中一些重要的数据结构的创建过程如下:
这里写图片描述

注:
1、
server 插口必须有个地址,这样 client 一方才能通过地址来找到 server 插口的数据结构,所以在创建了插口以后一定要调用 bind()将其“捆绑”到一个地址上。可是,对于 client 一方的插口来说,它只能主动地去寻找某个 server 插口,别的插口是不会来寻找它的。所以实际上没有必要让 client 插口也有个地址,当然有也无妨。
2、
在 sys_accept()中已经调用了 sock_alloc(),分配了一个新的 socket 结构(也就是inode 结构)。但 sock_alloc(),它并不分配与 socket 结构配对的 sock结构,从这个意义上讲,这个新的插口还不完整。那么什么时候才分配所需的 sock 数据结构呢?这是由client 一方在 connect()的过程中分配,并且将其指针通过用作连接请求报文的 sk_buff 结构带过来的,通过 sock_graft()将 client 一方提供的 sock结构 与 server 一方提供的 newsock(socket结构) 挂上钩。
3、
简单介绍一下sock_map_fd()函数(将套接口与文件描述符绑定):
这里写图片描述

[root@VM-24-11-opencloudos nginx-1.24.0]# pcre-config --version 8.35 [root@VM-24-11-opencloudos nginx-1.24.0]# ./configure --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --add-module=/www/server/nginx/src/ngx_http_substitutions_filter_module-master --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module --add-module=/usr/local/fastdfs-nginx-module/src checking for OS + Linux 6.6.47-12.oc9.x86_64 x86_64 checking for C compiler ... found + using GNU C compiler + gcc version: 12.3.1 20230912 (OpenCloudOS 12.3.1.3-1) (Tencent Compiler 12.3.1.3) checking for gcc -pipe switch ... found checking for --with-ld-opt="-Wl,-E" ... found checking for -Wl,-E switch ... found checking for gcc builtin atomic operations ... found checking for C99 variadic macros ... found checking for gcc variadic macros ... found checking for gcc builtin 64 bit byteswap ... found checking for unistd.h ... found checking for inttypes.h ... found checking for limits.h ... found checking for sys/filio.h ... not found checking for sys/param.h ... found checking for sys/mount.h ... found checking for sys/statvfs.h ... found checking for crypt.h ... found checking for Linux specific features checking for epoll ... found checking for EPOLLRDHUP ... found checking for EPOLLEXCLUSIVE ... found checking for eventfd() ... found checking for O_PATH ... found checking for sendfile() ... found checking for sendfile64() ... found checking for sys/prctl.h ... found checking for prctl(PR_SET_DUMPABLE) ... found checking for prctl(PR_SET_KEEPCAPS) ... found checking for capabilities ... found checking for crypt_r() ... found checking for sys/vfs.h ... found checking for UDP_SEGMENT ... found checking for nobody group ... found checking for poll() ... found checking for /dev/poll ... not found checking for kqueue ... not found checking for crypt() ... not found checking for crypt() in libcrypt ... found checking for F_READAHEAD ... not found checking for posix_fadvise() ... found checking for O_DIRECT ... found checking for F_NOCACHE ... not found checking for directio() ... not found checking for statfs() ... found checking for statvfs() ... found checking for dlopen() ... found checking for sched_yield() ... found checking for sched_setaffinity() ... found checking for SO_SETFIB ... not found checking for SO_REUSEPORT ... found checking for SO_ACCEPTFILTER ... not found checking for SO_BINDANY ... not found checking for IP_TRANSPARENT ... found checking for IP_BINDANY ... not found checking for IP_BIND_ADDRESS_NO_PORT ... found checking for IP_RECVDSTADDR ... not found checking for IP_SENDSRCADDR ... not found checking for IP_PKTINFO ... found checking for IPV6_RECVPKTINFO ... found checking for TCP_DEFER_ACCEPT ... found checking for TCP_KEEPIDLE ... found checking for TCP_FASTOPEN ... found checking for TCP_INFO ... found checking for accept4() ... found checking for int size ... 4 bytes checking for long size ... 8 bytes checking for long long size ... 8 bytes checking for void * size ... 8 bytes checking for uint32_t ... found checking for uint64_t ... found checking for sig_atomic_t ... found checking for sig_atomic_t size ... 4 bytes checking for socklen_t ... found checking for in_addr_t ... found checking for in_port_t ... found checking for rlim_t ... found checking for uintptr_t ... uintptr_t found checking for system byte ordering ... little endian checking for size_t size ... 8 bytes checking for off_t size ... 8 bytes checking for time_t size ... 8 bytes checking for AF_INET6 ... found checking for setproctitle() ... not found checking for pread() ... found checking for pwrite() ... found checking for pwritev() ... found checking for strerrordesc_np() ... found checking for localtime_r() ... found checking for clock_gettime(CLOCK_MONOTONIC) ... found checking for posix_memalign() ... found checking for memalign() ... found checking for mmap(MAP_ANON|MAP_SHARED) ... found checking for mmap("/dev/zero", MAP_SHARED) ... found checking for System V shared memory ... found checking for POSIX semaphores ... found checking for struct msghdr.msg_control ... found checking for ioctl(FIONBIO) ... found checking for ioctl(FIONREAD) ... found checking for struct tm.tm_gmtoff ... found checking for struct dirent.d_namlen ... not found checking for struct dirent.d_type ... found checking for sysconf(_SC_NPROCESSORS_ONLN) ... found checking for sysconf(_SC_LEVEL1_DCACHE_LINESIZE) ... found checking for openat(), fstatat() ... found checking for getaddrinfo() ... found configuring additional modules adding module in /www/server/nginx/src/ngx_devel_kit + ngx_devel_kit was configured adding module in /www/server/nginx/src/lua_nginx_module checking for LuaJIT library in /usr/local/lib and /usr/local/include/luajit-2.1 (specified by the LUAJIT_LIB and LUAJIT_INC env, with -ldl) ... found checking for LuaJIT 2.x ... found checking for Lua language 5.1 ... found checking for LuaJIT has FFI ... found checking for export symbols by default (-E) ... found checking for export symbols by default (--export-all-symbols) ... not found checking for SO_PASSCRED ... found checking for SA_RESTART ... found checking for malloc_trim ... found checking for pipe2 ... found checking for signalfd ... found checking for execvpe ... found + ngx_http_lua_module was configured adding module in /www/server/nginx/src/ngx_cache_purge + ngx_http_cache_purge_module was configured adding module in /www/server/nginx/src/ngx_http_substitutions_filter_module-master + ngx_http_subs_filter_module was configured adding module in /www/server/nginx/src/nginx-dav-ext-module + ngx_http_dav_ext_module was configured adding module in /usr/local/fastdfs-nginx-module/src + ngx_http_fastdfs_module was configured checking for zlib library ... found checking for libxslt ... found checking for libexslt ... found checking for GD library ... found checking for GD WebP support ... found creating objs/Makefile Configuration summary + using PCRE library: pcre-8.43 + using OpenSSL library: /www/server/nginx/src/openssl + using system zlib library nginx path prefix: "/www/server/nginx" nginx binary file: "/www/server/nginx/sbin/nginx" nginx modules path: "/www/server/nginx/modules" nginx configuration prefix: "/www/server/nginx/conf" nginx configuration file: "/www/server/nginx/conf/nginx.conf" nginx pid file: "/www/server/nginx/logs/nginx.pid" nginx error log file: "/www/server/nginx/logs/error.log" nginx http access log file: "/www/server/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp" ./configure: warning: the "--with-ipv6" option is deprecated [root@VM-24-11-opencloudos nginx-1.24.0]# make make -f objs/Makefile make[1]: Entering directory '/www/server/nginx/src/nginx-1.24.0' cd pcre-8.43 \ && if [ -f Makefile ]; then make distclean; fi \ && CC="cc" CFLAGS="-O2 -fomit-frame-pointer -pipe " \ ./configure --disable-shared /bin/sh: line 1: cd: pcre-8.43: No such file or directory make[1]: *** [objs/Makefile:2256: pcre-8.43/Makefile] Error 1 make[1]: Leaving directory '/www/server/nginx/src/nginx-1.24.0' make: *** [Makefile:10: build] Error 2
最新发布
06-19
<think>我们面对的问题是在执行`make`命令时出现错误:```cdpcre-8.43\&&if[-fMakefile];thenmakedistclean;fi\&&CC="cc"CFLAGS="-O2-fomit-frame-pointer-pipe"\./configure--disable-shared/bin/sh:line1:cd:pcre-8.43:Nosuchfileordirectory```错误信息表明在进入`pcre-8.43`目录时失败,因为该目录不存在。回顾用户提供的配置命令:```./configure--prefix=/www/server/nginx--add-module=/www/server/nginx/src/ngx_devel_kit--add-module=/www/server/nginx/src/lua_nginx_module--add-module=/www/server/nginx/src/ngx_cache_purge--with-openssl=/www/server/nginx/src/openssl--with-pcre=pcre-8.43--with-http_v2_module--with-stream--with-stream_ssl_module--with-stream_ssl_preread_module--with-http_stub_status_module--with-http_ssl_module--with-http_image_filter_module--with-http_gzip_static_module--with-http_gunzip_module--with-ipv6--with-http_sub_module--with-http_flv_module--with-http_addition_module--with-http_realip_module--with-http_mp4_module--add-module=/www/server/nginx/src/ngx_http_substitutions_filter_module-master--with-ld-opt=-Wl,-E--with-cc-opt=-Wno-error--with-http_dav_module--add-module=/www/server/nginx/src/nginx-dav-ext-module--add-module=/usr/local/fastdfs-nginx-module/src```特别注意`--with-pcre=pcre-8.43`选项。这个选项告诉Nginx的configure脚本,PCRE库的源代码位于当前目录下的`pcre-8.43`目录中。但是,错误信息表明在Nginx源代码目录下并没有这个目录。根据引用[1]和引用[2]的内容,我们需要确保PCRE库已经正确安装,并且在配置Nginx时指定正确的PCRE源码路径。###解决方案:####步骤1:确认PCRE源码包的存在首先,我们需要确认PCRE的源码包是否已经下载并解压到指定的位置。根据用户之前的操作,他可能将PCRE-8.43的源码包放在了`/usr/local/src`目录下。我们可以检查一下:```bashls/usr/local/src/pcre-8.43```如果该目录存在,那么我们需要在配置Nginx时指定完整的路径,而不是相对路径。####步骤2:重新配置Nginx在配置Nginx时,将`--with-pcre`参数的值改为PCRE源码的绝对路径。例如,如果PCRE源码在`/usr/local/src/pcre-8.43`,则配置命令应改为:```bash./configure...--with-pcre=/usr/local/src/pcre-8.43...```注意:其他配置选项保持不变,只需修改`--with-pcre`的值为绝对路径。####步骤3:重新编译重新运行`make`命令。```bashmake```如果之前已经执行过`make`并且失败了,建议先执行`makeclean`来清理之前的编译文件。###详细步骤:1.**确认PCRE源码目录**:如果PCRE源码不在`/usr/local/src/pcre-8.43`,那么需要下载并解压。根据引用[1]中的步骤:```bashcd/usr/local/srcwgethttps://sourceforge.net/projects/pcre/files/pcre/8.43/pcre-8.43.tar.gztar-zxvfpcre-8.43.tar.gz```2.**重新配置Nginx**:进入Nginx源码目录(`/www/server/nginx/src/nginx-1.24.0`),重新运行配置命令,并将`--with-pcre`参数指向绝对路径`/usr/local/src/pcre-8.43`:```bashcd/www/server/nginx/src/nginx-1.24.0./configure--prefix=/www/server/nginx\--add-module=/www/server/nginx/src/ngx_devel_kit\--add-module=/www/server/nginx/src/lua_nginx_module\--add-module=/www/server/nginx/src/ngx_cache_purge\--with-openssl=/www/server/nginx/src/openssl\--with-pcre=/usr/local/src/pcre-8.43\#修改为绝对路径...[其他参数保持不变]...```3.**编译并安装**:```bashmakemakeinstall```###注意事项:-确保PCRE的版本正确,这里是8.43。-如果之前配置过,最好先执行`makeclean`,然后再重新配置和编译。-在配置PCRE时,建议启用UTF-8支持(如引用[1]中提到的`./configure--enable-utf8`),但这一步在Nginx配置中不需要,因为Nginx会使用PCRE的源码进行编译,所以我们应该在PCRE的源码目录中先配置并编译安装PCRE吗?实际上,在Nginx配置中指定PCRE源码路径时,Nginx会在编译过程中自动编译PCRE,因此不需要单独安装PCRE。但是,如果我们已经单独安装了PCRE,也可以使用`--with-pcre`指向已安装的库(但注意,这里要求指向源码目录,而不是安装目录)。###引用说明:根据引用[1],用户提到安装PCRE-8.43时,需要先下载并解压,然后进行配置(包括`--enable-utf8`选项)和编译安装。但根据Nginx的配置要求,我们只需要提供PCRE的源码目录,Nginx会在编译过程中编译PCRE。因此,我们不需要预先编译安装PCRE,只需要提供源码目录即可。###相关问题:1.如何为Nginx添加第三方模块?2.在编译Nginx时如何解决OpenSSL路径问题?3.如何启用Nginx的HTTP/2支持?4.如何配置Nginx的Lua模块?5.如何解决Nginx编译过程中的zlib依赖问题?</think>### 解决 Nginx 编译时 PCRE 目录缺失错误 #### 🔍 问题分析 编译错误 `cd: pcre-8.43: No such file or directory` 表明: 1. `--with-pcre=pcre-8.43` 参数指定了相对路径,但实际文件不存在 2. PCRE 库未正确解压到 Nginx 源码目录 3. 路径权限问题导致无法访问(需检查 `/usr/local/src` 权限) #### ✅ 解决方案(逐步操作) ##### 步骤 1:验证并准备 PCRE 源码 ```bash # 检查源码位置(根据引用[1]应在 /usr/local/src) ls -l /usr/local/src/pcre-8.43* # 若不存在则重新下载解压(引用[1]方法) cd /usr/local/src sudo wget https://sourceforge.net/projects/pcre/files/pcre/8.43/pcre-8.43.tar.gz sudo tar -zxvf pcre-8.43.tar.gz sudo chmod -R 755 pcre-8.43 # 确保权限(引用[1]) ``` ##### 步骤 2:修正 Nginx 配置路径 ```bash cd /www/server/nginx/src/nginx-1.24.0 # 修改 --with-pcre 为绝对路径(关键!) ./configure \ --prefix=/www/server/nginx \ --with-pcre=/usr/local/src/pcre-8.43 \ # 修改这里 --with-openssl=/www/server/nginx/src/openssl \ ...其他参数保持原样... ``` ##### 步骤 3:重新编译安装 ```bash # 清理旧编译文件 make clean # 重新编译(引用[3]依赖检查) make -j$(nproc) # 安装 sudo make install ``` ##### 步骤 4:验证安装 ```bash sudo /www/server/nginx/sbin/nginx -t # 成功应显示: configuration file test is successful ``` #### ⚠️ 关键注意事项 1. **路径必须为绝对路径** `--with-pcre` 必须指向 **PCRE 源码目录** 而非压缩包或安装目录(引用[1][2]) 2. **UTF-8 支持** 配置 PCRE 时需启用 UTF-8(引用[1]): ```bash cd /usr/local/src/pcre-8.43 ./configure --enable-utf8 # 必须选项 ``` 3. **依赖完整性检查** 确保安装编译依赖(引用[3][4]): ```bash sudo yum -y install make zlib-devel gcc-c++ openssl-devel ``` #### 🔧 故障排查流程图 ```mermaid graph TD A[编译错误] --> B{错误类型} B --> |目录不存在| C[检查 --with-pcre 路径] B --> |权限问题| D[chmod -R 755 pcre-8.43] C --> E[使用绝对路径 /usr/local/src/pcre-8.43] D --> F[确认 /usr/local/src 可访问] E --> G[重新configure] F --> G G --> H[make clean && make] ``` #### 📚 相关问题 1. 如何为 Nginx 添加 Brotli 压缩支持? 2. PCRE JIT 编译对 Nginx 性能有何影响?[^1] 3. 如何在 OpenCloudOS 上配置 Nginx 系统服务? 4. 如何解决 `fatal error: pcre.h` 头文件缺失问题?[^2] 5. Nginx 动态模块加载 vs 静态编译有何区别? > 引用说明:PCRE 路径必须使用绝对路径[^1],UTF-8 支持是必须选项[^1],依赖完整性检查可避免后续错误[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值