Nginx学习笔记(四) 源码分析&socket/UDP/shmem

简介:

 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem)。那就来看看这个文件吧!从简单的开始~~~

src/os/unix/Ngx_socket.h&Ngx_socket.c

  源码如下(可用Source Insight来看源码,不错的选择):

  View Code

 

  其中,创建socket的相关函数如下:

typedef int  ngx_socket_t;//这个应该是套接口的描述符了

#define ngx_socket          socket           //只是替换了名称,仍然是socket,没什么可怕的
#define ngx_socket_n        "socket()"

  接下来:

复制代码
#if (NGX_HAVE_FIONBIO)  //FIONBIO:设置/ 清除非阻塞I/O 标志式
//使用ioctl来设置
int ngx_nonblocking(ngx_socket_t s);
int ngx_blocking(ngx_socket_t s);

#define ngx_nonblocking_n   "ioctl(FIONBIO)"
#define ngx_blocking_n      "ioctl(!FIONBIO)"

#else

//使用fcntl(点击查看详情)设定非阻塞状态 #define ngx_nonblocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK)//fcntl(s,F_GETEL)获取文件锁定状态 #define ngx_nonblocking_n "fcntl(O_NONBLOCK)" #define ngx_blocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK) #define ngx_blocking_n "fcntl(!O_NONBLOCK)" #endif
复制代码

  然后看看Ngnix自己定义的阻塞与非阻塞函数:

复制代码
int ngx_nonblocking(ngx_socket_t s)
{
    int  nb;
    nb = 1;
    return ioctl(s, FIONBIO, &nb);//FIONBIO:设置/清除非阻塞I/O 标志
}

int ngx_blocking(ngx_socket_t s)
{
    int  nb;
    nb = 0;
    return ioctl(s, FIONBIO, &nb);
}
复制代码

  ioctl:提供对连接到fd的设备驱动程序的属性和操作的访问。

  而fcntl:用来设置和修改描述符的的属性。

  两种方法都可以用来设置socket阻塞与非阻塞模式。

  再接着扫代码~:

int ngx_tcp_nopush(ngx_socket_t s);
//
setsockopt(s, IPPROTO_TCP, TCP_NOPUSH,(const void *) &tcp_nopush, sizeof(int));---->FREEBSD
//setsockopt(s, IPPROTO_TCP, TCP_CORK,(const void *) &cork, sizeof(int)); ----->linux
int ngx_tcp_push(ngx_socket_t s);
//setsockopt(s, IPPROTO_TCP, TCP_NOPUSH,(const void *) &tcp_nopush, sizeof(int));----->FREEBSD
//
setsockopt(s, IPPROTO_TCP, TCP_CORK,(const void *) &cork, sizeof(int)); ----->linux

  这个指令指定是否使用socket的TCP_NOPUSH(FreeBSD)或TCP_CORK(linux)选项,这个选项只在使用sendfile时有效。设置这个选项的将导致nginx试图将它的HTTP应答头封装到一个包中。

  所谓的cork就是塞子的意思,形象地理解就是用cork将连接塞住,使得数据先不发出去,等到拔去塞子后再发出去,而nodelay事实上是为了禁用Nagle算法,Nagle算法为了增加了网络的吞吐量而牺牲了响应时间体验。

  在进行大量数据发送的时候可以置位TCP_CORK关闭Nagle算法保证网络利用性,尽可能的进行数据的组包,以最大mtu传输。

src/os/unix/Ngx_dup_recv.c

  View Code

   开始就看到了这个NGX_HAVE_KQUEUE~~google一下得到下面的内容~

  kqueue(freebsd)与epoll(linux 2.6)两个东西极其相似,写好了一个之后,移到别外一个平台下,只要稍作修改就可以了,原理是一样,个人认为,从功能角度来盾kqueue比epoll灵活得多。在写kqueue的时候,内核帮你考虑好了不少东西。但是从效率来看,从我作的压力测试来看epoll比kqueue强。

   那么,就可以直接越过freebsd,直接看linux下的了,都很好理解。

