This is a discussion on select() woes within the Linux Networking forums, part of the Linux Forums category; I created a very UDP simple server (Linux kernel 2.4.20) that listens on two ports --- 6000 & 7000. ...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
I created a very UDP simple server (Linux kernel 2.4.20) that listens
on two ports --- 6000 & 7000. I am using select(), but I am seeing some unexpected behavior. The server seems to get "locked" on to the port number on which it receives its first message. For example, if the first message to the server is sent on port 6000, it will receive all subsequent messages on port 6000, but it will simply ignore all messages on port 7000. Similarly, if the first message to the server is sent on port 7000, it will receive all subsequent messages on port 7000, but it will turn deaf to port 6000. I am sure that there is some careless mistake on my part. Any help will be appreciated. Regards, Song ///// Sample Source Code ///// #include <unistd.h> #include <ctype.h> #include <iostream> #include <time.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <arpa/inet.h> using namespace std; #define MAXMESG 2048 #define PORT_1 6000 #define PORT_2 7000 int maxDescriptor_g = 0; ////////////////////////////////////////////////////////// // // Simply dumps the message contents in hex // ////////////////////////////////////////////////////////// void printMessage(void *msg, size_t msgLen) { ios_base::fmtflags oldFmtSettings = cout.setf(ios::showbase); char *msgPtr = (char *)msg; for(size_t i = 0; i < msgLen; i++) { if(!(i%10)) cout << endl; unsigned char ch = *(msgPtr+i); cout << hex << int(ch) << " "; } cout << endl; cout.setf(oldFmtSettings); cout <<"\n\n\n"; } ////////////////////////////////////////////////////////// // // Processes incoming message // ////////////////////////////////////////////////////////// void processMsg(int sockd) { int bytesRead, clilen; char mesg[MAXMESG]; sockaddr_in from; size_t addrLen = sizeof(sockaddr_in); size_t msgLen; for(;;) { bytesRead = recvfrom(sockd, mesg, MAXMESG, 0,(sockaddr*) &from, (socklen_t *)&addrLen); if(bytesRead < 0) { cerr << "recvfrom: error" << endl; continue; } cout << "Received following message from " << inet_ntoa(from.sin_addr) << ":\n"; printMessage(mesg, bytesRead); break; } } ////////////////////////////////////////////////////////// // // Makes calls to socket(), bind() etc. // ////////////////////////////////////////////////////////// int registerNewListener(int& sd, unsigned short portNum, fd_set& readSet) { sockaddr_in serverDetails; serverDetails.sin_family = AF_INET; serverDetails.sin_addr.s_addr = htonl(INADDR_ANY); serverDetails.sin_port = htons(portNum); socklen_t serverAddrLen = sizeof(sockaddr_in); if((sd=socket(AF_INET, SOCK_DGRAM, 0)) < 0) { cerr << "server: can't open datagram socket" << endl; return -1; } if(bind(sd, (const sockaddr*)&serverDetails, serverAddrLen) < 0) { cerr << "server: can't bind local address" << endl; close(sd); return -2; } int on = 1; if(ioctl(sd, FIONBIO, &on) < 0) { cerr << "server: can't set the socket to non-blocking" << endl; return -3; } FD_SET(sd, &readSet); if(sd > maxDescriptor_g) maxDescriptor_g = sd; return 0; } ////////////////////////////////////////////////////////// // // main // ////////////////////////////////////////////////////////// main(int argc, char *argv[]) { int sockd1, sockd2; fd_set readFDSet; FD_ZERO (&readFDSet); if(registerNewListener(sockd1, PORT_1, readFDSet) < 0) { return -1; } if(registerNewListener(sockd2, PORT_2, readFDSet) < 0) { return -1; } for(;;) { int rc; if((rc = select(maxDescriptor_g+1, &readFDSet, NULL, NULL, NULL)) < 1) { cerr << "server: Bad return value from select (" << rc << ")\n"; return -3; } if(FD_ISSET(sockd1, &readFDSet)) processMsg(sockd1); if(FD_ISSET(sockd2, &readFDSet)) processMsg(sockd2); } } |
|
|||
|
["Followup-To:" header set to comp.os.linux.misc.]
On 17 Oct 2006 12:47:32 -0700, Generic Usenet Account <usenet@sta.samsung.com> wrote: > I created a very UDP simple server (Linux kernel 2.4.20) that listens > on two ports --- 6000 & 7000. I am using select(), but I am seeing > some unexpected behavior. The server seems to get "locked" on to the > port number on which it receives its first message. [snip code] > main(int argc, char *argv[]) > { > int sockd1, sockd2; > > fd_set readFDSet; > FD_ZERO (&readFDSet); > > if(registerNewListener(sockd1, PORT_1, readFDSet) < 0) > { > return -1; > } > > > if(registerNewListener(sockd2, PORT_2, readFDSet) < 0) > { > return -1; > } > > for(;;) > { > int rc; > if((rc = select(maxDescriptor_g+1, &readFDSet, NULL, NULL, NULL)) < > 1) > { > cerr << "server: Bad return value from select (" << rc << ")\n"; > return -3; > } > > if(FD_ISSET(sockd1, &readFDSet)) > processMsg(sockd1); > > if(FD_ISSET(sockd2, &readFDSet)) > processMsg(sockd2); > } > } You only ever configure readFDSet in registerNewListener(). If you were to read the man page for select() you would see this: On exit, the sets are modified in place to indicate which file descriptors actually changed status. This means that you need to call FD_SET() again before each call to select(). If you don't do that, then the set will only contain the descriptors that changed, thus explaining the behavior you are seeing. -- -| Bob Hauck -| Have you had enough of George Bush yet? -| http://www.haucks.org/ |