什么原因?
上代码:
//////////////////////////////////////////////////////
// select.cpp文件
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.libclass InitWinSock
{
public:
InitWinSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~InitWinSock()
{
::WSACleanup();
}
};
#include <windows.h>
#include <process.h>
InitWinSock theSock;FD_SET g_fdRead;FD_SET g_allSet; //全集SOCKET g_sListen;unsigned long _stdcall ThreadFun(void*)
{
while(1)
{ g_fdRead=g_allSet; timeval timeval; timeval.tv_sec=0;
timeval.tv_usec=0; int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval); printf("%d\n",nRet); if(nRet<=0)
{
Sleep(500);
continue;
} //检测是否有新连接,或者有数据传输
if(FD_ISSET(g_sListen,&g_allSet))
{
SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in); stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen); FD_SET(stmp,&g_allSet); }//可以运行到for 循环中!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(int i=0;i< g_fdRead.fd_count;i++)
{ if(FD_ISSET(g_fdRead.fd_array[i],&g_allSet))
{ SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in);
char buf[200];
ZeroMemory(buf,sizeof(buf));
recv(g_fdRead.fd_array[i],buf,sizeof(buf),0); printf("接受数据为:%s\n",buf);
}
}
Sleep(500); } //end while
return 0;}
int main()
{
USHORT nPort = 9585; // 此服务器监听的端口号 // 创建监听套节字
g_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(g_sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf(" Failed bind() \n");
return -1;
}
// 进入监听模式
::listen(g_sListen, 5); FD_ZERO(&g_allSet); FD_ZERO(&g_fdRead);
FD_SET(g_sListen,&g_allSet); // HANDLE hThread=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL); HANDLE hThread=CreateThread(NULL,0,ThreadFun,0,0,NULL); WaitForSingleObject(hThread,-1); CloseHandle(hThread); return 0;
}问题代码中已经说了for循环是可以进入的,数据就是接受的为空!当只有一个客户端和服务端通信啊,且已经连接上了,
执行了for循环后,没有收到数据(这是第一个问题)
for 循环后,再次进入外层的while循环,此时还会会进入这个if块。if(FD_ISSET(g_sListen,&g_allSet))
{
SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in); stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen); FD_SET(stmp,&g_allSet); }
这个if块是用来检测有新的客户端连接的, 已经连接上了,为什么还会进入? 进入就堵死了。到底是怎么回事啊?
上代码:
//////////////////////////////////////////////////////
// select.cpp文件
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.libclass InitWinSock
{
public:
InitWinSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~InitWinSock()
{
::WSACleanup();
}
};
#include <windows.h>
#include <process.h>
InitWinSock theSock;FD_SET g_fdRead;FD_SET g_allSet; //全集SOCKET g_sListen;unsigned long _stdcall ThreadFun(void*)
{
while(1)
{ g_fdRead=g_allSet; timeval timeval; timeval.tv_sec=0;
timeval.tv_usec=0; int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval); printf("%d\n",nRet); if(nRet<=0)
{
Sleep(500);
continue;
} //检测是否有新连接,或者有数据传输
if(FD_ISSET(g_sListen,&g_allSet))
{
SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in); stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen); FD_SET(stmp,&g_allSet); }//可以运行到for 循环中!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(int i=0;i< g_fdRead.fd_count;i++)
{ if(FD_ISSET(g_fdRead.fd_array[i],&g_allSet))
{ SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in);
char buf[200];
ZeroMemory(buf,sizeof(buf));
recv(g_fdRead.fd_array[i],buf,sizeof(buf),0); printf("接受数据为:%s\n",buf);
}
}
Sleep(500); } //end while
return 0;}
int main()
{
USHORT nPort = 9585; // 此服务器监听的端口号 // 创建监听套节字
g_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(g_sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf(" Failed bind() \n");
return -1;
}
// 进入监听模式
::listen(g_sListen, 5); FD_ZERO(&g_allSet); FD_ZERO(&g_fdRead);
FD_SET(g_sListen,&g_allSet); // HANDLE hThread=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL); HANDLE hThread=CreateThread(NULL,0,ThreadFun,0,0,NULL); WaitForSingleObject(hThread,-1); CloseHandle(hThread); return 0;
}问题代码中已经说了for循环是可以进入的,数据就是接受的为空!当只有一个客户端和服务端通信啊,且已经连接上了,
执行了for循环后,没有收到数据(这是第一个问题)
for 循环后,再次进入外层的while循环,此时还会会进入这个if块。if(FD_ISSET(g_sListen,&g_allSet))
{
SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in); stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen); FD_SET(stmp,&g_allSet); }
这个if块是用来检测有新的客户端连接的, 已经连接上了,为什么还会进入? 进入就堵死了。到底是怎么回事啊?
timeval.tv_usec=500; int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval); printf("%d\n",nRet); if(nRet<=0)
{
Sleep(500);
continue;
} //检测是否有新连接,或者有数据传输
if(FD_ISSET(g_sListen,&g_allSet))
{
SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in); stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen); FD_SET(stmp,&g_allSet); }依然是有问题的,问题一个个的解决吧请你耐心看,麻烦你了啊。1. 我们不说接受数据的问题,只谈accept新连接的问题。这个代码有个逻辑的错误。
假设有个新的连接连接服务器,那么则accept成功(for 循环暂且无视它吧)sleep后,第二次进入while循环了。此时fd_allset中是有g_sListen监听套接字的。导致 FD_SET是成功的, msdn有云:该宏是检测 某个套接字是否在集合中。所以导致进入了if语句,此时到了accept,由于没有新的连接accept堵死了。
结论:非堵塞模型的 select的acccept其实是堵塞函数。想一想也对,如果是非堵塞的话,正常连接,accept的返回值恐怕值得考虑,深思。
如何修改这个问题呢?
(1)去掉FD-SET判断? 怕是去掉也解决不了问题。(2)用FD_SET(g_sListen,fd_read) 替代 FD-SET(g_sListen,g_allset)更是解决不了问题
{
Sleep(500);
continue;
}
看到printft了吧
我只运行服务端,客户端不运行
是可以看到打印的结果的,说明,select是非堵塞
但是隔几分钟后,发现不会打印了,什么原因呢( 我没有开启客户端)
?为什么刚开始 没开启,可以打印,隔几分钟后还不开启,就不打印了??
The maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.
亲,你看还有你结合 2 L的代码,时间已经改了依然有问题。所以这个时间或许有问题,但不是程序致命的问题。
#include <winsock2.h>
#pragma comment(lib, "WS2_32") // 链接到WS2_32.libclass InitWinSock
{
public:
InitWinSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~InitWinSock()
{
::WSACleanup();
}
};
#include <windows.h>
#include <process.h>
InitWinSock theSock;FD_SET g_fdRead;FD_SET g_allSet; //全集SOCKET g_sListen;unsigned long _stdcall ThreadFun(void*)
{
while(1)
{ g_fdRead=g_allSet; timeval timeval;
timeval.tv_sec=1;
timeval.tv_usec=500; int nRet = ::select(0, &g_fdRead, NULL, NULL, &timeval); printf("%d\n",nRet); if(nRet<=0)
{ Sleep(500);
continue;
} //检测是否有新连接,或者有数据传输
if(FD_ISSET(g_sListen,&g_allSet))
{
SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in); stmp=accept(g_sListen,(sockaddr*)&sockadd,&nLen); FD_SET(stmp,&g_allSet); }//可以运行到for 循环中!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(int i=0;i< g_fdRead.fd_count;i++)
{ if(FD_ISSET(g_fdRead.fd_array[i],&g_allSet))
{ SOCKET stmp=NULL;
sockaddr_in sockadd;
int nLen=sizeof(sockaddr_in);
char buf[200];
ZeroMemory(buf,sizeof(buf));
recv(g_fdRead.fd_array[i],buf,sizeof(buf),0); int sdggssdgsd=1; //printf("接受数据为:%s\n",buf);
}
}
Sleep(500); } //end while
return 0;}
int main()
{
USHORT nPort = 9585; // 此服务器监听的端口号 // 创建监听套节字
g_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(g_sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf(" Failed bind() \n");
return -1;
}
// 进入监听模式
::listen(g_sListen, 5); FD_ZERO(&g_allSet); FD_ZERO(&g_fdRead);
FD_SET(g_sListen,&g_allSet); // HANDLE hThread=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL); HANDLE hThread=CreateThread(NULL,0,ThreadFun,0,0,NULL); WaitForSingleObject(hThread,-1); CloseHandle(hThread); return 0;
}1. 当没有客户单连接 的时候,开始程序不会堵塞,会调用printf结果运行几分钟后就会堵塞2. 如果有客户单连接,接收不到数据
"当没有客户单连接 的时候,开始程序不会堵塞,会调用printf结果运行几分钟后就会堵塞"这个说法不对!!!!!我看错了,但是:接收不到数据 这个问题一直没有解决掉。还有只要和客户端连接了,然后 运行几次后,就会死在accept那里!!!!
还有
while(1)
{
g_fdRead=g_allSet; //这啥?
换成这个 FD_ZERO(&g_fdRead);
接受的问题,我猜测是客户端导致的问题:
我发代码:以下是客户端//////////////////////////////////////////////////////////
// TCPClient.cpp文件
#include "common/InitSock.h"
#include <stdio.h>
CInitSock initSock; // 初始化Winsock库int main()
{
// 创建套节字
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(s == INVALID_SOCKET)
{
printf(" Failed socket() \n");
return 0;
}
// 也可以在这里调用bind函数绑定一个本地地址
// 否则系统将会自动安排
// 填写远程地址信息
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(9585);
// 注意,这里要填写服务器程序(TCPServer程序)所在机器的IP地址
// 如果你的计算机没有联网,直接使用127.0.0.1即可
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
printf(" Failed connect() \n");
return 0;
}
else
{
printf(" Success connect() \n");
}
char buf[100];
memset(buf,0,100); strcpy(buf,"hello"); while(1)
{
send(s,buf,100,0);
Sleep(1000); }
// 关闭套节字
::closesocket(s);
return 0;
}
刚才我这里断网,不好意思啊,前辈
已经解决了现在剩下最后一个问题:接受数据为空!!!!buf的内容始终是""可以进入for循环
// Module Name: select.cpp
//
// Description:
//
// This sample illustrates how to develop a simple echo server Winsock
// application using the select() API I/O model. This sample is
// implemented as a console-style application and simply prints
// messages when connections are established and removed from the server.
// The application listens for TCP connections on port 5150 and accepts
// them as they arrive. When this application receives data from a client,
// it simply echos (this is why we call it an echo server) the data back in
// it's original form until the client closes the connection.
//
// Compile:
//
// cl -o select select.cpp ws2_32.lib
//
// Command Line Options:
//
// select.exe
//
// Note: There are no command line options for this sample.
//
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>#define PORT 5150
#define DATA_BUFSIZE 8192typedef struct _SOCKET_INFORMATION {
CHAR Buffer[DATA_BUFSIZE];
WSABUF DataBuf;
SOCKET Socket;
OVERLAPPED Overlapped;
DWORD BytesSEND;
DWORD BytesRECV;
} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;BOOL CreateSocketInformation(SOCKET s);
void FreeSocketInformation(DWORD Index);DWORD TotalSockets = 0;
LPSOCKET_INFORMATION SocketArray[FD_SETSIZE];void main(void)
{
SOCKET ListenSocket;
SOCKET AcceptSocket;
SOCKADDR_IN InternetAddr;
WSADATA wsaData;
INT Ret;
FD_SET WriteSet;
FD_SET ReadSet;
DWORD i;
DWORD Total;
ULONG NonBlock;
DWORD Flags;
DWORD SendBytes;
DWORD RecvBytes;
if ((Ret = WSAStartup(0x0202,&wsaData)) != 0)
{
printf("WSAStartup() failed with error %d\n", Ret);
WSACleanup();
return;
} // Prepare a socket to listen for connections. if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return;
} InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT); if (bind(ListenSocket, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr))
== SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return;
} if (listen(ListenSocket, 5))
{
printf("listen() failed with error %d\n", WSAGetLastError());
return;
} // Change the socket mode on the listening socket from blocking to
// non-block so the application will not block waiting for requests. NonBlock = 1;
if (ioctlsocket(ListenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return;
} while(TRUE)
{
// Prepare the Read and Write socket sets for network I/O notification.
FD_ZERO(&ReadSet);
FD_ZERO(&WriteSet); // Always look for connection attempts. FD_SET(ListenSocket, &ReadSet); // Set Read and Write notification for each socket based on the
// current state the buffer. If there is data remaining in the
// buffer then set the Write set otherwise the Read set. for (i = 0; i < TotalSockets; i++)
if (SocketArray[i]->BytesRECV > SocketArray[i]->BytesSEND)
FD_SET(SocketArray[i]->Socket, &WriteSet);
else
FD_SET(SocketArray[i]->Socket, &ReadSet); if ((Total = select(0, &ReadSet, &WriteSet, NULL, NULL)) == SOCKET_ERROR)
{
printf("select() returned with error %d\n", WSAGetLastError());
return;
} // Check for arriving connections on the listening socket.
if (FD_ISSET(ListenSocket, &ReadSet))
{
Total--;
if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET)
{ // Set the accepted socket to non-blocking mode so the server will
// not get caught in a blocked condition on WSASends NonBlock = 1;
if (ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return;
} if (CreateSocketInformation(AcceptSocket) == FALSE)
return; }
else
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("accept() failed with error %d\n", WSAGetLastError());
return;
}
}
} // Check each socket for Read and Write notification until the number
// of sockets in Total is satisfied. for (i = 0; Total > 0 && i < TotalSockets; i++)
{
LPSOCKET_INFORMATION SocketInfo = SocketArray[i]; // If the ReadSet is ed for this socket then this means data
// is available to be read on the socket. if (FD_ISSET(SocketInfo->Socket, &ReadSet))
{
Total--; SocketInfo->DataBuf.buf = SocketInfo->Buffer;
SocketInfo->DataBuf.len = DATA_BUFSIZE; Flags = 0;
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,
&Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError()); FreeSocketInformation(i);
} continue;
}
else
{
SocketInfo->BytesRECV = RecvBytes; // If zero bytes are received, this indicates the peer closed the
// connection.
if (RecvBytes == 0)
{
FreeSocketInformation(i);
continue;
}
}
}
// If the WriteSet is ed on this socket then this means the internal
// data buffers are available for more data. if (FD_ISSET(SocketInfo->Socket, &WriteSet))
{
Total--; SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;
SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND; if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0,
NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSASend() failed with error %d\n", WSAGetLastError()); FreeSocketInformation(i);
} continue;
}
else
{
SocketInfo->BytesSEND += SendBytes; if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
{
SocketInfo->BytesSEND = 0;
SocketInfo->BytesRECV = 0;
}
}
}
}
}
}BOOL CreateSocketInformation(SOCKET s)
{
LPSOCKET_INFORMATION SI;
printf("Accepted socket number %d\n", s); if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
sizeof(SOCKET_INFORMATION))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return FALSE;
} // Prepare SocketInfo structure for use. SI->Socket = s;
SI->BytesSEND = 0;
SI->BytesRECV = 0; SocketArray[TotalSockets] = SI; TotalSockets++; return(TRUE);
}void FreeSocketInformation(DWORD Index)
{
LPSOCKET_INFORMATION SI = SocketArray[Index];
DWORD i; closesocket(SI->Socket); printf("Closing socket number %d\n", SI->Socket); GlobalFree(SI); // Squash the socket array for (i = Index; i < TotalSockets; i++)
{
SocketArray[i] = SocketArray[i + 1];
} TotalSockets--;
}