您的位置:首页 > 理论基础 > 计算机网络

libuv之开启tcp服务端监听,并获得客户端的ip及端口

2015-02-12 15:17 477 查看
libuv中处理tcp连接的handle叫做uv_tcp_t,可以认为它是uv_stream_t的子类,所以它是可以当作流来使用的,这篇主要内容不在这,其实主要介绍两个函数

UV_EXTERN int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name,
int* namelen);
UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,
int* namelen);


一个用来获得“我方”的socket信息,一个用来获得“对方”的socket信息。

下面看一个简单的示例

/*
*  演示了通过uv_tcp_getpeername获得客户的ip和端口
* test_get_sock_name.cc
* Created on: 2015年2月12日
*/

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <node/uv.h>

int server_port = 7000;
uv_tcp_t tcpServer;
uv_loop_t* loop;

//开启一个tcp监听
int tcp_listener();
//一个新的连接到达时的回调函数
void on_connection(uv_stream_t* server, int status);
//校验两个地址是否相同
void check_sockname(struct sockaddr* addr, const char* compare_ip,
int compare_port, const char* context);

int tcp_listener() {
struct sockaddr sockname, peername;
int namelen;
int r;
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", server_port);
uv_tcp_init(loop, &tcpServer);
uv_tcp_bind(&tcpServer, addr);
uv_listen((uv_stream_t*) &tcpServer, 128, on_connection);

//sockname,获得监听自己的ip和端口
memset(&sockname, -1, sizeof sockname);
namelen = sizeof sockname;
r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen);
printf("the r is %d.\n", r);
check_sockname(&sockname, "0.0.0.0", server_port, "server socket");

//没有连接时,peername是无意义的
namelen = sizeof peername;
r = uv_tcp_getpeername(&tcpServer, &peername, &namelen);
printf("the r is %d.\n", r);
if (r == -1) {
printf("socket is not connected.\n");
}

return 0;
}

void on_connection(uv_stream_t* server, int status) {
struct sockaddr sockname, peername;
int namelen;
uv_tcp_t* handle;
int r;

if (status != 0) {
printf("Connect error %s\n");
}

handle = (uv_tcp_t*)malloc(sizeof(*handle));

r = uv_tcp_init(loop, handle);

/* associate server with stream */
handle->data = server;

uv_accept(server, (uv_stream_t*)handle);

memset(&sockname, -1, sizeof sockname);
namelen = sizeof sockname;
r = uv_tcp_getsockname(handle, &sockname, &namelen);
printf("the r is %d.\n", r);
check_sockname(&sockname, "0.0.0.0", server_port, "server socket");

//有连接,可以获得目标的ip和端口
namelen = sizeof peername;
r = uv_tcp_getpeername(handle, &peername, &namelen);
printf("the r is %d.\n", r);
check_sockname(&peername, "127.0.0.1", -1, "accepted socket peer");

//这儿应该开启一个流读取数据(这个例子只是为了说明怎么获得客户端的地址和端口)
}

void check_sockname(struct sockaddr* addr, const char* compare_ip,
int compare_port, const char* context) {
struct sockaddr_in check_addr = *(struct sockaddr_in*) addr;

char check_ip[17];
int r;

struct sockaddr_in compare_addr = uv_ip4_addr(compare_ip, compare_port);

/* Both addresses should be ipv4 */
if (check_addr.sin_family == AF_INET) {
printf("src sin_family is AF_INET.\n");
}

if (compare_addr.sin_family == AF_INET) {
printf("compare sin_family is AF_INET.\n");
}

/* Check if the ip matches */
if (memcmp(&check_addr.sin_addr, &compare_addr.sin_addr,
sizeof compare_addr.sin_addr) == 0) {
printf("ip matches.\n");
}

/* Check if the port matches. If port == 0 anything goes. */
if (compare_port == 0 || check_addr.sin_port == compare_addr.sin_port) {
printf("port matches.\n");
}
//网络字节序转换成主机字符序
uv_ip4_name(&check_addr, (char*)check_ip, sizeof check_ip);

//或者像下面这样获得ip地址
//char* check_ip = inet_ntoa(check_addr.sin_addr);

printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port));
}

int main() {
loop = uv_default_loop();
tcp_listener();
return uv_run(loop, UV_RUN_DEFAULT);
}


启动服务器端的监听,我们得到如下输出:

the r is 0.
src sin_family is AF_INET.
compare sin_family is AF_INET.
ip matches.
port matches.
server socket: 0.0.0.0:7000
the r is -1.
socket is not connected.


当有一个客户端连接时,输出如下

the r is 0.
src sin_family is AF_INET.
compare sin_family is AF_INET.
ip matches.
port matches.
server socket: 0.0.0.0:7000
the r is -1.
socket is not connected.
the r is 0.
src sin_family is AF_INET.
compare sin_family is AF_INET.
port matches.
server socket: 127.0.0.1:7000
the r is 0.
src sin_family is AF_INET.
compare sin_family is AF_INET.
ip matches.
accepted socket peer: 127.0.0.1:58830


这两个函数,其实就是对C的两个socket标准函数的封装。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