目录
1. 下载源码
git clone https://github.com/libuv/libuv.git
官方文档
http://docs.libuv.org/en/v1.x/design.html
2. 怎么编译
linux环境下,官方建议是
$ sh autogen.sh
$ ./configure
$ make
$ make check
$ make install
我们自己看看可以配置什么
执行效果:
选择安装目录和只编译静态库
$ ./configure --enable-static --disable-shared prefix=$PWD/output
3. tcp client
//tcpclient.cpp
#include <iostream>
#include <string.h>
#include <assert.h>
#include "uv.h"
#define TCP_SERVER_IP "127.0.0.1"
#define TCP_SERVER_PORT 9000
#define MAX_STRING_LEN 256
uv_tcp_t tcp_client;
uv_connect_t connect_req;
uv_write_t write_req_;
uv_loop_t uv_loop_;
bool need_loop_ = true;
//发送消息
char str_msg_[MAX_STRING_LEN]={0};
uv_buf_t uv_buf_ = {str_msg_, 0 };
uv_async_t async_handle_;
void on_close(uv_handle_t* handle) {
std::cout<<__LINE__<<"******* 退出 ******"<<std::endl;
}
//给读取数据,新建buf
static void alloc_cb(uv_handle_t* handle, size_t suggested_size,uv_buf_t* buf)
{
//std::cout<<__LINE__<<" alloc_cb-- suggested_size="<<suggested_size<<std::endl;
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
//读取网络数据,并且释放buf
static void read_cb(uv_stream_t* stream, ssize_t nread,const uv_buf_t* buf)
{
//std::cout<<__LINE__<<" alloc_cb-- nread="<<nread<<std::endl;
do{
if (nread < 0) {/* Error or EOF */
if (nread == UV_EOF) {
fprintf(stdout, "client(%d)eof\n", stream->u.fd);
} else if (nread == UV_ECONNRESET) {
fprintf(stdout, "client(%d)conn reset\n", stream->u.fd);
} else {
fprintf(stdout, "[%d] %s\n", __LINE__, uv_strerror(nread));
}
uv_close((uv_handle_t*)stream, on_close);
break;;
} else if (0 == nread) {/* Everything OK, but nothing read. */
} else {
char recvMsg[MAX_STRING_LEN]={0};
memcpy(recvMsg, buf->base, nread);
std::cout<<std::endl<<"server: "<<recvMsg<<std::endl;
}
}while(0);
if(buf->base)
free(buf->base);
}
static void write_cb(uv_write_t *req, int status) {
if (req && status == 0)
{
//std::cout << __LINE__ << " write_cb sucess" << std::endl;
}
else
{
std::cout << __LINE__ << " write_cb status = UV_ECONNRESET" <<"status="<< status << std::endl;
uv_close((uv_handle_t*)req->handle, NULL);
}
}
static void on_connect(uv_connect_t* req, int status) {
assert(0 == status);
//std::cout<<__LINE__<<" on_connect status="<<status<<std::endl;
uv_read_start(req->handle, alloc_cb, read_cb);
assert(0==uv_write(&write_req_ , (uv_stream_t *)&tcp_client, &uv_buf_, 1,write_cb ));
}
void on_client_close(uv_handle_t* handle)
{
std::cout<<__LINE__<<" on_client_close"<<std::endl;
}
//完全关闭loop
void on_close_walk(uv_handle_t* handle, void* arg)
{
//std::cout<<__LINE__<<" on_close_walk"<<std::endl;
if (!uv_is_closing(handle)) {
std::cout<<__LINE__<<" call uv_close"<<std::endl;
uv_close(handle, on_client_close);
}
}
static void on_thread_input_msg(void *argc)
{
std::cout<<"thread input msg ..."<<std::endl;
uv_tcp_t *pClient = (uv_tcp_t*)argc;
while(1)
{
uv_sleep(500);
std::cout<<std::endl<<"请输入(q退出):"<<std::endl;
//控制台输入字符串
std::string str_input;
std::getline(std::cin, str_input);
std::cout<<"client: "<<str_input.c_str()<<std::endl;
if(str_input=="q")
{
//此处标志位,然后在相应的回调中close,否则会出现异常
need_loop_ = false;
uv_async_send(&async_handle_);
break;
}
memset(uv_buf_.base, 0x0, MAX_STRING_LEN);
memcpy(uv_buf_.base , str_input.c_str(), str_input.length());
uv_buf_.len = str_input.length();
uv_async_send(&async_handle_);
}
}
static void on_async_send(uv_async_t* handle)
{
//std::cout<<__LINE__<<" in on_async_send ... "<<std::endl;
if(!need_loop_)
{
uv_walk(&uv_loop_, on_close_walk, (void*)handle);
}
if( uv_buf_.len == 0)
{
std::cout<<"空消息,不发送 ..."<<std::endl;
return;
}
int ret=uv_write(&write_req_ , (uv_stream_t *)&tcp_client, &uv_buf_, 1,write_cb );
if(ret==0)
{
//std::cout<<"发送成功 ..."<<std::endl;
}
else{
std::cout<<"发送失败 ..."<<uv_strerror(ret)<<std::endl;
}
}
int main()
{
int ret = 0;
std::cout<<"hello tcp client..."<<std::endl;
assert(ret ==uv_loop_init(&uv_loop_));
ret = uv_tcp_init(&uv_loop_, &tcp_client);
assert(ret == 0);
//本地客户端端口
struct sockaddr_in client_addr;
uv_ip4_addr("127.0.0.1", 9999, &client_addr);
uv_tcp_bind(&tcp_client, (const sockaddr*)&client_addr, 0);
struct sockaddr_in server_addr;
assert(0 == uv_ip4_addr(TCP_SERVER_IP, TCP_SERVER_PORT, &server_addr));
ret = uv_tcp_connect(&connect_req, &tcp_client, (const struct sockaddr*) &server_addr, on_connect );
assert(ret == 0);
//异步发送信息的方式
uv_async_init(&uv_loop_, &async_handle_, on_async_send);
//线程从控制台输入字符串
uv_thread_t thread_msg;
uv_thread_create(&thread_msg, on_thread_input_msg, &tcp_client);
ret = uv_run(&uv_loop_, UV_RUN_DEFAULT);
if(ret==0)
{
std::cout<<"loop 正常退出 ..."<<std::endl;
}
else{
std::cout<<"loop 异常退出 ..."<<uv_strerror(ret)<<std::endl;
}
uv_loop_close(&uv_loop_);
//getchar();
return 0;
}
4.tcp server
//tcpserver.cpp
#include <iostream>
#include <assert.h>
#include "uv.h"
uv_tcp_t tcp_server;
uv_connect_t connect_req;
uv_write_t write_req;
struct sockaddr_in addr;
uv_buf_t buf;
uv_thread_t thread_recv;
uv_thread_t thread_watch_;
uv_loop_t loop_;
#define TCP_SERVER_IP "127.0.0.1"
#define TCP_SERVER_PORT 9000
static void write_cb(uv_write_t *req, int status) {
std::cout<<__LINE__<<" write_cb-- status="<<status<<std::endl;
//assert(status == UV_ECANCELED);
//uv_close((uv_handle_t*) req->handle, NULL);
if (status) {
fprintf(stderr, "Write error %s\n", uv_strerror(status));
}
free(req);
}
static void close_cb(uv_handle_t* handle) {
std::cout<<__LINE__<<" -- close_cb="<<std::endl;
}
static void alloc_cb(uv_handle_t* handle, size_t suggested_size,uv_buf_t* buf)
{
std::cout<<__LINE__<<" alloc_cb-- suggested_size="<<suggested_size<<std::endl;
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
void on_close(uv_handle_t* handle) {
free(handle);
}
static void read_cb(uv_stream_t* stream, ssize_t nread,const uv_buf_t* buf)
{
std::cout<<__LINE__<<" alloc_cb-- nread="<<nread<<std::endl;
if (nread < 0) {/* Error or EOF */
if (nread == UV_EOF) {
fprintf(stdout, "client(%d)eof\n", stream->u.fd);
} else if (nread == UV_ECONNRESET) {
fprintf(stdout, "client(%d)conn reset\n", stream->u.fd);
} else {
fprintf(stdout, "[%d] %s\n", __LINE__, uv_strerror(nread));
}
uv_close((uv_handle_t*)stream, on_close);
return;
} else if (0 == nread) {/* Everything OK, but nothing read. */
} else {
std::cout<<__LINE__<<" read data = "<<nread<<" data:"<<buf->base<<std::endl;
//再发送到client
uv_write_t* req = (uv_write_t*)malloc(sizeof(uv_write_t));
uv_buf_t uvBuf = uv_buf_init(buf->base, nread);
if (uv_write(req, stream, &uvBuf, 1, write_cb)) {
std::cout<<"uv_write failed"<<std::endl;
}
}
free(buf->base);
}
static void connection_cb(uv_stream_t* server, int status)
{
std::cout<<__LINE__<<" connection_cb-- status="<<status<<std::endl;
//为tcp client申请资源;
uv_tcp_t *tcp_client = (uv_tcp_t *) malloc(sizeof(uv_tcp_t));
uv_tcp_init(&loop_, tcp_client);
uv_accept((uv_stream_t*)&tcp_server, (uv_stream_t*)tcp_client);
uv_read_start((uv_stream_t*)tcp_client, alloc_cb, read_cb);
struct sockaddr sockname, peername;
int namelen = sizeof(peername);
assert(0==uv_tcp_getpeername(tcp_client, &peername, &namelen )) ;
struct sockaddr_in check_addr = *(struct sockaddr_in*) &peername;
char check_ip[17];
uv_ip4_name(&check_addr, (char*)check_ip, sizeof check_ip);
std::cout<<__LINE__<<" -- peer ip="<<check_ip <<" : port="<<check_addr.sin_port <<std::endl;
}
static void thread_recv_data(void* arg)
{
std::cout<<__LINE__<<" -- thread_recv_data"<<std::endl;
//
int ret = uv_run(&loop_, UV_RUN_DEFAULT);
if(0 == ret)
{
std::cout<<__LINE__<<" stoped... ret="<<ret<<std::endl;
}
else{
//如果调用了uv_stop(),并且仍有活动句柄或请求,则返回非零
std::cout<<__LINE__<<" stoped... ret="<<ret<<std::endl;
}
}
static void thread_watch(void* arg)
{
while(1)
{
int c = getchar();
if(c=='q')
{
break;
}
}
uv_stop(&loop_);
}
int main()
{
std::cout<<"hello, this is tcp server..."<<std::endl;
assert(0 == uv_ip4_addr("0.0.0.0", TCP_SERVER_PORT, &addr));
assert(0==uv_loop_init(&loop_));
int r = uv_tcp_init(&loop_, &tcp_server);
assert(r == 0);
r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
assert(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);
assert(r == 0);
assert(0 == uv_is_writable((uv_stream_t*) &tcp_server));
assert(0 == uv_is_readable((uv_stream_t*) &tcp_server));
uv_thread_create(&thread_recv, thread_recv_data, (void*)&tcp_server);
uv_thread_create(&thread_watch_, thread_watch, nullptr);
uv_thread_join(&thread_watch_);
uv_thread_join(&thread_recv);
uv_loop_close(&loop_);
uv_close((uv_handle_t*)&tcp_server, close_cb);
return 0;
}
5. 编译
g++ -g -O0 -o client tcpclient.cpp -I./libuv/output/include -L./libuv/output/lib -luv -lpthread -ldl
g++ -g -O0 -o server tcpserver.cpp -I./libuv/output/include -L./libuv/output/lib -luv -lpthread -ldl
6. 执行效果
~/work/tcpdemo$ ./client
hello tcp client...
thread input msg ...
请输入(q退出):
hello
client: hello
server: hello
请输入(q退出):
gogogogogo gooooooo
client: gogogogogo gooooooo
server: gogogogogo gooooooo
请输入(q退出):
q
client: q
93 call uv_close
93 call uv_close
发送失败 ...bad file descriptor
86 on_client_close
86 on_client_close
loop 正常退出 ...
~/work/tcpdemo$ ./server
hello, this is tcp server...
94 -- thread_recv_data
75 connection_cb-- status=0
89 -- peer ip=127.0.0.1 : port=3879
34 alloc_cb-- suggested_size=65536
45 alloc_cb-- nread=5
60 read data = 5 data:hello
19 write_cb-- status=0
34 alloc_cb-- suggested_size=65536
45 alloc_cb-- nread=20
60 read data = 20 data:gogogogogo gooooooo
19 write_cb-- status=0
34 alloc_cb-- suggested_size=65536
45 alloc_cb-- nread=-4095
client(0)eof