c++ select issue
So I'm trying 开发者_如何转开发to build a async server... Here is a summary of what I have so far:
int sockfd;
int max;
fd_set socks;
set<int> conns;
bind();
listen(sockfd);
while(1){
FD_ZERO(&socks);
max = sockfd;
FD_SET(sockfd, &socks);
for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
FD_SET(*it, &socks);
if(max < *it){
max = *it;
}
}
int res = select(max+1, &socks, NULL, NULL, NULL);
if(res < 0){
cerr << "ERROR with select" << endl;
break;
}else if(res){
if(FD_ISSET(sockfd, &socks)){
//new connection
int new_sockfd = accept();
conns.insert(new_sockfd);
}else{
for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
if(FD_ISSET(*it, &socks){
char buffer[256];
read(buffer, 256, *it);
cout << buffer << endl;
close(*it);
conns.erase(*it);
}
}
}
}
}
What ends up happening is... If I connect a client-1, and then client-2. And then I try and send data using Client-2 and then Client-1... it works...
However, If I connect client-1 and then connect client-2... and then try to send data using client-1. Select() returns a -1...
Help?
Take a look into man pages for select. The important part is :
Under the following conditions, pselect() and select() shall fail and set errno to:
EBADF
One or more of the file descriptor sets specified a file descriptor that is not a valid open file descriptor.
EINTR
The function was interrupted before any of the selected events occurred and before the timeout interval expired.
If SA_RESTART has been set for the interrupting signal, it is implementation-defined whether the function restarts or returns with [EINTR].
EINVAL
An invalid timeout interval was specified.
EINVAL
The nfds argument is less than 0 or greater than FD_SETSIZE.
EINVAL
One of the specified file descriptors refers to a STREAM or multiplexer that is linked (directly or indirectly) downstream from a multiplexer.
errno should tell you what is wrong.
This is just a quess, but when you close the connection, your file descriptor becomes invalid. I guess the error from select should be EBADF
I think your code erasing from the set is suspect. once you call conns.erase(*it)
, your iterator is invalid (and incrementing it leads to undefined behavior).
Changing your loop to something like the following should resolve the issue:
for(set<int>::iterator it=conns.begin(); it!=conns.end();)
{
set<int>::iterator cur = it++;
if(FD_ISSET(*cur, &socks)){
char buffer[256];
read(buffer, 256, *cur);
cout << buffer << endl;
close(*cur);
conns.erase(*cur);
}
}
精彩评论