我想做一个C/S模式的小游戏,打算使用socket通信,客户端需要不断的扫描看看有没有服务器发送来的数据。我现在起了一个线程去监听是不是有发送来的数据(是一个死循环)大致代码如下:
while(true)
{
recv(……);
if(strcmp(csRecvMsg , "") == 0)
do sth.
}
可是我发现这样的系统资源会被大量的消耗。
请问各位有没有什么好办法既能扫描数据,又不消耗资源?
有代码更好,THANKS!!!
while(true)
{
recv(……);
if(strcmp(csRecvMsg , "") == 0)
do sth.
}
可是我发现这样的系统资源会被大量的消耗。
请问各位有没有什么好办法既能扫描数据,又不消耗资源?
有代码更好,THANKS!!!
为了解决这么问题,Microsoft提供了几个宏,FD_SET,FD_WRITE,FD_READ等来检查,这些资料在一般的winsock编程的电子书里面都有,建议去看看,或许能解决你的问题。
{
recv(……);
if(strcmp(csRecvMsg , "") == 0)
do sth.
}
死循环,把资源都占掉了
当然可以设为把socket非阻塞,或者换成异步模式
实现asynchronism
#include <windows.h>
#include <winsock.h>typedef struct
{
int a,b;
int res;
}PARAM;DWORD CALLBACK ServiceThread(LPVOID p)
{
SOCKET sock = (SOCKET)p;
PARAM param;
int size;
int len,recvlen,sendlen;
size = sizeof(PARAM); while (true)
{
//接收客户数据
recvlen = 0;
while (recvlen != size)
{
len = recv(sock,((char *)¶m) + recvlen,size - recvlen,0);
if (len != SOCKET_ERROR)
recvlen += len;
else
{
printf("receive error: %d\n",WSAGetLastError());
closesocket(sock);
return 0;
}
}
if (param.a == 0 && param.b == 0)//两个数都为零表示退出
{
printf("A Client Leave\n");
closesocket(sock);
return 0;
}
param.res = param.a + param.b;
//发送处理结果
sendlen = 0;
while (sendlen != size)
{
len = send(sock,(char *)¶m + sendlen,size - sendlen,0);
if (len != SOCKET_ERROR)
sendlen += len;
else
{
printf("send error: %d\n",WSAGetLastError());
closesocket(sock);
return 0;
}
}
}
}int main(int argc, char* argv[])
{
SOCKET server,client;
SOCKADDR_IN addr;
int addrlen;
DWORD dwID; WSADATA WSAData;
if (WSAStartup(MAKEWORD(2,0),&WSAData))
{
printf("Errot to Start WinSock!\n");
return 0;
}
addrlen = sizeof(SOCKADDR_IN); server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = INADDR_ANY;
addr.sin_port = 8000;;
bind(server,(SOCKADDR *)&addr,sizeof(SOCKADDR_IN));
listen(server,10);
printf("Listening......");
while (true)
{
client = accept(server,(SOCKADDR *)&addr,&addrlen);
if (client != INVALID_SOCKET)
{
printf("\nAccept a client");
CreateThread(NULL,0,ServiceThread,(LPVOID)client,0,&dwID);
}
Sleep(100);
}
WSACleanup();
return 0;
}
客户端代码:
#include <windows.h>
#include <winsock.h>typedef struct
{
int a,b;
int res;
}PARAM;int main(int argc, char* argv[])
{
SOCKET client;
SOCKADDR_IN addr;
PARAM param;
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2,0),&WSAData))
{
printf("Errot to Start WinSock!\n");
return 0;
}
client = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_port = 8000;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
printf("Connecting......");
if (SOCKET_ERROR != connect(client,(SOCKADDR *)&addr,sizeof(SOCKADDR_IN)))
{
printf("OK!\n");
while (true)
{
printf("Enter a & b(0 & 0 to Exit): ");
scanf("%d%d",¶m.a,¶m.b); send(client,(char *)¶m,sizeof(PARAM),0);
if (param.a == 0 && param.b == 0) break;
recv(client,(char *)¶m,sizeof(PARAM),0);
printf("Server Reply: %d\n",param.res);
}
}
else
printf("Failed!\n");
closesocket(client);
WSACleanup();
return 0;
}
说明:客户端连接到服务器后,发送两个整数给服务器,服务器求出它们的和,返回给客户端。
服务器对每个客户使用一个服务线程。
异步模式例子:客户端代码不变,服务器代码:
#include <windows.h>
#include <winsock2.h>#define MAX_CLIENT 64typedef struct _CLIENT
{
int no;
SOCKET sock;
HANDLE hEvent;
}CLIENT;typedef struct
{
int a,b;
int res;
}PARAM;BOOL ProcessClientRequest(SOCKET sock)
{
PARAM param;
int size;
int len,recvlen,sendlen;
size = sizeof(PARAM);
//接收客户数据
recvlen = 0;
while (recvlen != size)
{
len = recv(sock,((char *)¶m) + recvlen,size - recvlen,0);
if (len != SOCKET_ERROR)
recvlen += len;
else
{
printf("receive error: %d\n",WSAGetLastError());
closesocket(sock);
return FALSE;
}
}
if (param.a == 0 && param.b == 0)//两个数都为零表示退出
{
printf("A Client Leave\n");
closesocket(sock);
return TRUE;
}
param.res = param.a + param.b;
//发送处理结果
sendlen = 0;
while (sendlen != size)
{
len = send(sock,(char *)¶m + sendlen,size - sendlen,0);
if (len != SOCKET_ERROR)
sendlen += len;
else
{
printf("send error: %d\n",WSAGetLastError());
closesocket(sock);
return FALSE;
}
}
return TRUE;
}int main(int argc, char* argv[])
{
SOCKET server,clientsock;
SOCKADDR_IN addr;
int addrlen; int i,nClient;
DWORD dwWaitResult;
HANDLE hEvent[MAX_CLIENT];
CLIENT client[MAX_CLIENT];
WSADATA WSAData; if (WSAStartup(MAKEWORD(2,0),&WSAData))
{
printf("Errot to Start WinSock!\n");
return 0;
}
addrlen = sizeof(SOCKADDR_IN); server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = INADDR_ANY;
addr.sin_port = 8000;;
bind(server,(SOCKADDR *)&addr,sizeof(SOCKADDR_IN));
nClient = 1; //第一个Client实际上指服务监听套接字
hEvent[0] = CreateEvent(NULL,FALSE,FALSE,NULL);
WSAEventSelect(server,hEvent[0],FD_ACCEPT);
listen(server,10);
printf("Listening......");
while (true)
{
dwWaitResult = ::WaitForMultipleObjects(nClient,hEvent,FALSE,10);
if (dwWaitResult >= WAIT_OBJECT_0 && dwWaitResult < WAIT_OBJECT_0 + nClient)
{
int no;
no = dwWaitResult - WAIT_OBJECT_0;
if (no == 0)
{
clientsock = accept(server,(SOCKADDR *)&addr,&addrlen);
if (clientsock != INVALID_SOCKET)
{
client[nClient].no = nClient;
client[nClient].sock = clientsock;
client[nClient].hEvent = hEvent[nClient] = CreateEvent(NULL,FALSE,FALSE,NULL);
WSAEventSelect(clientsock,client[nClient].hEvent,FD_READ);
nClient++;
printf("\nAccept a client");
}
}
else
{
clientsock = client[no].sock;
ProcessClientRequest(clientsock);
}
}
} for(i = 0; i < nClient; i++)
{
CloseHandle(client[i].hEvent);
closesocket(client[i].sock);
}
WSACleanup();
return 0;
}说明:从上面的线程解决方法修改而来,实现同样的功能。有数据可读的时候,系统触发一个事件。
程序只需要等待事件就行了。