Nginx中发送udp请求
来源:互联网 发布:青岛平面美工培训 编辑:程序博客网 时间:2024/06/04 19:52
Nginx中发送udp请求
最近简单了解了一下Nginx发送udp请求的过程, 在这里简单记录一下.
主要参考的代码主要有两块, 分别是ngx_resolver.c以及agentzh的ngx_lua模块中的udp相关代码(ngx_http_lua_socket_udp.c). 有兴趣的同学可以看一下.
简单分析
首先看一下ngx_resolver.c这个文件, 主要解决了dns查询的问题, 也就是resolver这个指令. 这个文件长度还是蛮长的, 大概有2000多行, 但是udp部分的代码还是相当简洁的, 主要分为几个步骤: 初始化, 连接, 发送以及回收.
初始化的代码:
ngx_resolver.c1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n){ ngx_str_t s; ngx_url_t u; ngx_uint_t i, j; ngx_resolver_t *r; ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; /* 设置回收函数 */ cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NULL; } cln->handler = ngx_resolver_cleanup; r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); if (r == NULL) { return NULL; } cln->data = r; /* 省略很多代码, 初始化红黑树以及队列 */ for (i = 0; i < n; i++) { if (ngx_strncmp(names[i].data, "valid=", 6) == 0) { /* 省略valid参数的设置 */ } /* 进入正题 */ ngx_memzero(&u, sizeof(ngx_url_t)); u.url = names[i]; u.default_port = 53; /* ngx_parse_url用于解析url, 获取ip, port, 地址等信息 */ if (ngx_parse_url(cf->pool, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in resolver \"%V\"", u.err, &u.url); } return NULL; } uc = ngx_array_push_n(&r->udp_connections, u.naddrs); if (uc == NULL) { return NULL; } /* 设置各个ngx_udp_connection_t */ ngx_memzero(uc, u.naddrs * sizeof(ngx_udp_connection_t)); for (j = 0; j < u.naddrs; j++) { /* 看上去只需要设置这几个值;) */ uc[j].sockaddr = u.addrs[j].sockaddr; uc[j].socklen = u.addrs[j].socklen; uc[j].server = u.addrs[j].name; } } return r;}
这里主要就是根据配置文件来初始化ngx_udp_connection_t
类型的变量. 接下来是连接和发送请求:
1234567891011121314151617181920212223242526272829303132333435363738394041424344
static ngx_int_tngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn){ ssize_t n; ngx_udp_connection_t *uc; uc = r->udp_connections.elts; uc = &uc[r->last_connection++]; if (r->last_connection == r->udp_connections.nelts) { r->last_connection = 0; } if (uc->connection == NULL) { uc->log = *r->log; uc->log.handler = ngx_resolver_log_error; uc->log.data = uc; uc->log.action = "resolving"; /* 进行连接 */ if (ngx_udp_connect(uc) != NGX_OK) { return NGX_ERROR; } uc->connection->data = r; uc->connection->read->handler = ngx_resolver_read_response; uc->connection->read->resolver = 1; } /* 发送数据 */ n = ngx_send(uc->connection, rn->query, rn->qlen); if (n == -1) { return NGX_ERROR; } if ((size_t) n != (size_t) rn->qlen) { ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); return NGX_ERROR; } return NGX_OK;}
主要是使用了ngx_udp_connect和ngx_send这两个函数. 用起来还是相当方便的, 里面的实现有兴趣的同学可以看一下. 最后就是关闭连接:
ngx_resolver_cleanup123456789101112131415161718192021222324252627282930313233
static voidngx_resolver_cleanup(void *data){ ngx_resolver_t *r = data; ngx_uint_t i; ngx_udp_connection_t *uc; if (r) { ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "cleanup resolver"); ngx_resolver_cleanup_tree(r, &r->name_rbtree); ngx_resolver_cleanup_tree(r, &r->addr_rbtree); if (r->event) { ngx_free(r->event); } uc = r->udp_connections.elts; /* 关闭每一个建立的连接 */ for (i = 0; i < r->udp_connections.nelts; i++) { if (uc[i].connection) { ngx_close_connection(uc[i].connection); } } ngx_free(r); }}
主要是调用了ngx_close_connection这个函数. 通过以上操作就完成了一次udp数据的发送. ngx_lua当中也基本是这个步骤.
总结下就是:
- 初始化ngx_udp_connection_t类型的变量(通常会用到ngx_parse_url)
- 使用ngx_udp_connect进行连接
- 使用ngx_send进行数据发送
- 关闭连接, 可以在数据回收的回调中进行关闭
自己写一个试试
看明白了基本步骤, 自己验证一下, 写一个的对应的简单handler模块. 在配置文件中设置udp_address来设置要发送的地址, nginx接受到请求之后即向这个地址发送信息.
ngx_resolver_cleanup123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
#include <ngx_config.h>#include <ngx_core.h>#include <ngx_http.h>#include "ddebug.h"typedef struct { ngx_flag_t enable; ngx_udp_connection_t *play_udp_uc;} ngx_http_play_loc_conf_t;ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);static void *ngx_http_play_create_loc_conf(ngx_conf_t *cf);static char *ngx_conf_play(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);static void ngx_http_upstream_play_cleanup(void *data);static char *ngx_conf_set_udp_addr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);static ngx_int_t ngx_http_play_handler(ngx_http_request_t *r);static ngx_command_t ngx_http_play_commands[] = { { ngx_string("play"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, ngx_conf_play, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, { ngx_string("udp_address"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, ngx_conf_set_udp_addr, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, ngx_null_command};static ngx_http_module_t ngx_http_play_module_ctx = { NULL, /* preconfiguration */ //ngx_http_play_init, /* postconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_play_create_loc_conf, /* create location configuration */ NULL /* merge location configuration */};ngx_module_t ngx_http_play_module = { NGX_MODULE_V1, &ngx_http_play_module_ctx, /* module context */ ngx_http_play_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING};static char *ngx_conf_play(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ ngx_http_play_loc_conf_t *plcf; ngx_http_core_loc_conf_t *clcf; ngx_str_t *value; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); plcf = conf; value = cf->args->elts; ngx_conf_log_error(NGX_LOG_INFO, cf, 0, "play: %s", value[1].data); plcf->enable = 0; if (ngx_strncmp(value[1].data, "on", 2) == 0) { clcf->handler = ngx_http_play_handler; plcf->enable = 1; } return NGX_CONF_OK;}static char *ngx_conf_set_udp_addr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ ngx_http_play_loc_conf_t *plcf; ngx_str_t *value; ngx_url_t u; ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; plcf = conf; ngx_memzero(&u, sizeof(ngx_url_t)); value = cf->args->elts; /* resolve url */ u.url = value[1]; u.default_port = 12345; u.no_resolve = 0; if (ngx_parse_url(cf->pool, &u) != NGX_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "parse udp addr failed, %s", value[1].data); return NGX_CONF_ERROR; } /* init udp connection */ plcf->play_udp_uc = ngx_pcalloc(cf->pool, sizeof(ngx_udp_connection_t)); uc = plcf->play_udp_uc; if (uc == NULL) { return NGX_CONF_ERROR; } /* implement udp connection */ uc->sockaddr = u.addrs[0].sockaddr; uc->socklen = u.addrs[0].socklen; uc->server = u.addrs[0].name; uc->log = cf->cycle->new_log; /* implement clean handler */ cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } cln->data = uc; cln->handler = ngx_http_upstream_play_cleanup; // set the cleanup handler return NGX_OK;}static voidngx_http_upstream_play_cleanup(void *data){ ngx_udp_connection_t *uc = data; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "cleanup http_upstream_keepalive_fluentd"); if (uc->connection) { ngx_close_connection(uc->connection); }}static void ngx_http_play_dummy_handler(ngx_event_t *ev){ /* just empty */}static voidngx_http_play_send_udp(ngx_http_request_t *r, ngx_udp_connection_t *uc){ if (uc->connection == NULL) { if (ngx_udp_connect(uc) != NGX_OK) { return; } uc->connection->data = NULL; uc->connection->read->handler = ngx_http_play_dummy_handler; uc->connection->read->resolver = 1; } ngx_send(uc->connection, (u_char*)"hello", 5); return;}/* the main function */static ngx_int_tngx_http_play_handler(ngx_http_request_t *r){ ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_variable_value_t *var; ngx_http_play_loc_conf_t *plcf; plcf = ngx_http_get_module_loc_conf(r, ngx_http_play_module); /* here we go ;) */ rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } ngx_str_set(&r->headers_out.content_type, "text/html"); b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } out.buf = b; out.next = NULL; /* * * I want to change here ;) * * */ ngx_http_play_send_udp(r, plcf->play_udp_uc); b->pos = (u_char *)"send"; b->last = b->pos + 4; /////////////////////////////////////////////////////////////////////////////////////////////// b->memory = 1; b->last_buf = 1; r->headers_out.status = NGX_HTTP_OK; //r->headers_out.content_length_n = var.len; rc = ngx_http_send_header(r); return ngx_http_output_filter(r, &out);}static void *ngx_http_play_create_loc_conf(ngx_conf_t *cf){ ngx_http_play_loc_conf_t *plcf = NULL; plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_play_loc_conf_t)); if (plcf == NULL) { return NULL; } return plcf;}
0 0
- Nginx中发送udp请求
- Nginx中发送udp请求
- 向nginx发送请求
- 使用udp发送域名请求
- JMeter插件模拟发送UDP请求:UDP sampler
- QThread中执行UDP发送
- Android UDP连接发送请求和接受请求的例子
- javaweb项目 UDP发送请求获取客户端MAC地址
- Jmeter模拟发送TCP/UDP/HTTP/FTP等请求包
- java中发送GET请求
- android中发送get请求
- 在flex中发送请求
- java中发送post请求
- java中发送http请求
- jquery中发送ajax请求
- 在循环中发送请求
- java中发送get请求
- c#中UDP数据发送和接收
- Hibernate 连接数据库,取出query.list()集合中的元素
- Integer 变量A,B, 在不声明其它变量的情况下,将他们的值交换,如:A:=1; B:=2; 交换后, A=2, B=1,
- hdu 3008 Warcraft
- 1.数据表的基本操作--MySQL学习笔记
- Spark Streaming 流计算优化记录(1)-背景介绍
- Nginx中发送udp请求
- 程序猿需要知道的相关知识
- linux初学(九)之linux文件系统
- poj 3928 Ping pong 树状数组
- 如果你是一个项目组的老大
- leetcode: Count Complete Tree Nodes
- 贪心精讲
- 提高ios开发效率
- 【leetcode-16】3Sum Closest(java)