各位做过UDP完成端口的大侠帮忙了

jzgenius 2004-03-16 01:33:30
公司老大要我用UDP与完成端口实现服务器客户端模型,我是菜鸟啊,所以,哪位老大能Share个UDP用完成端口的代码看看,一定给分,100不够,我给1000也行。
要求是用UDP作服务器的收发操作,并充分利用完成端口的功能,实现高效率相应的数据收发操作。
代码有没有注释过都可以,看代码的功夫我还行,也会在MSDN中找资料。

前提:
我在MSDN或则网上找了很久,都没有完整的用UDP与完成端口作的应用程序代码,总是部分的,大部分都是TCP的,我也找了些代码看,但是总是一知半解,所以,老大们啊,救命啊~~~~~~~~~~~~~~~~~~~~~

联系QQ:3642100
E-Mail: rodger_hu@genius-software.com

再次感谢!!!!!!!!!!!诚心感谢!!!!!!!!!!!!!
...全文
362 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
jzgenius 2004-03-19
  • 打赏
  • 举报
回复
代码还没有详细看,马上就看 :)

太感谢你的帮助了,我想也一定帮助了更多人,大家都会从你的代码中学到东西的,谢谢!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
chenwhenlong 2004-03-19
  • 打赏
  • 举报
回复
注:我的是在服务端用作 UDP 转发器的。
chenwhenlong 2004-03-19
  • 打赏
  • 举报
回复
/*************************************************************************
文件名称: LUdpTranser.cpp
创建时间: 2003/11/30 16:26
程序编制: needway

功能描述:
*************************************************************************/

//========================================================================
// 断开完成端口
void LUdpTranser::CloseCompletionPort()
{
m_bExitThread = TRUE; // 要求线程池开始退出!

// 要求所有已启动的工作线程退出
while (m_nWorkerCounts) {
PostQueuedCompletionStatus(m_hIOPort, 0, NULL, NULL);
}

// 断开所有已经连接的用户
while (m_UsedLister) {
DelUser(m_UsedLister);
}

// 关闭完成端口
CloseHandle(m_hIOPort);

// 释放所有的用户句柄
HIOCP hTempUser;
while ((hTempUser = m_FreeLister) != NULL) {
m_FreeLister = m_FreeLister->pNextIOCP;

VMFree(hTempUser->wsaRecvBuf.buf);
VMFree(hTempUser);
}
}

//========================================================================
// 线程池函数
UINT LUdpTranser::ThreadPoolProc(LUdpTranser* pThis)
{
DWORD dwIoSize;
LPOVERLAPPED lpOverlapped;
HIOCP lpClientContext;
POVERLAPPEDPLUS pOverlapPlus = NULL;

// 工作线程的数量加 1
InterlockedIncrement(&pThis->m_nWorkerCounts);

HANDLE hCompletionPort = pThis->m_hIOPort;
while (!pThis->m_bExitThread) {
if(pOverlapPlus)
DestroyOverlappedPlus(pOverlapPlus);

// 进入阻塞模式,等待网络事件
lpClientContext = NULL;
if (!GetQueuedCompletionStatus(hCompletionPort, &dwIoSize,
(LPDWORD)&lpClientContext, &lpOverlapped, INFINITE)) {
// 无法从队列中取出消息

// 虽然 pOverlapPlus 在这个作用域不起作用,但是一定要,否则会
// 造成内存泄漏!
pOverlapPlus = CONTAINING_RECORD(lpOverlapped,
tagOverlappedPlus, m_ol);

if (lpClientContext && !pThis->m_bExitThread) {
pThis->DelUser(lpClientContext);
}
continue;
}

pOverlapPlus = CONTAINING_RECORD(lpOverlapped, tagOverlappedPlus,
m_ol);

if (NULL == pOverlapPlus || NULL == lpClientContext) {
continue; // Error Or StopServer
}

//================================================================
// 处理事件,返回是否需要接收数据
switch(pOverlapPlus->m_ioType) {
case IOAccept:
pThis->OnAddUser(lpClientContext);
break;

case IORead:
pThis->OnClientReading(lpClientContext, dwIoSize);
break;
}

//================================================================
// 接收数据
if (lpClientContext->socket != INVALID_SOCKET)
{
//============================================================
// 接收数据
POVERLAPPEDPLUS pOverlap = CreateOverlappedPlus(IORead);
if (pOverlap == NULL) {
continue;
}

ULONG ulFlags = 0;
int nRetVal = WSARecv(lpClientContext->socket,
&lpClientContext->wsaRecvBuf, 1, &dwIoSize,
&ulFlags, &pOverlap->m_ol, NULL);
if (nRetVal == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError())
{
// 接收数据失败,关闭客户连接
pThis->DelUser(lpClientContext);
DestroyOverlappedPlus(pOverlap);
continue;
}
}
}

if(pOverlapPlus)
DestroyOverlappedPlus(pOverlapPlus);

// 工作线程的数量减 1
InterlockedDecrement(&pThis->m_nWorkerCounts);
return 0;
}

