该模型的作用是解决recv和send函数死等的问题,也就是解决这两个函数一定要接或者收到消息才可以执行其它代码的问题,主要作用在tcp/ip协议中,在udp/ip协议的作用并不明显,因为udp/ip协议不是面向链接的,所有socket是只有一个的。
##模型代码,代码和tcp/ip协议中select模型很像,并且更简单
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
SOCKET socketServer;
BOOL WINAPI handlectr(DWORD dwTybe)
{
switch (dwTybe)
{
case CTRL_CLOSE_EVENT:
closesocket(socketServer);
WSACleanup();
break;
}
return FALSE;
}
int main()
{
SetConsoleCtrlHandler(handlectr, TRUE);
//第一步 打开网络库 校验版本
WORD wdVersion = MAKEWORD(2, 2);
WSADATA wdSockMsg;
if (0 != WSAStartup(wdVersion, &wdSockMsg))
{
printf("网络库打开失败\n");
return 0;
}
if (2 != HIBYTE(wdSockMsg.wVersion) || 2 != LOBYTE(wdSockMsg.wVersion))
{
WSACleanup();
printf("版本不对\n");
return 0;
}
//第二步 创建socket
socketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (socketServer == INVALID_SOCKET)
{
printf("socket创建失败\n");
WSACleanup();
return 0;
}
//第三步 绑定ip地址和端口号
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
si.sin_port = htons(12345);
if (SOCKET_ERROR == bind(socketServer, (const struct sockaddr*)&si, sizeof(si)))
{
printf("绑定出错\n");
closesocket(socketServer);
WSACleanup();
return 0;
}
//第四步 select
while (1)
{
//1、socket集合创建fd_set
fd_set fd;
FD_ZERO(&fd);
FD_SET(socketServer, &fd);
//2.select查询
TIMEVAL ti;
ti.tv_sec = 3;
ti.tv_usec = 0;
int nRes = select(0, &fd, NULL, NULL, &ti);
if (nRes == 0)
{
//等待超时
continue;
}
else if (nRes == SOCKET_ERROR)
{
//出错
printf("出错\n");
break;
}
//3.查询到了进行处理
else
{
char strbuf[548] = { 0 };
struct sockaddr siClient;
int nLen = sizeof(siClient);
int rNum = recvfrom(socketServer, strbuf, 548, 0, &siClient, &nLen);
if (rNum == SOCKET_ERROR)
{
//出错了
printf("出错了\n");
continue;
}
printf("%s\n", strbuf);
memset(strbuf, 0, 548);
int sNum = sendto(socketServer, "over", sizeof("over"), 0, &siClient, nLen);
if (sNum == SOCKET_ERROR)
{
printf("发送出错\n");
}
}
}
//第五步 收发消息
return 0;
}