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

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 
#include 
#include 
#include 
#include 

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标准函数的封装。

你可能感兴趣的:(nodejs,libuv,nodejs,libuv,tcp)