基于libuv库的简单UDP聊天客户端+服务端

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...

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值