void LUdpTranser::OnClientReading(HIOCP pContext, DWORD dwIoSize /* = 0 */)
{
if (dwIoSize == 0) {
DelUser(pContext);
return;
}

OnReceive(pContext->wsaRecvBuf.buf, dwIoSize);
}

bool LUdpTranser::SendData(HIOCP hUser, pbyte pbData, dword dwSize)
{
/*#########################*/ START_CATCH() /*##########################*/
if (hUser == NULL || hUser->socket == INVALID_SOCKET) {
return false;
}

//////////////////////////////////////////////////////////////////////
// 开始发送
int nSentBytes; // 本次已经发送的字节数
while (dwSize) { // 一直等到数据发送完毕
nSentBytes = sendto(hUser->socket, pbData, dwSize, 0, &hUser->saPeer,
socksize);
if (nSentBytes > 0) {
pbData += nSentBytes;
dwSize -= nSentBytes;
} else if (nSentBytes == 0 || WSAGetLastError() != WSAEWOULDBLOCK) {
return false;
}
}

return true;
/*#########################*/ END_CATCH() /*##########################*/
}

bool LUdpTranser::SendData(HIOCP hUser, DWORD dwData)
{
return SendData(hUser, (pbyte)&dwData, sizeof(dwData));
}

void LUdpTranser::SendDataToAllUsers(pbyte pbData, dword dwSize)
{
HIOCP hUser = m_UsedLister;
while (hUser) {
SendData(hUser, pbData, dwSize);
hUser = hUser->pNextIOCP;
}
}

void LUdpTranser::SendDataToAllUsers(DWORD dwData)
{
SendDataToAllUsers((pbyte)&dwData, sizeof(dwData));
}

//========================================================================
// 断开客户连接,注意:需要防止线程池中正在使用!
bool LUdpTranser::DelUser(HIOCP hUser)
{
/*#########################*/ START_CATCH() /*##########################*/
if (hUser == NULL || hUser->socket == INVALID_SOCKET) {
return false;
}

// 得到用户的网络套接字,并将用户的网络套接字置为无效状态!
SOCKET tmpSocket = InterlockedExchange((LPLONG)&hUser->socket,
INVALID_SOCKET);
if (tmpSocket == INVALID_SOCKET) {
return false;
}

// 取消 I/O 操作
CancelIo((HANDLE)tmpSocket);

// 一直待到 I/O 操作完成
while(!HasOverlappedIoCompleted((LPOVERLAPPED)hUser))
Sleep(0);

// 关闭网络套接字
closesocket(tmpSocket);

// 从用户列表中删除
EnterCriticalSection(&m_UsedLocker);
if (hUser->pPrevIOCP == NULL) { // 要删除的是列表的第一个用户
m_UsedLister = hUser->pNextIOCP;
} else { // 要删除的是列表中间或尾部的用户
hUser->pPrevIOCP->pNextIOCP = hUser->pNextIOCP;
}

// 如果当前用户后面还有用户,将它向前移
if (hUser->pNextIOCP) {
hUser->pNextIOCP->pPrevIOCP = hUser->pPrevIOCP;
}
LeaveCriticalSection(&m_UsedLocker);

// 添加到空闲列表
EnterCriticalSection(&m_FreeLocker);
hUser->pNextIOCP = m_FreeLister;
m_FreeLister = hUser;
LeaveCriticalSection(&m_FreeLocker);

// 将已连接的用户数量减 1
InterlockedDecrement(&m_nCurrentUsers);

// 通知用户
OnDelUser(hUser);

return true;
/*#########################*/ END_CATCH() /*##########################*/
}

