<winsock>重叠IO模型

 基于事件判断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);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值