IOCP六:UDP 客户端退出
实验过程:
1.线程A在socket s上投递1号WSARecvFrom
2.Client发送"woyougexiaozhinv,kewoburenshita"
3.1号WSARecvFrom接收数据,创建线程B
4.线程B投递2号WSARecvFrom,然后线程A投递3-10号WSARecvFrom
5.线程B每隔两秒发送"nihaihaoma"
6.Client接两次后发送"woyougexiaozhinv,kewoburenshita",然后退出
实验结果:
1.Client最后发送的数据由2号WSARecvFrom接收
2.线程B第三次发送数据,显示:发送成功 影响:3号WSARecvFrom以“ret=false, dwNum=0, GetLastError()=1234, 目标地址”返回
线程B第四次发送数据,显示:发送成功 影响:4号WSARecvFrom以“ret=false, dwNum=0, GetLastError()=1234, 目标地址”返回
线程B第五次发送数据,显示:发送成功 影响:5号WSARecvFrom以“ret=false, dwNum=0, GetLastError()=1234, 目标地址”返回
。。。
实验结论:
用socket s向一个不存在的地址投递WSASendTo,显示:发送成功,结果:在s上等待接收的WSARecvFrom按投递顺序以”ret=false,dwNum=0,GetLastError()=1234,ppiod->clientAddr=目标地址“四参数返回
实验结果图:
实验代码:
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <process.h>
#include <string>
#include <MSWSock.h>
#include <set>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "Mswsock.lib")
#define BUF_LEN 1024
bool flag = true;
enum OperateType
{
OP_RECV,
OP_SEND,
};
typedef struct PER_HANDLE_DATA
{
SOCKET s;
SOCKADDR_IN addr;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
typedef struct PER_IO_DATA
{
OVERLAPPED overlapped;
int no;
char buf[BUF_LEN];
int operationType;
sockaddr clientAddr;
}PER_IO_DATA, *LPPER_IO_DATA;
typedef struct Arg
{
SOCKET s;
sockaddr addr;
}Arg;
SOCKET SocketInitBind()
{
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
if(INVALID_SOCKET == s)
{
std::cout<<"create socket failed : "<<GetLastError()<<std::endl;
return INVALID_SOCKET;
}
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = INADDR_ANY;
addr.sin_port = htons(4444);
int ret = bind(s, (sockaddr*)&addr, sizeof(addr));
if(SOCKET_ERROR == ret)
{
std::cout<<"bind failed : "<<GetLastError()<<std::endl;
return SOCKET_ERROR;
}
return s;
}
bool PostSendTo(SOCKET s, const sockaddr *clientAddr, const char *buf, int len)
{
LPPER_IO_DATA ppiod = new PER_IO_DATA;
ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
ppiod->operationType = OP_SEND;
ppiod->clientAddr = *clientAddr;
ppiod->no = 128;
memset(ppiod->buf, 0, BUF_LEN);
memcpy(ppiod->buf, buf, len);
WSABUF databuf;
databuf.buf = ppiod->buf;
databuf.len = len;
DWORD dwRecv = 0;
DWORD dwFlags = 0;
int ret = WSASendTo(s, &databuf, 1, &dwRecv, dwFlags, clientAddr, sizeof(sockaddr), &ppiod->overlapped, NULL);
if(SOCKET_ERROR == ret && WSA_IO_PENDING != GetLastError())
{
delete ppiod;
return false;
}
return true;
}
bool PostRecvFrom(SOCKET s, int n)
{
LPPER_IO_DATA ppiod = new PER_IO_DATA;
//ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
ZeroMemory(ppiod, sizeof(PER_IO_DATA));
ppiod->operationType = OP_RECV;
ppiod->no = n;
memset(ppiod->buf, 0, BUF_LEN);
WSABUF databuf;
databuf.buf = ppiod->buf;
databuf.len = BUF_LEN;
DWORD dwRecv = 0;
DWORD dwFlags = 0;
int len = sizeof(sockaddr);
int ret = WSARecvFrom(s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->clientAddr, &len, &ppiod->overlapped, NULL);
if(SOCKET_ERROR == ret && WSA_IO_PENDING != GetLastError())
{
delete ppiod;
return false;
}
return true;
}
unsigned int __stdcall Func(void *param)
{
Arg *arg = (Arg*)param;
SOCKET s = arg->s;
sockaddr addr = arg->addr;
PostRecvFrom(s, 2);
while(1)
{
Sleep(2000);
std::string str = "nihaihaoma";
PostSendTo(s, &addr, str.c_str(), str.length());
}
_endthreadex(0);
return 0;
}
unsigned int __stdcall ThreadFunc(void *arg)
{
HANDLE hcp = (HANDLE)arg;
if(NULL == hcp)
{
std::cout<<"thread arg error"<<std::endl;
return -1;
}
DWORD dwNum = 0;
LPPER_HANDLE_DATA pphd;
LPPER_IO_DATA ppiod;
while(true)
{
bool ret = GetQueuedCompletionStatus(hcp, &dwNum, (LPDWORD)&pphd, (LPOVERLAPPED*)&ppiod, WSA_INFINITE);
//线程退出控制,没有释放申请的堆空间,还不完善
if(-1 == dwNum)
{
std::cout<<"Thread Exit"<<std::endl;
_endthreadex(0);
return 0;
}
//错误发生
if(false == ret || 0 == dwNum)
{
std::cout<<"An Error Occurs : "<<GetLastError()<<" no:"<<ppiod->no<<std::endl;
std::cout<<"ret="<<ret<<" dwNum="<<dwNum<<std::endl;
sockaddr_in sin;
memcpy(&sin, &ppiod->clientAddr, sizeof(sin));
std::cout<<"---->To:"<<inet_ntoa(sin.sin_addr)<<" Port:"<<sin.sin_port<<std::endl;
delete(ppiod);
continue;
}
int type = ppiod->operationType;
if(OP_RECV == type)
{
//
std::cout<<"接收完成"<<std::endl;
//
sockaddr_in sin;
memcpy(&sin, &ppiod->clientAddr, sizeof(sin));
char *ip = inet_ntoa(sin.sin_addr);
int port = sin.sin_port;
std::cout<<"From:"<<ip<<" Port:"<<port<<std::endl;
ppiod->buf[dwNum] = '\0';
std::cout<<"Receiver : "<<ppiod->no<<" "<<ppiod->buf<<std::endl;
//只允许进入一次
if(flag)
{
flag = false;
Arg arg;
arg.s = pphd->s;
arg.addr = ppiod->clientAddr;
//测试在s等待接收时,另一线程在s上投递发送会怎样
_beginthreadex(NULL, 0, Func, (void*)&arg, 0, NULL);
//等待子线程成功读取参数
Sleep(500);
//投递3-10号接收请求
for(int i = 3; i < 11; i++)
{
bool ret = PostRecvFrom(pphd->s, i);
if(false == ret)
{
std::cout<<"PostAccept Failed"<<std::endl;
return -1;
}
}
}
delete ppiod;
/*ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));
ZeroMemory(ppiod->buf, BUF_LEN);
ppiod->no = 14;
WSABUF databuf;
databuf.buf = ppiod->buf;
databuf.len = BUF_LEN;
DWORD dwRecv = 0;
DWORD dwFlags = 0;
int len = sizeof(sockaddr);
WSARecvFrom(pphd->s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->clientAddr, &len, &ppiod->overlapped, NULL);*/
}
else if(OP_SEND == type)
{
//
std::cout<<"发送完成"<<std::endl;
//
sockaddr_in sin;
memcpy(&sin, &ppiod->clientAddr, sizeof(sin));
std::cout<<"To:"<<inet_ntoa(sin.sin_addr)<<" Port:"<<sin.sin_port<<std::endl;
delete ppiod;
}
}
return 0;
}
int main()
{
WSADATA ws;
if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)
{
std::cout<<"WSAStartup error : "<<GetLastError()<<std::endl;
return -1;
}
HANDLE hcp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if(NULL == hcp)
{
std::cout<<"create completion port failed : "<<GetLastError()<<std::endl;
return -1;
}
std::set<HANDLE> setWorkers;
SYSTEM_INFO si;
GetSystemInfo(&si);
for(int i = 0; i < si.dwNumberOfProcessors * 2 + 2; i++)
{
HANDLE worker = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)hcp, 0, NULL);
if(NULL == worker)
{
std::cout<<"create thread failed : "<<GetLastError()<<std::endl;
return -1;
}
setWorkers.insert(worker);
}
SOCKET s = SocketInitBind();
if(INVALID_SOCKET == s)
{
std::cout<<"socket init failed"<<std::endl;
return -1;
}
LPPER_HANDLE_DATA pphd = new PER_HANDLE_DATA;
pphd->s = s;
CreateIoCompletionPort((HANDLE)s, hcp, (DWORD)pphd, 0);
//投递编号1接收请求
bool ret = PostRecvFrom(s, 1);
if(false == ret)
{
std::cout<<"PostAccept Failed"<<std::endl;
return -1;
}
//退出控制
/*std::cin.get();
for(int i = 0; i < setWorkers.size(); i++)
PostQueuedCompletionStatus(hcp, -1, NULL, NULL);*/
auto iter = setWorkers.begin();
for(; iter != setWorkers.end(); iter++)
WaitForSingleObject(*iter, INFINITE);
WSACleanup();
std::cin.get();
return 0;
}
#include <stdio.h>
#include <Winsock2.h>
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
int main()
{
WSADATA ws;
if(WSAStartup(MAKEWORD(2, 2), &ws) != 0)
return -1;
sockaddr_in addr;
int len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(4444);
addr.sin_addr.s_addr = inet_addr("192.168.15.14");
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
std::string str = "woyougexiaozhinv,kewoburenshita";
int ret = sendto(s, str.c_str(), str.length(), 0, (sockaddr*)&addr, len);
if (SOCKET_ERROR == ret)
{
std::cout<<"Data Send Fail"<<std::endl;
return -1;
}
char buf[100] = {0};
ret = recvfrom(s, buf, 100, 0, (sockaddr*)&addr, &len);
if(SOCKET_ERROR == ret)
{
std::cout<<"Data Recv Fail"<<std::endl;
return -1;
}
std::cout<<buf<<std::endl;
{
char buf[100] = {0};
ret = recvfrom(s, buf, 100, 0, (sockaddr*)&addr, &len);
if(SOCKET_ERROR == ret)
{
std::cout<<"Data Recv Fail"<<std::endl;
return -1;
}
std::cout<<buf<<std::endl;
std::string str = "woyougexiaozhinv,kewoburenshita";
int ret = sendto(s, str.c_str(), str.length(), 0, (sockaddr*)&addr, len);
if (SOCKET_ERROR == ret)
{
std::cout<<"Data Send Fail"<<std::endl;
return -1;
}
}
closesocket(s);
WSACleanup();
return 0;
}
浙公网安备 33010602011771号