bool LUdpTranser::IsStopping() const
{
return m_bExitThread;
}
chenwhenlong 2004-03-19
  • 打赏
  • 举报
回复
/*************************************************************************
文件名称: LUdpTranser.cpp
创建时间: 2003/11/30 16:26
程序编制: needway

功能描述:
*************************************************************************/
#include "StdAfx.h"
#include "LIOCPServer.h"

//////////////////////////////////////////////////////////////////////////
// UDP 客户数据
struct IOCP {
SOCKET socket; // 网络套接字
WSABUF wsaRecvBuf; // 接收缓冲

IOCP* pPrevIOCP; // 前一个用户
IOCP* pNextIOCP; // 下一个用户
};
const int socksize = sizeof(struct sockaddr_in);
//////////////////////////////////////////////////////////////////////////

LUdpTranser::LUdpTranser() :
m_bExitThread(TRUE),
m_hIOPort(NULL),
m_nWorkerCounts(0),
m_FreeLister(NULL),
m_UsedLister(NULL),
{
InitializeCriticalSection(&m_UsedLocker);
InitializeCriticalSection(&m_FreeLocker);

// 启动网络系统
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
}

LUdpTranser::~LUdpTranser()
{
StopServer(); // 停止服务器
WSACleanup(); // 关闭网络系统

DeleteCriticalSection(&m_UsedLocker);
DeleteCriticalSection(&m_FreeLocker);
}

//========================================================================
// 启动服务器
bool LUdpTranser::StartServer()
{
if (!m_bExitThread) {
return false;
}

// 创建完成端口
m_bExitThread = FALSE;
if (!InitializeIOCP()) {
m_bExitThread = TRUE;
return false;
}

return true;
}

//========================================================================
// 停止服务器
void LUdpTranser::StopServer()
{
if (m_bExitThread) {
return; // 线程池已经退出
}

// 要求线程池开始退出
m_bExitThread = TRUE;

// 等待 KeepAlive 线程退出
WaitForSingleObject(m_hKeeper, INFINITE);
CloseHandle(m_hKeeper);

// 关闭完成端口
CloseCompletionPort();
}

HIOCP LUdpTranser::AddUser(string szAddr, ushort usPort)
{
DWORD dwAddr = inet_addr(szAddr);
if (dwAddr == INADDR_NONE) {
return NULL;
}

if (m_bExitThread) {
return NULL;
}

// 创建网络套接字
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) {
InterlockedDecrement(&m_nCurrentUsers);
return NULL;
}

// 设置发送缓冲区的大小
DWORD maxBytes = 0;
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&maxBytes,
sizeof(maxBytes));

// 获取允许的最大接收缓冲区大小
int maxSend = sizeof(int);
getsockopt(sock,SOL_SOCKET,SO_MAX_MSG_SIZE,(char*)&maxBytes,
&maxSend);

// 设置接收缓冲区的大小
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&maxBytes,
sizeof(maxBytes));

//********************************************************************
// 以下这段代码用于解决 Win2K 互发数据时产生的 10054 错误消息
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
DWORD dwBytesReturned;
BOOL bNewBehavior = FALSE;
WSAIoctl(sock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
NULL, 0, &dwBytesReturned, NULL, NULL);
//********************************************************************

// 检测出本机的哪个 IP 地址可以发送到目的地址
struct sockaddr_in saTarget;
struct sockaddr_in saSource;
memset(&saTarget, 0, socksize);
memset(&saSource, 0, socksize);
saTarget.sin_family = saSource.sin_family = AF_INET;
saTarget.sin_addr.s_addr = dwAddr;
WSAIoctl(sock, SIO_ROUTING_INTERFACE_QUERY, (LPVOID)&saTarget,
socksize, (LPVOID)&saSource, socksize, &dwBytesReturned,
NULL, NULL);

