udpserver
//udpserver.cpp
#include <iostream>
#include <assert.h>
#include "uv.h"
uv_udp_t udp_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;
}
static void on_udp_send(uv_udp_send_t* req, int status)
{
std::cout << __LINE__ << " on udp send..." << std::endl;
}
static void udp_recv_cb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
{
std::cout<<__LINE__<<" in udp_recv_cb nread="<<nread<<std::endl;
if (nread < 0) {/* Error or EOF */
std::cout<<__LINE__<<" udp_recv_cb nread="<<nread<<std::endl;
return;
} else if (0 == nread) {/* Everything OK, but nothing read. */
} else {
std::cout<<__LINE__<<" read data = "<<nread<<" data:"<<buf->base<<std::endl;
//再回传到client
uv_buf_t uvBuf = uv_buf_init(buf->base, nread);
uv_udp_send_t* req = (uv_udp_send_t*)malloc(sizeof(uv_udp_send_s));;
int ret = uv_udp_send(req, handle, &uvBuf, 1, addr, on_udp_send);
std::cout<<__LINE__<<" ret="<<ret<<" : "<<uv_strerror(ret);
}
free(buf->base);
}
void on_close(uv_handle_t* handle) {
free(handle);
}
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_udp_init(&loop_, &udp_server);
assert(r == 0);
r = uv_udp_bind(&udp_server, (const struct sockaddr*) &addr, 0);
assert(r == 0);
assert(0==uv_udp_recv_start(&udp_server, alloc_cb, udp_recv_cb));
uv_thread_create(&thread_recv, thread_recv_data, (void*)&udp_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*)&udp_server, close_cb);
return 0;
}
udpclient
//udpclient.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_udp_t udp_client;
uv_connect_t connect_req;
uv_udp_send_t send_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__<<" in alloc_cb, suggested_size="<<suggested_size<<std::endl;
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
//读取网络数据,并且释放buf
static void udp_recv_cb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
{
//std::cout<<__LINE__<<" in udp_recv_cb nread="<<nread<<std::endl;
if (nread < 0) {/* Error or EOF */
std::cout<<__LINE__<<" udp_recv_cb nread="<<nread<<std::endl;
return;
} else if (0 == nread) {/* Everything OK, but nothing read. */
} else {
buf->base[nread]='\0';
std::cout<<__LINE__<<" server:"<<buf->base<<std::endl;
}
free(buf->base);
}
static void on_udp_send(uv_udp_send_t* req, int status)
{
//std::cout << __LINE__ << " on udp send..." << std::endl;
}
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_udp_send(&send_req_ , &udp_client, &uv_buf_, 1 , NULL, on_udp_send);
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_udp_init(&uv_loop_, &udp_client);
assert(ret == 0);
//本地客户端端口
struct sockaddr_in client_addr;
uv_ip4_addr("127.0.0.1", 9999, &client_addr);
uv_udp_bind(&udp_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_udp_connect(&udp_client, (const struct sockaddr*) &server_addr );
assert(ret == 0);
uv_udp_recv_start(&udp_client, alloc_cb, udp_recv_cb);
//异步发送信息的方式
uv_async_init(&uv_loop_, &async_handle_, on_async_send);
//线程从控制台输入字符串
uv_thread_t thread_msg;
uv_thread_create(&thread_msg, on_thread_input_msg, &udp_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;
}
演示:
client
~/work/udpdemo$ ./client
hello tcp client...
thread input msg ...
请输入(q退出):
12345678
client: 12345678
46 server:12345678
请输入(q退出):
321
client: 321
46 server:321
请输入(q退出):
q
client: q
66 call uv_close
66 call uv_close
59 on_client_close
59 on_client_close
loop 正常退出 ...
server
~/work/udpdemo$ ./server
hello, this is tcp server...
73 -- thread_recv_data
35 alloc_cb-- suggested_size=65536
47 in udp_recv_cb nread=8
54 read data = 8 data:12345678
61 ret=0 : Unknown system error 035 alloc_cb-- suggested_size=65536
47 in udp_recv_cb nread=0
42 on udp send...
35 alloc_cb-- suggested_size=65536
47 in udp_recv_cb nread=3
54 read data = 3 data:321<i
61 ret=0 : Unknown system error 035 alloc_cb-- suggested_size=65536
47 in udp_recv_cb nread=0
42 on udp send...