基于事件判断io完成
send程序
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable : 4996)
int main()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup 失败\n");
system("pause");
return 1;
}
// 创建 重叠模型的套接字
SOCKET HSocket = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (HSocket == INVALID_SOCKET)
{
printf("WSASocket 失败\n");
WSACleanup();
system("pause");
return -1;
}
//和往常一样创建客户端连接
sockaddr_in SendAddr;
memset(&SendAddr, 0, sizeof(SendAddr));
SendAddr.sin_family = AF_INET;
SendAddr.sin_port = htons(4567); // 服务器端口
SendAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 服务器 IP本地还回地址
if (connect(HSocket, (LPSOCKADDR)&SendAddr, sizeof(SendAddr)) == SOCKET_ERROR)
{
printf("WSASocket 失败\n");
WSACleanup();
system("pause");
return -1;
}
//创建一个初始无信号手动重置的事件对象
WSAEVENT evobj = WSACreateEvent();
//创建一个WSAOVERLAPPED 结构体变量
WSAOVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = evobj;
//保存待传输的数据大小 和数据存储的地址
WSABUF dataBuf;
char msg[] = "网络编程";
dataBuf.buf = msg;
dataBuf.len = strlen(msg) + 1;
//保存实际发送字节数
DWORD sendedBytes = 0;
//开始传输数据
//如果不返回SOCKET_ERROR,说明数据已经传输完成了
if (WSASend(HSocket, &dataBuf, 1, &sendedBytes, 0, &overlapped, NULL) == SOCKET_ERROR)
{ //判断错误码是不是WSA_IO_PENDING,说明数据没有传输完成
if (WSAGetLastError() == WSA_IO_PENDING)
{
puts("正在后台传输数据中");
//永久等待 一个事件
WSAWaitForMultipleEvents(1, &evobj, TRUE, WSA_INFINITE, FALSE);
//事件有信号了,用这个函数获得io处理的结果.如果fwait设置为true,将等待io的完成,函数阻塞;如果设置为false并且调用时io的未完成 ,函数立即返回false
BOOL isok= WSAGetOverlappedResult(HSocket, &overlapped, &sendedBytes, FALSE, NULL);
if(!isok)
{
printf("WSAGetOverlappedResult 失败 %d\n",WSAGetLastError());
}
}
else
{
printf("WSASend 失败 %d\n", WSAGetLastError());
}
}
printf("发送了%d 个字节\n", sendedBytes);
WSACloseEvent(evobj);
closesocket(HSocket);
WSACleanup();
return 0;
}
recvicer程序
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable : 4996)
#define BUFFER_SIZE 1024
int main(int argc, char* argv[])
{
WSADATA initsock;
if (WSAStartup(MAKEWORD(2, 2), &initsock) != 0)
{
printf("WSAStartup失败 ");
return -1;
}
//创建重叠模型套接字
SOCKET s = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (s == INVALID_SOCKET)
{
printf("socket失败");
return -1;
}
#pragma region 经典起手式 设置端口和ip 并绑定服务器套接字,进入监听,并允许连接
//设置ip和端口
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(4567);
servAddr.sin_addr.S_un.S_addr = INADDR_ANY;
//绑定套接字
if (bind(s, (LPSOCKADDR)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
{
printf("bind失败");
closesocket(s);
WSACleanup();
return -1;
}
//进入监听
if (listen(s, 5) == SOCKET_ERROR)
{
printf("listen失败%d\n",WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
sockaddr_in clintAddr;
int lenOfclintAddr= sizeof(clintAddr);
SOCKET hClintSock = accept(s, (LPSOCKADDR)&clintAddr, &lenOfclintAddr);
if (hClintSock == INVALID_SOCKET)
{
printf("accept失败%d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
#pragma endregion
//创建手动重置初始无信号的事件对象,将地址保存到OVERLAPPED结构变量中
WSAEVENT evObj = WSACreateEvent();
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = evObj;
//保存数据的缓冲区
WSABUF dataBuf;
char buf[BUFFER_SIZE] = { 0 };
dataBuf.len = BUFFER_SIZE;
dataBuf.buf = buf;
//WSARecv函数返回时,接收的数据字节数
DWORD recvBytes = 0;
//传输特性
DWORD flags = 0;
if (WSARecv(hClintSock, &dataBuf, 1, &recvBytes, &flags, &overlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() == WSA_IO_PENDING)
{
puts("后台接收数据中");
WSAWaitForMultipleEvents(1, &evObj, true, WSA_INFINITE, false);
WSAGetOverlappedResult(hClintSock, &overlapped, &recvBytes, FALSE, NULL);
}
else
{
printf("WSARecv失败%d\n", WSAGetLastError());
WSACloseEvent(evObj);
closesocket(s);
WSACleanup();
return -1;
}
}
printf("接收到消息:%s\n", buf);
WSACloseEvent(evObj);
closesocket(s);
WSACleanup();
return 0;
}
基于apc的回调函数通知io完成 的recvicer
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma warning(disable : 4996)
#define BUFFER_SIZE 1024
//WSARecv函数返回时,接收的数据字节数
DWORD g_recvBytes = 0;
char g_buf[BUFFER_SIZE];
void CompRoutine(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
int main(int argc, char* argv[])
{
WSADATA initsock;
if (WSAStartup(MAKEWORD(2, 2), &initsock) != 0)
{
printf("WSAStartup失败 ");
system("pause");
return -1;
}
//创建重叠模型套接字
SOCKET s = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (s == INVALID_SOCKET)
{
printf("socket失败");
system("pause");
return -1;
}
#pragma region 经典起手式 设置端口和ip 并绑定服务器套接字,进入监听,并允许连接
//设置ip和端口
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(4567);
servAddr.sin_addr.S_un.S_addr = INADDR_ANY;
//绑定套接字
if (bind(s, (LPSOCKADDR)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
{
printf("bind失败");
closesocket(s);
WSACleanup();
system("pause");
return -1;
}
//进入监听
if (listen(s, 5) == SOCKET_ERROR)
{
printf("listen失败%d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
system("pause");
return -1;
}
sockaddr_in clintAddr;
int lenOfclintAddr = sizeof(clintAddr);
SOCKET hClintSock = accept(s, (LPSOCKADDR)&clintAddr, &lenOfclintAddr);
if (hClintSock == INVALID_SOCKET)
{
printf("accept失败%d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
system("pause");
return -1;
}
#pragma endregion
//这个事件只是为了让当前线程进入可警报状态
WSAEVENT evObj = WSACreateEvent();
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
//保存数据的缓冲区
WSABUF dataBuf;
dataBuf.len = BUFFER_SIZE;
dataBuf.buf = g_buf;
//传输特性
DWORD flags = 0;
if (WSARecv(hClintSock, &dataBuf, 1, &g_recvBytes, &flags, &overlapped,(LPWSAOVERLAPPED_COMPLETION_ROUTINE)CompRoutine) == SOCKET_ERROR)
{
if (WSAGetLastError() == WSA_IO_PENDING)
{
puts("后台接收数据中");
}
}
//只是为了假装自己进入了等待状态,,,,,APC函数将唤醒 这个线程
//因为我在等待
/*DWORD ret=WSAWaitForMultipleEvents(1, &evObj, FALSE, WSA_INFINITE, TRUE);
if (ret == WAIT_IO_COMPLETION)
{
printf("io传输已完成");
}*/
DWORD ret = SleepEx(INFINITE, TRUE);
if (ret == WAIT_IO_COMPLETION)
{
printf("io传输已完成");
}
WSACloseEvent(evObj);
closesocket(s);
WSACleanup();
system("pause");
return 0;
}
//本程序 将会由于调用约定错误 而引发c0005异常
// vs中设置的调用约定默认为 __cdecl (/Gd)
void CompRoutine(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
)
{
if (dwError!=0)
{
printf("完成回调函数失败\n");
}
else
{
g_recvBytes = cbTransferred;
printf("接收到的消息:%s",g_buf);
}
}