概述
为了学习libuv的tcp相关函数使用,实现了一个tcp代理服务。
1 启动TCP服务
2 如果有新的连接X,则向代理地址建立连接Y,并关联X和Y成组
3 如果X收到数据包,发往Y;反之如果Y收到数据包发往X
4 如果X或者Y连接异常,关闭此组连接
5 代理服务退出时,清理所有组,清理TCP服务
API简介
uv_err_name
出现错误可以通过uv_strerror和uv_err_name找错误原因。
int r = uv_accept(server, stream);
fprintf(stderr, "uv_accept error %s\n", uv_err_name(r));
uv_ip4_addr
struct sockaddr_in m_local;
struct sockaddr_in m_remote;
...
uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &m_local);
将给定的ip地址和端口转换成sockaddr_in结构体,原生编程的时候,设置ip和端口需要至少五行,用这个方法可以简化操作
uv_tcp_init
初始化 tcp 对象
uv_loop_t* m_loop;
...
m_loop = uv_default_loop();
...
uv_tcp_t m_tcpServer;
...
uv_tcp_init(m_loop, &m_tcpServer);//初始化tcp server对象
uv_tcp_bind
等同于原生API的 bind() 方法
uv_tcp_bind(&m_tcpServer, (const struct sockaddr*) &m_local, 0);
uv_tcp_bind() 的第三个参数 flag 一般是0,如果想使用IP6,可以使用 UV_TCP_IPV6ONLY
enum uv_tcp_flags {
/* Used with uv_tcp_bind, when an IPv6 address is used. */
UV_TCP_IPV6ONLY = 1
};
uv_listen
与listen作用类似,增加了回调函数,有新连接来时会触发回调。
uv_listen((uv_stream_t*)&m_tcpServer, 50, OnAccept);
uv_accept
在OnAccept回调中执行uv_accept,用socket与stream关联,stream需要先分配内存和初始化。
int r;
uv_stream_t* stream;
...
uv_tcp_init(pProxy->m_loop, (uv_tcp_t*) stream);
...
r = uv_accept(server, stream);
uv_err_name(r)
源码演示
//
/*
在入口函数中包含 _CrtDumpMemoryLeaks();
即可检测到内存泄露
*/
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
//
#include <conio.h> //for kbhit()
#include "stdafx.h"
#include "uv.h"
#include <map>
#include <algorithm>
using namespace std;
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
typedef void* (*proc_func)(char* buff, size_t size);
class CProxy
{
public:
CProxy(const char* sip, int sport, const char* dip, int dport, uv_loop_t* loop = NULL)
{
uv_ip4_addr(sip, sport, &m_local);
uv_ip4_addr(dip, dport, &m_remote);
if (NULL == loop)
{
m_loop = uv_default_loop();
}
else
{
m_loop = loop;
}
}
int Start()
{
int r = 0;
r = uv_tcp_init(m_loop, &m_tcpServer);
if (r)
{
return r;
}
r = uv_tcp_bind(&m_tcpServer, (const struct sockaddr*) &m_local, 0);
if (r)
{
uv_err_name(r);
return r;
}
r = uv_listen((uv_stream_t*)&m_tcpServer, 50, OnAccept);