// 绑定端口
struct sockaddr_in saLocal;
saLocal.sin_family = AF_INET;
saLocal.sin_addr.s_addr = saSource.sin_addr.s_addr;
saLocal.sin_port = 0;
if(SOCKET_ERROR == bind(sock, (sockaddr*)&saLocal, sizeof(saLocal)))
{
closesocket(sock);
InterlockedDecrement(&m_nCurrentUsers);
return NULL;
}

HIOCP hUser = NULL;

// 进入空闲列表锁,看看有没有空闲的用户句柄,如果有就使用空闲的,否则
// 就创建一个新的
EnterCriticalSection(&m_FreeLocker);
if (m_FreeLister != NULL) { // 有空闲的用户句柄
hUser = m_FreeLister;
m_FreeLister = m_FreeLister->pNextIOCP;
}
LeaveCriticalSection(&m_FreeLocker);

// 如果空闲列表中没有,创建新的
if (hUser == NULL) {
hUser = (HIOCP)VMAlloc(sizeof(IOCP));
if (hUser == NULL) { // 创建失败
InterlockedDecrement(&m_nCurrentUsers);
closesocket(sock);
return NULL;
}

// 创建成功
hUser->wsaRecvBuf.buf = (pbyte)VMAlloc(maxBytes);
hUser->wsaRecvBuf.len = maxBytes;
if (hUser->wsaRecvBuf.buf == NULL) {
// 无法为用户分配接收缓冲区,释放!
VMFree(hUser);
InterlockedDecrement(&m_nCurrentUsers);
closesocket(sock);
return NULL;
}
}

// 初始化客户数据
hUser->socket = sock;
hUser->dwTime = GetTickCount();

struct sockaddr_in* saTemp = (struct sockaddr_in*)&hUser->saPeer;
saTemp->sin_family = AF_INET;
saTemp->sin_addr.s_addr = dwAddr;
saTemp->sin_port = htons(usPort);

// 给用户分配完成端口
if (m_hIOPort != CreateIoCompletionPort((HANDLE)sock, m_hIOPort,
(DWORD)hUser, 0))
{
InterlockedDecrement(&m_nCurrentUsers);
closesocket(sock);

// 无法为用户分配完成端口,将刚才新创建的添加到空闲列表
EnterCriticalSection(&m_FreeLocker);
hUser->socket = INVALID_SOCKET;
hUser->pNextIOCP = m_FreeLister;
m_FreeLister = hUser;
LeaveCriticalSection(&m_FreeLocker);

return NULL;
}

// 添加到用户列表
EnterCriticalSection(&m_UsedLocker);
if (m_UsedLister != NULL) {
m_UsedLister->pPrevIOCP = hUser;
}
hUser->pNextIOCP = m_UsedLister;
hUser->pPrevIOCP = NULL;
m_UsedLister = hUser;
LeaveCriticalSection(&m_UsedLocker);

// 通知线程池
POVERLAPPEDPLUS pOverlap = CreateOverlappedPlus(IOAccept);
if (pOverlap == NULL) { DelUser(hUser); return NULL; }
BOOL bSuccess = PostQueuedCompletionStatus(m_hIOPort, 0,
(DWORD)hUser, &pOverlap->m_ol);
if ((!bSuccess && GetLastError( ) != ERROR_IO_PENDING)) {
DelUser(hUser);
DestroyOverlappedPlus(pOverlap);
return NULL;
}

return hUser;
}

//========================================================================
// 创建完成端口,并启动线程池
bool LUdpTranser::InitializeIOCP()
{
// 创建一个用于创建完成端口的临时套接字
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == INVALID_SOCKET) {
return false;
}

// 创建完成端口
m_hIOPort = CreateIoCompletionPort((HANDLE)sock,NULL,0,0);
if (m_hIOPort == NULL) {
closesocket(sock);
return false;
}

// 关闭创建的临时套接字
closesocket(sock);

// 获取工作线程的最佳数量
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
UINT nWorkerCnd = sysInfo.dwNumberOfProcessors * 2;

