#include<winsock2.h>
#include<stdio.h>
#include<windows.h>
#pragma comment(lib,"WS2_32.lib")
BOOL InsertSock(SOCKET* pSock, SOCKET sock)
{
for (int nIndex = 0; nIndex < FD_SETSIZE - 1; nIndex++)
{
if (pSock[nIndex] == INVALID_SOCKET)
{
pSock[nIndex] = sock;
break;
}
}
if (nIndex == FD_SETSIZE - 1)
return FALSE;
return TRUE;
}
int main(int argc, char* argv[])
{
WSADATA wsaData;
WORD sockVersion=MAKEWORD(2,0);
WSAStartup(sockVersion,&wsaData);
SOCKET clientsockarray[FD_SETSIZE - 1];
SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s==INVALID_SOCKET)
{
printf(" Failed socket()/n");
WSACleanup();
return 0;
}
sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(8888);
sin.sin_addr.S_un.S_addr=INADDR_ANY;
if(bind(s,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
{
printf(" Failed bind() %d/n",GetLastError());
WSACleanup();
return 0;
}
if(listen(s,63)==SOCKET_ERROR)
{
printf(" Failed listen()/n");
WSACleanup();
return 0;
}
for (int i=0;i < 64; i++)
{
clientsockarray[i] = INVALID_SOCKET;
}
sockaddr_in remoteAddr;
int nAddrLen=sizeof(remoteAddr);
//char szText[]="Hello World!";
FD_SET fd;
FD_ZERO(&fd);
TIMEVAL tv={30,0};
FD_SET(s,&fd);
printf("server start:%d/n",GetLastError());
int num=0;
while(TRUE)
{
int nResult;
nResult = select(0,&fd, NULL,NULL,&tv);
if (nResult == SOCKET_ERROR)
{
printf("select failed /n");
continue;
}
/*
if (nResult > 0)
{
printf("dddddddddd/n");
}
*/
if(FD_ISSET(s,&fd))
{
SOCKET client;
client=accept(s,(SOCKADDR*)&remoteAddr,&nAddrLen);
if (client == INVALID_SOCKET)
{
printf("client connect fail %d",GetLastError());
continue;
}
if(!InsertSock(clientsockarray,client))
{
printf("³¬¹ý×î´óSOCKET/n");
closesocket(client);
continue;
}
FD_SET(client,&fd);
}
// Öð¸ö´¦Àí´¦ÓÚ´ý¾ö״̬µÄÌ×½Ó×Ö
nResult = select(0,&fd, NULL,NULL,&tv);
if (nResult == SOCKET_ERROR)
{
printf("select failed /n");
continue;
}
for (int nIndex = 0; nIndex <= FD_SETSIZE - 1; nIndex++)
{
if(FD_ISSET(clientsockarray[nIndex], &fd))
{
//printf("aaaa/n");
char buffer[256];
int nRet = recv(clientsockarray[nIndex], buffer, sizeof(buffer), 0);
if (nRet == 0 || nRet == SOCKET_ERROR)
{
closesocket(clientsockarray[nIndex]);
clientsockarray[nIndex] = INVALID_SOCKET;
continue; // ¼ÌÐø´¦ÀíÌ×½Ó×Ö¾ä±úÊý×éÖеÄÆäËüÌ×½Ó×Ö
}
// ½«½ÓÊܵ½µÄÊý¾Ý½øÐд¦Àí,´Ë´¦Ö»½«ÆäÊä³ö
//char buffer[256];
//recv(clientsockarry[nIndex],buffer,256);
printf("has recv data from socket %d : %s",i, buffer);
printf(" num:%d/n",++num);
}
}
}
closesocket(s);
WSACleanup();
return 0;
}
附一个例子,,
下面这段代码是一个建立在SELECT这是I/O模型的多连接应用。能正常工作。
但有些问题。就是在接受2或更多连接后,当接收这些连接发送的数据时总发生,不稳定的情况。
例如;
当接受3个连接后。
1连接发送数据 11111。
显示 11111。
2连接发送 22222。
显示 22222
空跑一个。
3连接发送 33333。
显示则是
3
3
3
3
3跑了5回,是分着接收的数据。
我不明白为什么,到后来程序变得不稳定了?
为什么一条数据总要,一个字节一个字节的接送?
为什么总发送空接收的现象?
是哪个地方没处理好呢?
代码如下:
// select I/O模型
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "WS2_32")
int ret;
int main()
{
USHORT nPort = 12345; // 此服务器监听的端口号
WSADATA wsaData;
if(WSAStartup(0x0202,&wsaData) != 0)
{
printf("wsastartup error !/n");
getchar();
return 0;
}
// 创建监听套节字
SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
// 绑定套节字到本地机器
if(bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf(" Failed bind() /n");
return 0;
}
if(listen(sListen, 5))
{
printf("listen error !/n");
getchar();
return 0;
}
//-------------------------------------------------看来这个模式的设置有必要的。
ULONG NonBlock = 1;
if (ioctlsocket(sListen, FIONBIO, (u_long *)&NonBlock) == SOCKET_ERROR)
{
printf("ioctlsocket() failed with error %d/n", WSAGetLastError());
getchar();
return 0;
}
//----------------------------------------------------
// select模型处理过程
// 1)初始化一个套节字集合fdSocket,添加监听套节字句柄到这个集合
fd_set fdSocket; // 所有可用套节字集合
FD_ZERO(&fdSocket);
FD_SET(sListen, &fdSocket);
while(TRUE)
{
ret = printf("/n big while -----------------------!/n");
// 2)将fdSocket集合的一个拷贝fdRead传递给select函数,
// 当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
fd_set fdRead = fdSocket;
int nRet = select(0, &fdRead, NULL, NULL, NULL);
if(nRet > 0)
{
// 3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
// 确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
for(int i=0; i<(int)fdSocket.fd_count; i++)
{
ret = printf("/n big for !/n");
if(FD_ISSET(fdSocket.fd_array[i], &fdRead))
{
if(fdSocket.fd_array[i] == sListen) // (1)监听套节字接收到新连接
{
if(fdSocket.fd_count < FD_SETSIZE)
{
sockaddr_in addrRemote;
int nAddrLen = sizeof(addrRemote);
SOCKET sNew = ::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen);
FD_SET(sNew, &fdSocket);
printf("接收到连接(%s)/n", ::inet_ntoa(addrRemote.sin_addr));
}
else
{
printf(" Too much connections! /n");
continue;
}
}
else
{
char szText[256];
int nRecv = ::recv(fdSocket.fd_array[i], szText, sizeof(szText), 0);
if(nRecv > 0) // (2)可读
{
szText[nRecv] = '/0';
printf("接收到数据:%s /n", szText);
}
else // (3)连接关闭、重启或者中断
{
::closesocket(fdSocket.fd_array[i]);
FD_CLR(fdSocket.fd_array[i], &fdSocket);
}
}
}
}
}
else
{
printf(" Failed select() /n");
break;
}
}
return 0;
}