关于select

z75050429 2008-12-16 11:33:27
// MUD Programming
// Ron Penton
// (C)2003
// Demo02-03.cpp - Hello Internet! Server v2
// This program will start up a server on port 4000, listen for connections,
// receive data until the other side quits, and then close the connection, and
// wait for more data; all the while simulation other game functions.


// Code Block 2.1 - Header Includes
// This code block includes all of the standard Sockets API/Winsock headers
#ifdef WIN32 // windows 95 and above
#include "winsock2.h"
#include "Ws2tcpip.h"

#else // UNIX/Linux
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
// End Code Block 2.1 - Header Includes



// Code Block 2.2 - Redefinitions and globals For Cross-Compatibility
#ifdef WIN32 // windows 95 and above
WSADATA g_wsadata; // winsock data holder
#define CloseSocket closesocket
#define GetSocketError WSAGetLastError
#define StartSocketLib WSAStartup( MAKEWORD( 2, 2 ), &g_wsadata );
#define CloseSocketLib WSACleanup();

#ifndef socklen_t
typedef int socklen_t;
#endif
#else // Unix/Linux
#define CloseSocket close
#define GetSocketError errno
#define StartSocketLib {}
#define CloseSocketLib {}
#endif

// End Code Block 2.2 - Redefinitions and globals For Cross-Compatibility



#include <iostream> // load the iostream library
#include <vector>
#include <string.h> // for string manipulations
using namespace std; // use the std namespace


int main()
{
int err; // for getting errors
int lsock; // listening socket
vector<int> socketlist; // list of sockets

// start the socket library
StartSocketLib;

// BEGIN CODE BLOCK 2.3 - Create a Listening Socket on port 4000
// create a socket
lsock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

// check if socket was created
if( lsock == -1 )
{
cout << "Socket creation error!" << endl;
return 0;
}
cout << "Socket created!" << endl;

// create a sockaddr_in for binding, listening on port 4000
struct sockaddr_in socketaddress;
socklen_t sa_size = sizeof( struct sockaddr_in );
socketaddress.sin_family = AF_INET;
socketaddress.sin_port = htons( 4000 );
socketaddress.sin_addr.s_addr = htonl( INADDR_ANY );
memset( &(socketaddress.sin_zero), 0, 8 );

// bind the socket
err = bind( lsock, (struct sockaddr*)&socketaddress, sa_size );

if( err == -1 )
{
cout << "Socket binding error!" << endl;
return 0;
}
cout << "Socket bound!" << endl;


// listen on the socket
err = listen( lsock, 16 );

if( err == -1 )
{
cout << "Socket listening error!" << endl;
return 0;
}
cout << "Socket listening, waiting for connection..." << endl;
// END CODE BLOCK 2.3 - Create a Listening Socket on port 4000


fd_set rset;
int i;

struct timeval zerotime;
zerotime.tv_usec = 0;
zerotime.tv_sec = 0;

char buffer[128]; // used for getting messages
bool done = false; // used for quitting
vector<int>::iterator itr;

// now begin the main loop.
while( !done )
{
// clear the set
FD_ZERO( &rset );

// add the listening socket
FD_SET( lsock, &rset );

// add all of the data sockets
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{
FD_SET( *itr, &rset );
}

// find out if there is any activity on any of the sockets.
i = select( 128, &rset, NULL, NULL, &zerotime );

if( i > 0 )
{
if( FD_ISSET( lsock, &rset ) )
{
// incomming connection
cout << "Incomming connection..." << endl;
int dsock = accept( lsock,
(struct sockaddr*)&socketaddress,
&sa_size );
if( dsock == -1 )
{
cout << "Socket accepting error!" << endl;
return 0;
}
cout << "Socket " << dsock << " accepted." << endl;

// add the socket to the list
socketlist.push_back( dsock );
}

// loop through each socket and see if it has any activity
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{
if( FD_ISSET( *itr, &rset ) )
{
// incomming data
cout << "receiving data from socket ";
cout << *itr << "..." << endl;
err = recv( *itr, buffer, 128, 0 );

if( err == -1 )
{
cout << "Socket receiving error!" << endl;
return 0;
}
if( err == 0 )
{
cout << "Socket " << *itr << " closed" << endl;
shutdown( *itr, 2 );
CloseSocket( *itr );
socketlist.erase( itr );
itr--;
}
else
{

cout << "Data: " << buffer << endl;

// if the message was "servquit", then quit the server.
if( strcmp( buffer, "servquit" ) == 0 )
done = true;
}
}
}
}

}


shutdown( lsock, 2 );
CloseSocket( lsock );

for( i = 0; i < socketlist.size(); i++ )
{
shutdown( socketlist[i], 2 );
CloseSocket( socketlist[i] );
}

CloseSocketLib;
}
while( !done )内的请解释下下··谢谢







...全文
227 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
rabbii 2008-12-18
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 scott_1987 的回复:]
好长,新手刚学!心有力而力不足啊!
[/Quote]
up~~~
caremsi 2008-12-16
  • 打赏
  • 举报
回复
FD_ZERO( &rset ); //把rset这个文件描述符集置0
// add the listening socket
FD_SET( lsock, &rset ); //添加lsock到rset这个文件描述符集

// add all of the data sockets
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{
FD_SET( *itr, &rset ); //同上
}

// find out if there is any activity on any of the sockets.
i = select( 128, &rset, NULL, NULL, &zerotime ); //select我的理解类似于激活开始判断文件描述集的状况