// 创建客户端工作线程
HANDLE hWorker;
UINT nThreadId;
m_nWorkerCounts = 0;
for(UINT n = 0; n < nWorkerCnd; n++)
{
hWorker = make_thread(ThreadPoolProc, this, nThreadId);
if (hWorker == NULL) {
CloseHandle(m_hIOPort);
return false;
}

CloseHandle(hWorker);
}

return true;
}
wanggenggz 2004-03-19
  • 打赏
  • 举报
回复
udp是不需要完成端口的。tcp可以多路io复用。tcp完成端口可以跳出64的限制。udp是面向数据报的。不需要要完成端口,如要做高效。做一个线程收,很多线程处理,通过一个buf来交换。
jzgenius 2004-03-19
  • 打赏
  • 举报
回复
回flinming,VCKBase上面我已经翻遍了,没有关于UDP的说明,或则说我只在网上找到了一个用UDP进行广播的代码,不适用,所以。。。嘿嘿,有别的资料吗?给个代码片断也行啊 :)

回bm1408(嗔!我心己乱,万物皆沉,唯伊也!独醉!),没有收到你的邮件阿,是不是发错了?邮件:rodger_hu@genius-software.com or rodger_hu@pg168.com

再次谢谢回帖的各位,万分感谢!!!

问题解决了就结贴,给大家分 :)
jzgenius 2004-03-19
  • 打赏
  • 举报
回复
可以结贴了,虽然问题没有决定性质的解决,但现在的资料来看,我应该可以做出来了,相信大家看了这个帖子也能有所收获。
这里要感谢以上各位朋友的帮助,也帮助帮我UP的朋友们,非常感谢!!!

以后有问题还要请教大家,以后我们还会见面的 :)
jzgenius 2004-03-18
  • 打赏
  • 举报
回复
回猫头鹰,我已经给你发了邮件了,请查收,或则,直接把Code E-Mail给我,rodger_hu@genius-software.com 谢谢!!!
bm1408 2004-03-18
  • 打赏
  • 举报
回复
前几天写了一个,给你发过去,你看看!

bmm1408@163.com
flinming 2004-03-18
  • 打赏
  • 举报
回复
www.vckbase.com/code
jzgenius 2004-03-18
  • 打赏
  • 举报
回复
各位大侠阿,都露个面啊,帮帮忙了~~~~~ PLS..........
jzgenius 2004-03-17
  • 打赏
  • 举报
回复
回 ydfok,完成端口是Microsoft的输入输出端口的复用机制,用这个能够充分利用计算机的性能,用在网络通讯中,可以加大服务器的网络处理效率。
我也是菜鸟,不知道说得对不对,呵呵
ydfok 2004-03-17
  • 打赏
  • 举报
回复
完成端口?是一个什么概念?
jzgenius 2004-03-17
  • 打赏
  • 举报
回复
回复GeorgeHunter,我已经给你发了邮件,我的名字叫:rodger hu,感谢您的回复,并真心感谢您的帮助!!
jzgenius 2004-03-17
  • 打赏
  • 举报
回复
回潇湘夜雨,vckbase.com上面的东西也翻过了,没有UDP完成端口的资料,至少不完全。。。

可能是我很菜吧,希望能知道怎么用UDP+完成端口发送数据,接受大概知道了,再次谢谢各位!!!
jzgenius 2004-03-17
  • 打赏
  • 举报
回复
网络上关于完成端口的东西翻的差不多了,大多都是TCP的,真的不知道UDP要怎么做 :(
有代码的兄弟姐妹阿,帮帮忙了。。。。。。。。。。
OWLEYE 2004-03-17
  • 打赏
  • 举报
回复
我这而有完成端口的原代码,我现在也是要用完成端口写服务器,vcclass@hotmail.com请与我联系
GeorgeHunter 2004-03-17
  • 打赏
  • 举报
回复
jzgenius(jzgenius)说得很对,对于完成端口的网络应用,可以在《windows网络编程》里找到详细地说明。
GeorgeHunter 2004-03-16
  • 打赏
  • 举报
回复
要代码的e_mail我。icewolf911@163.com
薛定谔之死猫 2004-03-16
  • 打赏
  • 举报
回复
up
加载更多回复(6)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