网络库是从事C++开发最基础、最核心、最经常使用的一个库,全部的协议都是创建在一个稳定高效的网络库之上的,因此对于c++程序员来讲它是必不可少且很是很是重要的一个核心组件,咱们可使用网络库作任何咱们想作的事情,好比 java
一直不停的在C++、Java、Web以及linux系统运维等技术方面不停的来回切换,忽然发现好久没有作c++了,最近一直在作java的要多,关于c++这块从事有8-9年的开发,这块相关的文章总结的却比Java要少不少。 linux
无论如何,由于工做缘由,最近又杠上了C++的音视频这块相关技术,正好抽空将以前全部的c++资料和库总结了一下:c++
不总结还好,一旦总结,仍是不少的,不少实际项目中开发的库和组件还没提取出来,不过对于一个老C++程序员来讲,项目中开发好的稳定的库和资料是弥足珍贵的,要多善于总结和滚雪球。
在开始讲解boost网络库以前,我这里先给你们稍微普及一下windows下的网络知识,我是windows下开发的,关于socket编程在windows下有多重开发模型,能够参考一下《winsock网络编程》 一书 程序员
选择模型是网络编程中最基础、最简单的一种模型,由于其简单易用性因此备受学生时代的在校生或毕业生使用,可是它也是性能最差的一种编程模型。选择模型是针对select而言的,它能够阻塞能够是非阻塞的,因此它包括两种模式:
(1)、 阻塞模式
执行I/O操做完成前会一直进行等待,不会将控制权交给程序
(2)、 非阻塞模式
执行I/O操做时,WinSock函数会返回并交出控制权。由于函数在没有运行完成就进行返回,并会不断地返回 WSAEWOULDBLOCK错误,可是它功能很强大。 express
异步消息模型就是借助windows的消息机制来实现的,熟悉win32应用开发或者mfc应用开发的人员都知道,全部的窗口都有对应的消息处理机制,咱们只须要建立一个窗口句柄HWND,而后将HWND与对应的消息进行绑定便可,它是经过WsaAsyncSelect接口函数来实现的,它实现的主要思路是:
(1)、首先咱们定义一个消息,告诉系统当有客户端消息到达的时候,发送该消息通知咱们
(2)、而后在消息处理函数里面添加对消息的处理便可 编程
除此以外,winsock还提供了一个异步I/O模型-事件模型--WsaEventSelect ,和WSAAsyncSelect模型相似的是,它也容许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。该模型最主要的差异在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。
事件选择模型不用主动去轮询全部客户端套接字是否有数据到来的模型,它也是在客户端有数据到来时,系统发送通知给咱们的程序,可是,它不是发送消息,而是经过事件的方式来通知咱们的程序,这就解决了WsaAsyncSelect模型只能用在Win32窗口程序的问题。 windows
重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个 WinSock I/O请求。针对这些请求,在它们完成后,应用程序会受到通知,因而就能够经过另外的代码来处理这些数据了。有两种方法能够用来管理重叠I/O请求完成的状况 – 即接到重叠操做完成的通知时处理
(1) 事件对象通知 (Event Object Notification)
基于事件通知的方法,就是要将WinSock事件对象与WSAOVERLPPED结构关联在一块儿,在使用重叠结构的状况下,咱们经常使用的 send,sendto,recv,recvfrom 也要被WSASend,WSASendto,WSARecv,WSARecvfrom 替换掉了。
(2) 完成例程(Completion Routies)
完成例程来实现重叠I/O比用事件通知简单得多,在这个模型中,主线程只用不停的接受链接便可服务器
WSARecv( lpPerIOData->sClient, &lpPerIOData->Buffer, 1, &lpPerIOData->NumberOfByteRecvd, &lpPerIOData->Flags, &lpPerIOData->overlap, CompletionRoutine);
完成端口对象取代了WSAAsyncSelect中的消息驱动和WSAEventSelect中的事件对象,固然完成端口模型的内部机制要比WSAAsyncSelect和WSAEventSelect模型复杂得多,可是是性能最佳的网络编程模型。从本质上说,完成端口模型要求咱们建立一个Win32完成端口对象,经过指定数量的线程,对重叠I/O请求进行管理,以便为已经完成的重叠I/O请求提供服务。
倘若一个应用程序同时须要管理为数众多的套接字,那么采用这种模型,每每能够达到最佳的系统性能!
boost库的网络模型实如今windows上底层是经过iocp完成端口模型实现的,因此是性能最佳的一种网络模型实现。 微信
boost库中有一个专门的用于网络编程的库-asio,也就是异步io,它能实现tcp、udp、甚至usb串口数据读取的功能,它是一个很是强大的、跨平台的异步网络通讯库,这就是我为何选择它的缘由。
在介绍源码实现的时候,咱们先了解一下asio中的几个经常使用对象,和socket同样,它包含以下几个对象 网络
它主要做为一个事件驱动器,在多线程编程里面提供了任务队列和任务分发功能
它和socket同样,提供了端点链接监听相关能力
address封装了设备ipv4和ipv6的地址,endpoint标识address和port的组合,决定一台机器的某个端口(咱们称之为端点)。
套接口编程模型的核心类,提供了同步和异步操做接口集合
说明了以上几个核心概念以后,我须要经过boost网络库封装实现以下几个接口的能力,包括tcp、udp、广播、数据收发、同步异步等,各个接口以及说明以下:
// --------------------------------------------------------------------------------------- // Function: // Init network SDK // Parameters: // [in]pConnectCallBack : connect or disconnect callback // [in]pDataCallBack : receive data callback // [in]pErrCallBack : error message callback // [in]pContext : callback context // Remark: // This interface must be invoked at the beginning of application, when connect server // success or disconnect server pConnectCallBack callback will be invoked; when data // arrived, pDataCallBack callback will be invoked ; when error occur at the process // of running, pErrCallBack callback will be invoked; // pContext parameter express the scenes of the callback, if the callback invoked by // SDK, pContext will be passed to you by callback last parameter // Return: // if error occur, the result value as the top description will be return by SDK // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Init(); // --------------------------------------------------------------------------------------- // Function: // Clean and release SDK resource // Parameters: // NULL // Remark: // This interface must be invoked at the end of application // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Cleanup(); // tcp server // --------------------------------------------------------------------------------------- // Function: // Start or stop listen local port // Parameters: // [in]nPort : listen port // [out]pHandle : server handle address // [lHandle] : server handle output by NetSdk_Listen // Remark: // This interface is adapted to server, not for client // Example: // PCONNECTCALLBACK // NetSdk_Listen--> PRECVDATACALLBACK -->NetSdk_UnListen // PNETSDKERRCALLBACK // || // / // NetSdk_Send // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Listen(int nPort, PCONNECTCALLBACK pConnectCallBack, PRECVDATACALLBACK pDataCallBack, PNETSDKERRCALLBACK pErrorBack, void* pContext, long* pHandle); NETSDK_API NETSDK_RETURN NetSdk_ListenEx(const char* ipV4OrV6, int nPort, PCONNECTCALLBACK pConnectCallBack, PRECVDATACALLBACK pDataCallBack, PNETSDKERRCALLBACK pErrorBack, void* pContext, long* pHandle); NETSDK_API NETSDK_RETURN NetSdk_UnListen(long lHandle); // tcp client // --------------------------------------------------------------------------------------- // Function: // Connect or disconnect server // Parameters: // [in]pServerIp : server ip address // [in]nPort : server port // [out]pHandle : client handle address // [in]lHandle : client handle // [in]nTimeoutSec : timeout // [in]bindLocalPort : tcp client bind local port // Remark: // This interface is adapted to tcp client, not for server // if set bindLocalPort to none zero, then client bind local port by manual // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Connect(const char* pServerIp, int nPort, int nTimeoutSec, PCONNECTCALLBACK pConnectCallBack, PRECVDATACALLBACK pDataCallBack, void* pContext, long* pHandle, int bindLocalPort = 0); // tcp client // --------------------------------------------------------------------------------------- // Function: // Send message to server or reply message to client // Parameters: // [in]nClientId : client handle // [in]pBytes : send data address // [in]nLen : send data length // Remark: // This interface is adapted to tcp client, not for server // Example: // NetSdk_Connect-->NetSdk_Send-->NetSdk_DisConnect // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Send(long nClientId, unsigned char* pBytes, int nLen); // return byte have send, if error occur then return 0 or less than 0 NETSDK_API int NetSdk_SendSync(long nClientId, unsigned char* pBytes, int nLen); // tcp client // --------------------------------------------------------------------------------------- // Function: // Get TCP Client local address and peer address // Parameters: // [in]nClientId : client handle // [in]pBytes : send data address // [in]nLen : send data length // Remark: // This interface is adapted to tcp client // Example: // NetSdk_Connect-->NetSdk_GetConnectAddr // NetSdk_Listen-->PCONNECTCALLBACK-->NetSdk_GetConnectAddr // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_GetConnectAddr(long nClientId, sockaddr_in* pLocalAddr, sockaddr_in* pPeerAddr); // udp client // --------------------------------------------------------------------------------------- // Function: // Bind local port and send udp data to another device // Parameters: // NULL // Remark: // This interface is adapted to udp client, not for server // NetSdk_Broadcast_Sync and NetSdk_SendTo_Sync is synchronized interface // the value returned is indicate the size has send // NetSdk_Broadcast and NetSdk_SendTo is asynchronized interface // Example: // NetSdk_Bind-->NetSdk_Broadcast // or // NetSdk_Bind-->NetSdk_SendTo // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Bind(const char* pServerIp, int nPort, PRECVDATACALLBACK pDataCallBack, void* pContext,long* pHandle); // --------------------------------------------------------------------------------------- // Function: // Send Udp broadcast message to local network // Parameters: // [in]nClientId : returned by NetSdk_Bind // [in]nPort : which port to all machine // [in]pBytes : the message body // [in]nLen : the message length // Remark: // this interface is used to send broadcast to all // machine in local network // Example: // NetSdk_Bind-->NetSdk_Broadcast // or // NetSdk_Bind-->NetSdk_SendTo // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_Broadcast(long nClientId,int nPort,unsigned char* pBytes, int nLen); // --------------------------------------------------------------------------------------- // Function: // Send Udp message to specific machine // Parameters: // [in]nClientId : returned by NetSdk_Bind // [in]pAddr : the endpoint to received message // [in]pBytes : the message body // [in]nLen : the message length // Remark: // NULL // Example: // NetSdk_Bind-->NetSdk_SendTo // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_SendTo(long nClientId,sockaddr_in* pAddr,unsigned char* pBytes, int nLen); NETSDK_API int NetSdk_Broadcast_Sync(long nClientId,int nPort,unsigned char* pBytes, int nLen); NETSDK_API int NetSdk_SendTo_Sync(long nClientId,sockaddr_in* pAddr,unsigned char* pBytes, int nLen); // tcp or udp client // --------------------------------------------------------------------------------------- // Function: // Close client handle // Parameters: // NULL // Remark: // // Example: // NetSdk_Bind-->NetSdk_CloseHandle // or // NetSdk_Connect-->NetSdk_CloseHandle // Return: // return value returned by SDK As mentioned above // --------------------------------------------------------------------------------------- NETSDK_API NETSDK_RETURN NetSdk_CloseHandle(long lHandle);
实现总的类图以下所示
各个类的做用以下:
提供了做为tcp客户端和udp客户端的基础实现类,包括获取客户id、获取地址、端口、日志等接口封装
实现了udp本地端口绑定、数据同步异步发送、数据接收、广播等接口
实现了tcp客户端链接、断开、发送数据、处理数据等接口
服务端网络的抽象,服务端能够同时监听多个网卡的多个网口,它包括启动、中止等接口
是tcp网络的实现,服务端能够同时监听多个tcp端点,实现多端口通讯。
网络管理器,管理多个网络对象,包括添加网络、移除网络、清理等接口
udp数据异步发送
NETSDK_RETURN CUdpClient::AsynSendTo(udp::endpoint ep, unsigned char* pBytes, int nLen) { try { // 获取空buffer BufferPtr pBuffer = m_write_buffer.GetEmptyBuffer(); if (!pBuffer) return NETERR_BUFERR_FULL; // 填充数据 pBuffer->FillData(pBytes, nLen); pBuffer->m_ep = ep; m_write_buffer.AddFullBuffer(pBuffer); // 数据是否发送完毕 boost::mutex::scoped_lock a_lock(m_send_lock); if (m_send_finish) { // 获取当前发送buffer BufferPtr pBuffer = m_write_buffer.GetFullBuffer(); // 无可发送的buffer if (!pBuffer) return NETERR_UNKNOWN; m_send_finish = false; AsyncSend(pBuffer); } return NETERR_SUCCESS; } catch (std::exception& e) { CCallBack::NotifyErrCB(m_eType, GetSId(), GetId(), NETERR_UNKNOWN, (unsigned char*)e.what(), strlen(e.what())); } return NETERR_UNKNOWN; }
tcp客户端链接
bool CTcpClient::Connect(std::string strIp, int nPort, bool bSync, int nTimeout) { try { tcp::endpoint ep(ip::address::from_string(strIp), nPort); if (bSync) { m_bconnected = false; boost::system::error_code err_code; if (m_bindLocalPort != 0) { m_socket.open(/*tcp::v4()*/ep.protocol(), err_code); m_socket.set_option(tcp::acceptor::reuse_address(true), err_code); tcp::endpoint bind_ep(ip::address::from_string("0.0.0.0"), m_bindLocalPort); m_socket.bind(bind_ep, err_code); } // 非阻塞模式链接,方式默认等待20秒 // { // m_socket.io_control(boost::asio::ip::tcp::socket::non_blocking_io(true)); // //err_code = m_socket.connect(ep, err_code); // m_socket.connect(ep, err_code); // // fd_set fdWrite; // FD_ZERO(&fdWrite); // FD_SET(m_socket.native(), &fdWrite); // timeval tv = { nTimeout }; // if (select(0, NULL, &fdWrite, NULL, &tv) <= 0 || !FD_ISSET(m_socket.native(), &fdWrite)) // { // m_bconnected = false; // return m_bconnected; // } // // m_socket.io_control(boost::asio::ip::tcp::socket::non_blocking_io(false)); // m_bconnected = true; // StartKeepAlive(); // } // err_code = m_socket.connect(ep, err_code); // if (!err_code) // { // m_bconnected = true; // StartKeepAlive(); // return true; // } // return m_bconnected; boost::recursive_mutex::scoped_lock guard(m_connect_mutext); m_socket.async_connect(ep, boost::bind(&CTcpClient::ConnectHandler, shared_from_this(), boost::asio::placeholders::error)); m_connect_cond.wait_for(guard, boost::chrono::seconds(nTimeout)); return m_bconnected; } else { m_socket.async_connect(ep, boost::bind(&CTcpClient::ConnectHandler, shared_from_this(), boost::asio::placeholders::error)); return true; } } catch (std::exception& e) { CCallBack::NotifyErrCB(m_eType, GetSId(), GetId(), NETERR_UNKNOWN, (unsigned char*)e.what(), strlen(e.what())); } return false; }
tcp数据处理
NETSDK_RETURN CTcpClient::AsynWrite(unsigned char* pBytes, int nLen) { try { if(!m_bconnected) return NETERR_SEND_ERR; // 获取空buffer BufferPtr pBuffer = m_write_buffer.GetEmptyBuffer(nLen); if (!pBuffer) return NETERR_BUFERR_FULL; // 填充数据 pBuffer->FillData(pBytes, nLen); m_write_buffer.AddFullBuffer(pBuffer); // 数据是否发送完毕 boost::mutex::scoped_lock a_lock(m_send_lock); if (m_send_finish) { // 获取当前发送buffer BufferPtr pNextBuffer = m_write_buffer.GetFullBuffer(); // 无可发送的buffer if (!pNextBuffer) return NETERR_UNKNOWN; m_send_finish = false; AsyncSend(pNextBuffer); } return NETERR_SUCCESS; } catch (std::exception& e) { CCallBack::NotifyErrCB(m_eType, GetSId(), GetId(), NETERR_UNKNOWN, (unsigned char*)e.what(), strlen(e.what())); } return NETERR_UNKNOWN; }
稍微注意的是,tcp数据发送的时候,我这里用了一个环形缓冲区,数据发送首先进入环形缓冲器,发送完成后继续从环形缓冲区中获取数据并发送出去。
tcp数据读取
void CTcpClient::ReadHandler(const boost::system::error_code err, const size_t nTransferedSize) { sockaddr_in stAddr; try { stAddr.sin_family = AF_INET; stAddr.sin_addr.s_addr = inet_addr(GetAddr().c_str()); stAddr.sin_port = htons(GetPort()); if (!err && nTransferedSize > 0) { CCallBack::NotifyDataCB(m_eType, GetSId(), GetId(),&stAddr,m_read_buffer->m_pBuffer, nTransferedSize); AsynRead(); } else if(err) { std::string strErr = (boost::format("read tcp data error[%d]n")%err.value()).str(); CCallBack::NotifyErrCB(m_eType, GetSId(), GetId(), NETERR_RECV_ERR, (unsigned char*)strErr.c_str(), strErr.length()); // 其余异常不认为是断开 if (WSAECONNRESET == err.value() || WSAECONNABORTED == err.value() || WSAENETRESET == err.value() || WSAESHUTDOWN == err.value() || WSAENETDOWN == err.value() || WSAEHOSTDOWN == err.value()|| ERROR_SEM_TIMEOUT == err.value() || ERROR_FILE_NOT_FOUND == err.value()) { m_bconnected = false; if(CClientMgr::get_mutable_instance().GetTcpClient(GetId())) { CClientMgr::get_mutable_instance().PopTcpClient(GetId()); CCallBack::NotifyConnectCB(m_eType, GetSId(), GetId(), &stAddr, true); } } else { std::string strErr = (boost::format("ReadHandle error[%d-%s]n")%err.value()%err.message()).str(); WriteLog(strErr); } } else { std::string strErr = (boost::format("ReadHandle error[%d-%s]n")%err.value()%err.message()).str(); WriteLog(strErr); } } catch (std::exception& e) { std::string strErr = (boost::format("read tcp[%d] data exception[%s]n")%GetId()%e.what()).str(); CCallBack::NotifyErrCB(m_eType, GetSId(), GetId(), NETERR_RECV_ERR, (unsigned char*)strErr.c_str(), strErr.length()); WriteLog(strErr); } }
当有数据回调的时候,咱们首先检查是否有错误,如网络断开、对方重置链接、关闭、超时等,若是没有错误则回调出去数据,若是异常则回调断开异常!
服务端实现,最重要的就是支持多个端点的监听,支持多个客户端的链接,如下一tcp服务为例进行说明
tcp服务端链接监听实现
bool CTcpServer::Listen() { try { boost::system::error_code err; if (!m_acceptor.is_open()) { m_acceptor.open(m_endPoint.protocol(),err); if (err) { Stop(); return false; } m_acceptor.set_option(tcp::acceptor::reuse_address(true),err); if (err) { Stop(); return false; } m_acceptor.bind(m_endPoint,err); if (err) { Stop(); return false; } m_acceptor.listen(socket_base::max_connections,err); if (err) { Stop(); return false; } } TcpClientPtr client(new CTcpClient(m_io_server,GetId(),true)); client->RegisterConnectCallBack(GetConnectCallBack(), GetConnectCallBackContext()); client->RegisterReceiveDataCallBack(GetReceiveDataCallBack(), GetReceiveDataCallBackContext()); m_acceptor.async_accept(client->GetSocket(),bind(&CTcpServer::AcceptClient,shared_from_this(),boost::asio::placeholders::error,client)); } catch (std::exception) { return false; } return true; }
当客户端链接到服务端以后,会调用异步回调
void CTcpServer::AcceptClient(boost::system::error_code err, TcpClientPtr client) { if (err) { return ; } // client connect { sockaddr_in stAddr; std::memset(&stAddr, 0, sizeof(stAddr)); stAddr.sin_family = AF_INET; stAddr.sin_addr.s_addr = inet_addr(client->GetAddr().c_str()); stAddr.sin_port = ::ntohs(client->GetPort()); CCallBack::NotifyConnectCB(client_type_tcp, GetId(), client->GetId(), &stAddr, false); } CClientMgr::get_mutable_instance().PushTcpClient(client->GetId(), client); client->StartKeepAlive(); client->AsynRead(); Listen(); }
客户端链接以后将由CClientMgr客户端管理对象进行管理。
核心的代码我在上面已经列举出来,其余的枝节你们能够自行补脑或搜索实现,下面咱们使用tcp-udp测试工具进行测试或使用我写的自带测试工具测试,首先来了解一下netsdk网络的使用,个人头文件中有关于该网络的说明:
// ------------------------------------------------------------------------------------------------ // File: // netsdk.h // Usage: // net library for tcp client or udp client or tcp server // Remark: // usage for this library discribed as follow // Author: // lixiangxiang from founder // History: // 2015/10/1 v1.0 // Contact: // lixiang6153@126.com csdn name:lixiang987654321 // Copyright: // lixiang6153@126.com // ------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------- // >>>>>>>>>>>>>>>>>>>>>>>usage for this library<<<<<<<<<<<<<<<< // ********************************tcp server************************************************* // NetSdk_Init → PNETSDKERRCALLBACK → NetSdk_Cleanup // ↓ // ↓nClientId (client connected,bExit is false,save client id) // ↓ // PRECVDATACALLBACK(data from client) // ↓ // ↓ // NetSdk_Send (response data toclient) // ↓ // ↓maybe occur // PCONNECTCALLBACK(client disconnect, bExit is true) // // ********************************tcp client************************************************* // NetSdk_Init → NetSdk_Connect → NetSdk_CloseHandle → NetSdk_Cleanup // ↓ // ↓ // PRECVDATACALLBACK(data from server) // ↓ // ↓maybe occur // PCONNECTCALLBACK(server disconnect, bExit is true) // // ********************************udp client************************************************* // NetSdk_Init → NetSdk_Bind NetSdk_CloseHandle→ NetSdk_Cleanup // ↓ // ↓ // NetSdk_SendTo(send data to endpoint) // // ********************************udp broadcast********************************************** // NetSdk_Init → NetSdk_Bind NetSdk_CloseHandle→ NetSdk_Cleanup // ↓ ↓ // ↓ ↓ // (send broadcast to everyone) (receive data from endpoint) // NetSdk_Broadcast PRECVDATACALLBACK // //-------------------------------------------------------------------------------------------------
我这里稍做说明,若是是做为服务器端咱们的使用方式以下:
NetSdk_Init初始化网络库=>NetSdk_Listen开始监听本机端口=> 接收链接=>处理数据=> NetSdk_UnListen中止端口监听=>NetSdk_Cleanup清理网络库资源
咱们能够同时监听多个网卡的多个端口,若是须要服务端反馈数据给客户端,能够经过链接返回的clientId,使用客户端相关接口进行回复和反馈。
做为客户端,若是是tcp客户端,使用接口流程以下:
NetSdk_Init初始化网络库=>NetSdk_Connect链接服务器=>处理数据=>NetSdk_Send发送数据到服务端=> NetSdk_CloseHandle关闭与服务端链接=>NetSdk_Cleanup清理网络库资源
做为tcp客户端,数据发送也能够支持同步和异步发送,默认是异步,同步发送接口NetSdk_SendSync
做为客户端,若是是udp客户端,使用接口流程以下:
NetSdk_Init初始化网络库=>NetSdk_Bind绑定本机端口=>处理数据=>NetSdk_SendTo发送数据报文到对应机器=> NetSdk_CloseHandle关闭与服务端链接=>NetSdk_Cleanup清理网络库资源
做为udp客户端,数据发送也支持同步发送,同步发送接口:NetSdk_SendTo_Sync;除此以外udp还支持广播,广播接口也支持同步也异步发送,接口以下:
NetSdk_Broadcast NetSdk_Broadcast_Sync
个人测试工具以下所示:
包括了服务端和客户端,能够将该工具放在2台机器,一台作服务端,一台作客户端,若是没有多余机器,可使用一个工具进行测试既做为服务端,也做为客户端,客户端使用同一个ip和端口。
服务端监听和断开监听代码
void CNetsdkDemonDlg::OnBnClickedButtonListen() { UpdateData(TRUE); if (m_listenHandle < 0) { if (NETERR_SUCCESS != NetSdk_Listen(m_local_port, Connect_Callback, Receive_Data_Callback, Error_Callback, this, &m_listenHandle)) { AfxMessageBox("监听本机端口失败!"); return; } GetDlgItem(IDC_BUTTON_LISTEN)->SetWindowText("中止监听"); AddLog("服务端:开始监听本机端口:%d", m_local_port); EnableServerButton(FALSE); } else { CloseServer(); GetDlgItem(IDC_BUTTON_LISTEN)->SetWindowText("开始监听"); AddLog("服务端:中止监听本机端口"); EnableServerButton(TRUE); } } void CNetsdkDemonDlg::CloseServer() { if (m_listenHandle > 0) { NetSdk_UnListen(m_listenHandle); m_listenHandle = -1; } }
如本机默认监听的端口为1234,启动demon后点击监听(本地ip使用默认的127.0.0.1监听全部网卡)
监听成功后效果
监听成功后可使用tcp-dup测试工具测试链接本机的1234端口了
能够看到使用tcp-udp测试工具链接上了个人服务端,注意个人本机真实地址192.168.50.7,服务端监听的是全部网卡的1234端口!
而后咱们发送数据试试看!
能够看到服务端收到了客户端id为3的客户发送到服务端的数据!
为了不干扰,咱们使用tcp-udp工具做为服务端,个人测试工具做为客户端链接到服务端(固然客户端和服务端彻底能够用个人工具)测试以下:
能够看到客户端链接到了服务端,下面咱们开始发送数据:
我给的demon仅仅调用了tcp服务端和tcp客户端相关接口,固然还包括udp相关接口,这里能够本身测试调用,我想说明的是本网络库是通过了大量数据测试和多个实战项目测试的一个稳定高效的网络库组件(120路音视频主码流同时发送接收),只要有了网络库组件,你不再在为项目之间的通讯而担心,只需关注业务逻辑处理便可。
固然,网络库进行是封装了tcp和udp等相关通讯,协议层(私有协议或http、rtsp等与业务相关的协议)设计仍是须要你我的去设计的,这个与项目的具体业务息息相关,与底层的通讯无关(不关心传输的是什么数据)。
另外,本网络库是通过了大量实战和不断更新和修改的稳定高效的网络库,花费了较多的心思,因此若是须要本项目的源码,能够与本人直接沟通购买意向,价格在500-1000不等(本身考量一下应该是很值得了,买一个视频教程都已经到这个数了),该库是一个boost封装了跨平台的库(linux只须要稍做改动,请自行修改,本人不会帮忙修改),代码风格绝对是一个c++老手写的代码,阅读性较强,新手上手较快,很容易修改得linux或定制本身接口或添加其余模块或功能,代码一瞥:
源码获取、合做、技术交流请获取以下联系方式:
QQ交流群:961179337
微信帐号:lixiang6153
公众号:IT技术快餐
电子邮箱:lixx2048@163.com
参考文章:
http://blog.tk-xiong.com/arch...