if( i > 0 )
{
if( FD_ISSET( lsock, &rset ) ) //当lsock有变化,则进入到if里的继续
就呆在云上 2008-12-16
  • 打赏
  • 举报
回复


建议你去看看unix环境高级编程里面说的非常的清楚了
select的使用
他获取等待的文件描述符,得到后返回
超时返回
等等
artwl_cn 2008-12-16
  • 打赏
  • 举报
回复
帮顶!
lq20051610211 2008-12-16
  • 打赏
  • 举报
回复
oh, my god~
hityct1 2008-12-16
  • 打赏
  • 举报
回复
不是有英语注释了吗?
星羽 2008-12-16
  • 打赏
  • 举报
回复
so long
太乙 2008-12-16
  • 打赏
  • 举报
回复
upup
bitwwzhang130 2008-12-16
  • 打赏
  • 举报
回复
太长了,慢慢看
hhyttppd 2008-12-16
  • 打赏
  • 举报
回复

// now begin the main loop.
while( !done ) //查看__{Quit}__处
{
// clear the set
FD_ZERO( &rset );

// add the listening socket
FD_SET( lsock, &rset );

// add all of the data sockets
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{
FD_SET( *itr, &rset );
}

// find out if there is any activity on any of the sockets.
i = select( 128, &rset, NULL, NULL, &zerotime ); //用MSDN查看select的说明,此处一直等待,直到rset句柄集中有输入
//这个集包括连接处理套接字和所accept的套接字
//lsock如果有输入则说明有新的连接请求


if( i > 0 )
{
if( FD_ISSET( lsock, &rset ) ) //有新连接
{
// incomming connection
cout < < "Incomming connection..." < < endl;
int dsock = accept( lsock, //响应并建立新连接
(struct sockaddr*)&socketaddress,
&sa_size );
if( dsock == -1 )
{
cout < < "Socket accepting error!" < < endl;
return 0;
}
cout < < "Socket " < < dsock < < " accepted." < < endl;

// add the socket to the list
socketlist.push_back( dsock ); //保存
}

// loop through each socket and see if it has any activity
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{
if( FD_ISSET( *itr, &rset ) ) //遍历,看某个连接是否有新的输入数据
{
// incomming data
cout < < "receiving data from socket ";
cout < < *itr < < "..." < < endl;
err = recv( *itr, buffer, 128, 0 );

if( err == -1 )
{
cout < < "Socket receiving error!" < < endl;
return 0;
}
if( err == 0 )
{
cout < < "Socket " < < *itr < < " closed" < < endl;
shutdown( *itr, 2 );
CloseSocket( *itr );
socketlist.erase( itr );
itr--;
}
else
{

cout < < "Data: " < < buffer < < endl;

// if the message was "servquit", then quit the server.
if( strcmp( buffer, "servquit" ) == 0 ) //__{Quit}__---------退出客户端发来的servquit消息,则服务退出
done = true;
}
}
}
}

}

SearchLife 2008-12-16
  • 打赏
  • 举报
回复
好长啊,mmk
scott_1987 2008-12-16
  • 打赏
  • 举报
回复
好长,新手刚学!心有力而力不足啊!
gccli 2008-12-16
  • 打赏
  • 举报
回复
// now begin the main loop.
while( !done )
{
// clear the set
FD_ZERO( &rset ); //读集,表示监视有没有准备好的可读文件描述符,此时这个集合中为空

// add the listening socket
FD_SET( lsock, &rset ); //添加lsock这个Socket描述符到这个(rset)集合中

// add all of the data sockets
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{
FD_SET( *itr, &rset ); //添加socketlist列表中的Socket描述符到这个(rset)集合中
}

// find out if there is any activity on any of the sockets.
i = select( 128, &rset, NULL, NULL, &zerotime ); //这里会进行阻塞(这么长时间zerotime),直到上面集合中有一个文件描述符中准备好了数据

if( i > 0 ) //i>0表示有i个文件描述符准备好了数据
{
if( FD_ISSET( lsock, &rset ) ) //先判断这个准备好数据的描述符是不是lscok
{
// incomming connection //从这里可以看出这个lsock是用来监听连接用的,如果有连接则将连接的客户端的socket放入socketlist中
cout < < "Incomming connection..." < < endl;
int dsock = accept( lsock, //客户端连接后的socket
(struct sockaddr*)&socketaddress,
&sa_size );
if( dsock == -1 )
{
cout < < "Socket accepting error!" < < endl;
return 0;
}
cout < < "Socket " < < dsock < < " accepted." < < endl;

// add the socket to the list
socketlist.push_back( dsock );
}

// loop through each socket and see if it has any activity
for( itr = socketlist.begin(); itr != socketlist.end(); itr++ )
{ //从这里可以看出,socketlist中的描述是用来接收数据的
//这里是轮询这些socket,如果在linux下,我建议不要用select效率太低,建议用epoll
if( FD_ISSET( *itr, &rset ) )
{
// incomming data
cout < < "receiving data from socket ";
cout < < *itr < < "..." < < endl;
err = recv( *itr, buffer, 128, 0 ); //接收数据,如果接收到servquit则客户端要要服务器退出
// 看到这里,我不得不说,此程序效率差且结构不合理

if( err == -1 )
{
cout < < "Socket receiving error!" < < endl;
return 0;
}
if( err == 0 )
{
cout < < "Socket " < < *itr < < " closed" < < endl;
shutdown( *itr, 2 );
CloseSocket( *itr );
socketlist.erase( itr );
itr--;
}
else
{

cout < < "Data: " < < buffer < < endl;

// if the message was "servquit", then quit the server.
if( strcmp( buffer, "servquit" ) == 0 )
done = true;
}
}
}
}

}

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