复制代码
ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
{
    ssize_t       n;
    ngx_err_t     err;
    ngx_event_t  *rev;
    rev = c->read;
    do {
        n = recv(c->fd, buf, size, 0); //简单的recv()函数
        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
                       "recv: fd:%d %d of %d", c->fd, n, size); //添加日志
        if (n >= 0) {                 //接收数据成功,返回接收数据的大小
            return n;
        }
        err = ngx_socket_errno;    //errno

        if (err == NGX_EAGAIN || err == NGX_EINTR) {
       //EAGAIN重试 EINTR由于信号中断,没读到任何数据
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c
->log, err, "recv() not ready"); n = NGX_AGAIN; } else { n = ngx_connection_error(c, err, "recv() failed"); break; } } while (err == NGX_EINTR);   //EINTR由于信号中断,没读到任何数据 rev->ready = 0; if (n == NGX_ERROR) { rev->error = 1; } return n; }
复制代码

src/os/unix/shmem.c&shmem.h 

  从名称shmem就能看出来share memory共享内存。

  View Code

  其中,有个结构体ngx_shm_t:

复制代码
typedef struct {
    u_char      *addr;   //共享内存的地址
    size_t       size;  //大小
    ngx_str_t    name;   //名称
    ngx_log_t   *log;    
    ngx_uint_t   exists;   /* unsigned  exists:1;  */
} ngx_shm_t;
复制代码

  和两个相关的操作函数(分配/释放共享内存----直接看Linux部分):

复制代码
ngx_int_t ngx_shm_alloc(ngx_shm_t *shm)
{
    int  id;
    id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT));//使用linux下的shmget来创建一个共享内存对象

    ...log...

    shm->addr = shmat(id, NULL, 0);                              //linux下把共享内存区对象映射到调用进程的地址空间

    if (shm->addr == (void *) -1) { //失败的话
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");
    }

    if (shmctl(id, IPC_RMID, NULL) == -1) {                      //linux下完成对共享内存的控制 IPC_RMID:删除这片共享内存
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmctl(IPC_RMID) failed");
    }

    return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK;
}


void
ngx_shm_free(ngx_shm_t *shm)
{
    if (shmdt(shm->addr) == -1) {                               //与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmdt(%p) failed", shm->addr);
    }
}
复制代码

 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/p/3147468.html,如需转载请自行联系原作者

相关文章
|
6月前
|
安全 网络协议 Java
Thread类的用法 && 线程安全 && 多线程代码案例 && 文件操作和 IO && 网络原理初识 &&UDP socket
Thread类的用法 && 线程安全 && 多线程代码案例 && 文件操作和 IO && 网络原理初识 &&UDP socket
38 0
|
11天前
|
Python
Python网络编程基础(Socket编程)UDP服务器编程
【4月更文挑战第8天】Python UDP服务器编程使用socket库创建UDP套接字,绑定到特定地址(如localhost:8000),通过`recvfrom`接收客户端数据报,显示数据长度、地址和内容。无连接的UDP协议使得服务器无法主动发送数据,通常需应用层实现请求-响应机制。当完成时,用`close`关闭套接字。
|
1月前
|
网络协议 Linux
TCP 和 UDP 的 Socket 调用
【2月更文挑战第19天】
TCP 和 UDP 的 Socket 调用
|
2月前
|
tengine Rust 负载均衡
反向代理学习笔记(一) Nginx与反向代理绪论
反向代理学习笔记(一) Nginx与反向代理绪论
|
8月前
|
前端开发 应用服务中间件 nginx
前端学习笔记202305学习笔记第二十三天-nginx项目部署500情况
前端学习笔记202305学习笔记第二十三天-nginx项目部署500情况
45 0
|
4月前
|
存储 网络协议 安全
网络编程『socket套接字 ‖ 简易UDP网络程序』
网络编程『socket套接字 ‖ 简易UDP网络程序』
75 0
|
4月前
|
网络协议
百度搜索:蓝易云【基于TCP/UDP的Socket编程】
通过使用上述示例,您可以基于TCP或UDP协议进行Socket编程,实现网络通信功能。根据您的需求,可以进一步扩展和定制这些示例代码。
36 1
|
3月前
|
网络协议
百度搜索:蓝易云【基于TCP/UDP的Socket编程。】
以上是基于TCP/UDP的Socket编程的基本步骤和函数调用。通过理解和掌握这些概念和操作,可以实现网络应用程序的数据传输和通信功能。
47 1
|
6月前
|
域名解析 存储 移动开发
TCP socket && UDP && TCP协议 && IP协议 && 以太网等
TCP socket && UDP && TCP协议 && IP协议 && 以太网等
36 0
|
6月前
|
存储 网络协议 Java
网络编程:UDP socket
网络编程:UDP socket
55 0