之前, 我们简要第了解了一下非阻塞的socket。 在本文中, 我们让服务端用非阻塞socket, 客户端依然用我们熟悉的阻塞的socket.
服务端程序如下(非阻塞的socket):
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
// 网络初始化
WSADATA wsd;
WSAStartup(MAKEWORD(2,2), &wsd);
// 默认为阻塞socket
SOCKET sServer = socket(AF_INET,SOCK_STREAM, 0);
// 设置为非阻塞socket
int iMode = 1;
ioctlsocket(sServer, FIONBIO, (u_long FAR*)&iMode);
// 设置服务器套接字地址
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(8888);
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(sServer,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN));
// 用耳朵听听
listen(sServer, 5);
// 接受客户请求
printf("accept\n");
sockaddr_in addrClient;
int len = sizeof(addrClient);
SOCKET sClient = 0;
while(1)
{
sClient = accept(sServer,(sockaddr FAR*)&addrClient, &len);
if(INVALID_SOCKET == sClient)
{
int err = WSAGetLastError();
if(WSAEWOULDBLOCK == err) // 没有客户端来connect
{
Sleep(100);
continue;
}
// 其实这里还应该考虑一下异常比较好
}
printf("accept ok\n");
break;
}
int iRet = -1;
while(1)
{
char szRecvBuf[100] = {0};
iRet = recv(sClient, szRecvBuf, sizeof(szRecvBuf), 0);
if(SOCKET_ERROR == iRet)
{
int err = WSAGetLastError();
if(WSAEWOULDBLOCK == err) // 接收socket对应的内核缓冲区中暂时没有数据
{
Sleep(100);
continue;
}
// 这里考虑一下异常比较好
}
printf("%s\n", szRecvBuf);
break;
}
// 网络释放
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return 0;
}
运行程序, 开启服务端进程。
下面, 我们看看客户端的程序(阻塞的socket):
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup( wVersionRequested, &wsaData );
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8888);
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
send(sockClient, "hello world", strlen("hello world") + 1, 0);
closesocket(sockClient);
WSACleanup();
return 0;
}
运行该程序。
服务端进程打印的结果为:
accept
accept ok
hello world
最后, 根据实践的结果, 我不得不在这里强调一下: 服务端的recv函数是否阻塞, 并不取决于客户端的sockClient是否是阻塞式的, 而是取决于服务端的sServer是否为阻塞式的, 所以, 上面服务端的recv并不会阻塞。
好, 本文我们就先学到这里。